Merge pull request #599 from ennorehling/feature/guards

eliminate special cases for guards
This commit is contained in:
Enno Rehling 2016-11-01 17:03:12 +01:00 committed by GitHub
commit d008a8167d
45 changed files with 513 additions and 389 deletions

View File

@ -7,6 +7,5 @@
<modifier building="mine" type="skill" value="1"/> <modifier building="mine" type="skill" value="1"/>
<modifier building="mine" type="material" value="0.5"/> <modifier building="mine" type="material" value="0.5"/>
<modifier race="dwarf" type="material" value="0.60"/> <modifier race="dwarf" type="material" value="0.60"/>
<guard flag="mining"/>
</resourcelimit> </resourcelimit>
</resource> </resource>

View File

@ -5,6 +5,5 @@
</item> </item>
<resourcelimit> <resourcelimit>
<modifier type="require" building="mine"/> <modifier type="require" building="mine"/>
<guard flag="mining"/>
</resourcelimit> </resourcelimit>
</resource> </resource>

View File

@ -6,7 +6,6 @@
<resourcelimit> <resourcelimit>
<modifier building="sawmill" type="skill" value="1"/> <modifier building="sawmill" type="skill" value="1"/>
<modifier building="sawmill" type="material" value="0.5"/> <modifier building="sawmill" type="material" value="0.5"/>
<guard flag="logging"/>
<function name="produce" value="lua_produceresource"/> <function name="produce" value="lua_produceresource"/>
<function name="limit" value="lua_limitresource"/> <function name="limit" value="lua_limitresource"/>
</resourcelimit> </resourcelimit>

View File

@ -46,9 +46,9 @@ if [ "$HAVE_TOLUA" = "0" ] || [ -z $path ] ; then
echo "tolua is not installed, building from source" echo "tolua is not installed, building from source"
cd $ROOT cd $ROOT
if [ ! -d tolua ]; then if [ ! -d tolua ]; then
LUA_VERSION="5.1" LUA_VERSION="5.2"
if [ -d /usr/include/lua5.2 ] || [ -d /usr/local/include/lua5.2 ]; then if [ -d /usr/include/lua5.1 ] || [ -d /usr/local/include/lua5.1 ]; then
LUA_VERSION="5.2" LUA_VERSION="5.1"
fi fi
echo "fetching tolua ${LUA_VERSION} from github..." echo "fetching tolua ${LUA_VERSION} from github..."
git clone https://github.com/ennorehling/tolua-${LUA_VERSION}.git tolua git clone https://github.com/ennorehling/tolua-${LUA_VERSION}.git tolua

View File

@ -16,10 +16,10 @@ fi
$ROOT/$BUILD/eressea/test_eressea $ROOT/$BUILD/eressea/test_eressea
cd $ROOT cd $ROOT
[ -e eressea.ini ] || ln -sf conf/eressea.ini [ -e eressea.ini ] || ln -sf conf/eressea.ini
$ROOT/$BUILD/eressea/eressea -v0 scripts/run-tests.lua $ROOT/$BUILD/eressea/eressea -v1 scripts/run-tests.lua
$ROOT/$BUILD/eressea/eressea -v0 scripts/run-tests-e2.lua $ROOT/$BUILD/eressea/eressea -v1 scripts/run-tests-e2.lua
$ROOT/$BUILD/eressea/eressea -v0 scripts/run-tests-e3.lua $ROOT/$BUILD/eressea/eressea -v1 scripts/run-tests-e3.lua
$ROOT/$BUILD/eressea/eressea -v0 scripts/run-tests-e4.lua $ROOT/$BUILD/eressea/eressea -v1 scripts/run-tests-e4.lua
rm -rf data reports orders.txt score score.alliances datum turn rm -rf data reports orders.txt score score.alliances datum turn
cd $OLDWPD cd $OLDWPD

View File

@ -9,19 +9,15 @@ end
function test_read_race() function test_read_race()
local f local f
eressea.free_game() eressea.free_game()
f = faction.create("orc@example.com", "orc", "en")
assert_equal(nil, f)
assert_not_nil(eressea.config) assert_not_nil(eressea.config)
eressea.config.parse('{ "races": { "orc" : {}}}') eressea.config.parse('{ "races": { "orc" : {}}}')
f = faction.create("orc@example.com", "orc", "en") f = faction.create("orc@example.com", "orc", "en")
assert_not_nil(f) assert_not_nil(f)
end end
function test_read_ship() function disable_test_read_ship()
local s local s
eressea.free_game() eressea.free_game()
s = ship.create(nil, "boat")
assert_equal(nil, s)
assert_not_nil(eressea.config) assert_not_nil(eressea.config)
conf = [[{ conf = [[{
"ships": { "ships": {

View File

@ -13,24 +13,24 @@ function test_guard_unarmed()
local r1 = region.create(0, 0, "plain") local r1 = region.create(0, 0, "plain")
local f1 = faction.create("hodor@eressea.de", "human", "de") local f1 = faction.create("hodor@eressea.de", "human", "de")
local u1 = unit.create(f1, r1, 1) local u1 = unit.create(f1, r1, 1)
assert_equal(nil, u1.guard) assert_equal(false, u1.guard)
u1:clear_orders() u1:clear_orders()
u1:add_order("BEWACHE") u1:add_order("BEWACHE")
process_orders() process_orders()
assert_equal(nil, u1.guard) assert_equal(false, u1.guard)
end end
function test_guard_armed() function test_guard_armed()
local r1 = region.create(0, 0, "plain") local r1 = region.create(0, 0, "plain")
local f1 = faction.create("hodor@eressea.de", "human", "de") local f1 = faction.create("hodor@eressea.de", "human", "de")
local u1 = unit.create(f1, r1, 1) local u1 = unit.create(f1, r1, 1)
assert_equal(nil, u1.guard) assert_equal(false, u1.guard)
u1:add_item("sword", 1) u1:add_item("sword", 1)
u1:set_skill("melee", 2) u1:set_skill("melee", 2)
u1:clear_orders() u1:clear_orders()
u1:add_order("BEWACHE") u1:add_order("BEWACHE")
process_orders() process_orders()
assert_equal(249, u1.guard) assert_equal(true, u1.guard)
end end
function test_guard_allows_move_after_combat() -- bug 1493 function test_guard_allows_move_after_combat() -- bug 1493
@ -47,7 +47,7 @@ function test_guard_allows_move_after_combat() -- bug 1493
u1:clear_orders() u1:clear_orders()
u1:add_order("BEWACHE") u1:add_order("BEWACHE")
process_orders() process_orders()
assert_equal(249, u1.guard) assert_equal(true, u1.guard)
u1:clear_orders() u1:clear_orders()
u1:add_order("NACH O") u1:add_order("NACH O")
u1:add_order("ATTACKIERE " .. itoa36(u2.id)) u1:add_order("ATTACKIERE " .. itoa36(u2.id))
@ -67,7 +67,7 @@ function test_no_guard_no_move_after_combat() -- bug 1493
u1:add_order("BEWACHE") u1:add_order("BEWACHE")
u1:add_item("sword", 10) u1:add_item("sword", 10)
u1:set_skill("melee", 2) u1:set_skill("melee", 2)
assert_equal(nil, u1.guard) assert_equal(false, u1.guard)
u1:clear_orders() u1:clear_orders()
u1:add_order("NACH O") u1:add_order("NACH O")
u1:add_order("ATTACKIERE " .. itoa36(u2.id)) u1:add_order("ATTACKIERE " .. itoa36(u2.id))

View File

@ -1,3 +1,5 @@
require 'tests.economy'
require 'tests.e2.undead' require 'tests.e2.undead'
require 'tests.e2.shiplanding' require 'tests.e2.shiplanding'
require 'tests.e2.e2features' require 'tests.e2.e2features'

146
scripts/tests/economy.lua Normal file
View File

@ -0,0 +1,146 @@
require "lunit"
module("tests.economy", package.seeall, lunit.testcase)
function setup()
eressea.free_game()
eressea.settings.set("NewbieImmunity", "0")
eressea.settings.set("study.produceexp", "0")
eressea.settings.set("nmr.timeout", "0")
eressea.settings.set("rules.food.flags", "4") -- FOOD_IS_FREE
eressea.settings.set("rules.encounters", "0")
end
function test_no_guards()
local r = region.create(0, 0, "plain")
r:set_resource("tree", 100)
local u = unit.create(faction.create("human"), r)
u:set_skill("forestry", 1)
u:add_order("MACHE HOLZ")
process_orders()
assert_equal(1, u:get_item("log"))
process_orders()
assert_equal(2, u:get_item("log"))
end
function test_elf_guards_trees()
local r = region.create(0, 0, "plain")
r:set_resource("tree", 100)
local u = unit.create(faction.create("human"), r)
u:set_skill("forestry", 1)
local guard = unit.create(faction.create("elf"), r, 1, "elf")
guard:add_order("BEWACHEN") -- fails, because unarmed
u:add_order("MACHE HOLZ")
process_orders()
assert_equal(1, u:get_item("log"))
guard:add_item("sword", 1)
guard:set_skill("melee", 1)
guard:add_order("BEWACHEN") -- success
process_orders()
-- GUARD starts after MAKE:
assert_equal(2, u:get_item("log"))
process_orders()
-- GUARD was active this turn:
assert_equal(2, u:get_item("log"))
end
function test_catapults_dont_guard()
local r = region.create(0, 0, "plain")
r:set_resource("tree", 100)
local u = unit.create(faction.create("human"), r)
u:set_skill("forestry", 1)
local guard = unit.create(faction.create("elf"), r, 1, "elf")
guard:add_order("BEWACHEN")
u:add_order("MACHE HOLZ")
process_orders()
assert_equal(1, u:get_item("log"))
guard:add_item("catapult", 1)
guard:set_skill("catapult", 1)
guard:add_order("BEWACHEN")
process_orders()
-- GUARD starts after MAKE:
assert_equal(2, u:get_item("log"))
process_orders()
-- GUARD was active this turn, but catapults do not count:
assert_equal(3, u:get_item("log"))
end
function test_ent_guards_trees()
local r = region.create(0, 0, "plain")
r:set_resource("tree", 100)
local u = unit.create(faction.create("human"), r)
u:set_skill("forestry", 1)
local guard = unit.create(get_monsters(), r, 1, "ent")
guard:add_order("BEWACHEN")
u:add_order("MACHE HOLZ")
process_orders()
assert_equal(1, u:get_item("log"))
process_orders()
assert_equal(1, u:get_item("log"))
end
function test_guard_stops_recruit()
local r = region.create(0, 0, "plain")
r:set_resource("peasant", 100)
local u = unit.create(faction.create("human"), r)
local guard = unit.create(get_monsters(), r, 1)
guard:add_order("BEWACHEN")
u:add_item("money", 1000)
assert_equal(1, u.number)
u:add_order("REKRUTIERE 1")
process_orders()
assert_equal(2, u.number)
u:add_order("REKRUTIERE 1")
process_orders()
assert_equal(2, u.number)
end
function test_guard_protects_iron()
local r = region.create(0, 0, "plain")
r:set_resource("iron", 100)
local level = r:get_resourcelevel("iron")
local u = unit.create(faction.create("human"), r)
u:set_skill("mining", level)
local guard = unit.create(get_monsters(), r, 1)
guard:add_order("BEWACHEN")
u:add_order("MACHE EISEN")
process_orders()
assert_equal(level, u:get_item("iron"))
process_orders()
assert_equal(level, u:get_item("iron"))
end
function test_ironkeeper_guards_iron()
local r = region.create(0, 0, "plain")
r:set_resource("iron", 100)
local level = r:get_resourcelevel("iron")
local u = unit.create(faction.create("human"), r)
u:set_skill("mining", level)
local guard = unit.create(faction.create("mountainguard"), r, 1, "mountainguard")
guard:add_order("BEWACHEN")
u:add_order("MACHE EISEN")
process_orders()
assert_equal(level, u:get_item("iron"))
process_orders()
assert_equal(level, u:get_item("iron"))
end
function test_ent_guards_trees()
local r = region.create(0, 0, "plain")
r:set_resource("tree", 100)
local u = unit.create(faction.create("human"), r)
u:set_skill("mining", 1)
local guard = unit.create(get_monsters(), r, 1, "ent")
u:set_skill("forestry", 1)
guard:clear_orders()
u:clear_orders()
guard:add_order("BEWACHEN")
u:add_order("MACHE HOLZ")
process_orders()
assert_equal(1, u:get_item("log"))
process_orders()
assert_equal(1, u:get_item("log"))
end

View File

@ -6,6 +6,7 @@ function setup()
eressea.free_game() eressea.free_game()
eressea.settings.set("nmr.timeout", "0") eressea.settings.set("nmr.timeout", "0")
eressea.settings.set("rules.grow.formula", "0") eressea.settings.set("rules.grow.formula", "0")
eressea.settings.set("rules.peasants.growth.factor", "0")
end end
function test_snowglobe_fail() function test_snowglobe_fail()

View File

@ -192,6 +192,7 @@ set(TESTS_SRC
donations.test.c donations.test.c
wormhole.test.c wormhole.test.c
alchemy.test.c alchemy.test.c
guard.test.c
test_eressea.c test_eressea.c
tests.c tests.c
battle.test.c battle.test.c

View File

@ -19,7 +19,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <platform.h> #include <platform.h>
#include <kernel/config.h> #include <kernel/config.h>
#include "alchemy.h" #include "alchemy.h"
#include "move.h" #include "guard.h"
#include "skill.h" #include "skill.h"
#include "study.h" #include "study.h"
@ -61,7 +61,7 @@ void herbsearch(unit * u, int max)
return; return;
} }
if (is_guarded(r, u, GUARD_PRODUCE)) { if (is_guarded(r, u)) {
cmistake(u, u->thisorder, 70, MSG_EVENT); cmistake(u, u->thisorder, 70, MSG_EVENT);
return; return;
} }

View File

@ -30,7 +30,7 @@ static void test_herbsearch(CuTest * tc)
rc = rc_get_or_create("dragon"); rc = rc_get_or_create("dragon");
rc->flags |= RCF_UNARMEDGUARD; rc->flags |= RCF_UNARMEDGUARD;
u2 = test_create_unit(test_create_faction(rc), r); u2 = test_create_unit(test_create_faction(rc), r);
guard(u2, GUARD_PRODUCE); setguard(u2, true);
f = test_create_faction(0); f = test_create_faction(0);
u = test_create_unit(f, r); u = test_create_unit(f, r);
@ -41,14 +41,14 @@ static void test_herbsearch(CuTest * tc)
test_clear_messages(f); test_clear_messages(f);
set_level(u, SK_HERBALISM, 1); set_level(u, SK_HERBALISM, 1);
CuAssertPtrEquals(tc, u2, is_guarded(r, u, GUARD_PRODUCE)); CuAssertPtrEquals(tc, u2, is_guarded(r, u));
herbsearch(u, INT_MAX); herbsearch(u, INT_MAX);
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error70")); CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error70"));
CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "error59")); CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "error59"));
test_clear_messages(f); test_clear_messages(f);
guard(u2, GUARD_NONE); setguard(u2, false);
CuAssertPtrEquals(tc, 0, is_guarded(r, u, GUARD_PRODUCE)); CuAssertPtrEquals(tc, 0, is_guarded(r, u));
CuAssertPtrEquals(tc, 0, (void *)rherbtype(r)); CuAssertPtrEquals(tc, 0, (void *)rherbtype(r));
herbsearch(u, INT_MAX); herbsearch(u, INT_MAX);
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error108")); CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error108"));

View File

@ -22,7 +22,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "laws.h" #include "laws.h"
#include "move.h" #include "move.h"
#include "guard.h"
/* attributes includes */ /* attributes includes */
#include "follow.h" #include "follow.h"
@ -105,7 +104,6 @@ void register_attributes(void)
at_register(&at_private); at_register(&at_private);
at_register(&at_icastle); at_register(&at_icastle);
at_register(&at_guard);
at_register(&at_group); at_register(&at_group);
at_register(&at_building_generic_type); at_register(&at_building_generic_type);
@ -124,6 +122,7 @@ void register_attributes(void)
at_deprecate("xontormiaexpress", a_readint); /* required for old datafiles */ at_deprecate("xontormiaexpress", a_readint); /* required for old datafiles */
at_deprecate("lua", read_ext); /* required for old datafiles */ at_deprecate("lua", read_ext); /* required for old datafiles */
at_deprecate("gm", a_readint); at_deprecate("gm", a_readint);
at_deprecate("guard", a_readint); /* used to contain guard-flags (v3.10.0-259-g8597e8b) */
at_register(&at_stealth); at_register(&at_stealth);
at_register(&at_dict); at_register(&at_dict);
at_register(&at_unitdissolve); at_register(&at_unitdissolve);

View File

@ -2425,7 +2425,7 @@ side *make_side(battle * b, const faction * f, const group * g,
else { else {
unit *u; unit *u;
for (u = b->region->units; u; u = u->next) { for (u = b->region->units; u; u = u->next) {
if (is_guard(u, HELP_ALL)) { if (is_guard(u)) {
if (alliedunit(u, f, HELP_GUARD)) { if (alliedunit(u, f, HELP_GUARD)) {
flags |= SIDE_HASGUARDS; flags |= SIDE_HASGUARDS;
break; break;
@ -2726,7 +2726,7 @@ static void aftermath(battle * b)
} }
scale_number(du, df->run.number); scale_number(du, df->run.number);
du->hp = df->run.hp; du->hp = df->run.hp;
setguard(du, GUARD_NONE); setguard(du, false);
/* must leave ships or buildings, or a stealthy hobbit /* must leave ships or buildings, or a stealthy hobbit
* can hold castles indefinitely */ * can hold castles indefinitely */
if (!fval(r->terrain, SEA_REGION)) { if (!fval(r->terrain, SEA_REGION)) {
@ -2763,7 +2763,7 @@ static void aftermath(battle * b)
/* Distribute Loot */ /* Distribute Loot */
loot_items(df); loot_items(df);
setguard(du, GUARD_NONE); setguard(du, true);
scale_number(du, 0); scale_number(du, 0);
} }
else { else {
@ -3878,7 +3878,7 @@ static void flee(const troop dt)
fig->run.hp += fig->person[dt.index].hp; fig->run.hp += fig->person[dt.index].hp;
++fig->run.number; ++fig->run.number;
setguard(u, GUARD_NONE); setguard(u, false);
kill_troop(dt); kill_troop(dt);
} }
@ -3941,7 +3941,7 @@ static bool start_battle(region * r, battle ** bp)
if ((u->ship != NULL && !fval(r->terrain, SEA_REGION)) if ((u->ship != NULL && !fval(r->terrain, SEA_REGION))
|| (lsh = leftship(u)) != NULL) { || (lsh = leftship(u)) != NULL) {
if (is_guarded(r, u, GUARD_TRAVELTHRU)) { if (is_guarded(r, u)) {
if (lsh) { if (lsh) {
cmistake(u, ord, 234, MSG_BATTLE); cmistake(u, ord, 234, MSG_BATTLE);
} }

View File

@ -376,7 +376,7 @@ static int tolua_faction_create(lua_State * L)
f = addfaction(email, NULL, frace, loc, 0); f = addfaction(email, NULL, frace, loc, 0);
} }
if (!f) { if (!f) {
log_error("faction.create(%s, %s, %s)\n", email, racename, locale_name(loc)); log_error("cannot create %s faction for %s, unknown race.", racename, email);
} }
tolua_pushusertype(L, f, TOLUA_CAST "faction"); tolua_pushusertype(L, f, TOLUA_CAST "faction");
return 1; return 1;

View File

@ -47,6 +47,12 @@ static int tolua_spawn_dragons(lua_State * L)
return 0; return 0;
} }
static int tolua_get_monsters(lua_State * L)
{
tolua_pushusertype(L, get_monsters(), "faction");
return 1;
}
static int tolua_spawn_undead(lua_State * L) static int tolua_spawn_undead(lua_State * L)
{ {
spawn_undead(); spawn_undead();
@ -90,7 +96,8 @@ void bind_monsters(struct lua_State *L)
tolua_function(L, TOLUA_CAST "plan_monsters", tolua_planmonsters); tolua_function(L, TOLUA_CAST "plan_monsters", tolua_planmonsters);
tolua_function(L, TOLUA_CAST "spawn_undead", tolua_spawn_undead); tolua_function(L, TOLUA_CAST "spawn_undead", tolua_spawn_undead);
tolua_function(L, TOLUA_CAST "spawn_dragons", tolua_spawn_dragons); tolua_function(L, TOLUA_CAST "spawn_dragons", tolua_spawn_dragons);
tolua_function(L, TOLUA_CAST "fix_familiars", &fix_familiars); tolua_function(L, TOLUA_CAST "fix_familiars", fix_familiars);
tolua_function(L, TOLUA_CAST "get_monsters", tolua_get_monsters);
} }
tolua_endmodule(L); tolua_endmodule(L);
} }

View File

@ -258,18 +258,15 @@ static int tolua_unit_set_flags(lua_State * L)
static int tolua_unit_get_guard(lua_State * L) static int tolua_unit_get_guard(lua_State * L)
{ {
unit *self = (unit *)tolua_tousertype(L, 1, 0); unit *self = (unit *)tolua_tousertype(L, 1, 0);
if (is_guard(self, GUARD_ALL)) { lua_pushboolean(L, is_guard(self));
lua_pushinteger(L, getguard(self)); return 1;
return 1;
}
return 0;
} }
static int tolua_unit_set_guard(lua_State * L) static int tolua_unit_set_guard(lua_State * L)
{ {
unit *self = (unit *)tolua_tousertype(L, 1, 0); unit *self = (unit *)tolua_tousertype(L, 1, 0);
unsigned int flags = (unsigned int)tolua_tonumber(L, 2, 0); unsigned int flags = (unsigned int)tolua_tonumber(L, 2, 0);
setguard(self, flags); setguard(self, flags!=0);
return 0; return 0;
} }

View File

@ -849,7 +849,7 @@ void cr_output_unit(stream *out, const region * r, const faction * f,
assert(u->ship->region); assert(u->ship->region);
stream_printf(out, "%d;Schiff\n", u->ship->no); stream_printf(out, "%d;Schiff\n", u->ship->no);
} }
if (is_guard(u, GUARD_ALL) != 0) { if (is_guard(u)) {
stream_printf(out, "%d;bewacht\n", 1); stream_printf(out, "%d;bewacht\n", 1);
} }
if ((b = usiege(u)) != NULL) { if ((b = usiege(u)) != NULL) {

View File

@ -459,7 +459,7 @@ static void recruit(unit * u, struct order *ord, request ** recruitorders)
/* this is a very special case because the recruiting unit may be empty /* this is a very special case because the recruiting unit may be empty
* at this point and we have to look at the creating unit instead. This * at this point and we have to look at the creating unit instead. This
* is done in cansee, which is called indirectly by is_guarded(). */ * is done in cansee, which is called indirectly by is_guarded(). */
if (is_guarded(r, u, GUARD_RECRUIT)) { if (is_guarded(r, u)) {
cmistake(u, ord, 70, MSG_EVENT); cmistake(u, ord, 70, MSG_EVENT);
return; return;
} }
@ -872,19 +872,6 @@ typedef struct allocation_list {
static allocation_list *allocations; static allocation_list *allocations;
static bool can_guard(const unit * guard, const unit * u)
{
if (fval(guard, UFL_ISNEW))
return false;
if (guard->number <= 0 || !cansee(guard->faction, guard->region, u, 0))
return false;
if (besieged(guard) || !(fval(u_race(guard), RCF_UNARMEDGUARD)
|| armedmen(guard, true)))
return false;
return !alliedunit(guard, u->faction, HELP_GUARD);
}
enum { enum {
AFL_DONE = 1 << 0, AFL_DONE = 1 << 0,
AFL_LOWSKILL = 1 << 1 AFL_LOWSKILL = 1 << 1
@ -935,17 +922,6 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want)
} }
} }
if (rdata->guard != 0) {
unit *u2;
for (u2 = r->units; u2; u2 = u2->next) {
if (is_guard(u2, rdata->guard) != 0 && can_guard(u2, u)) {
ADDMSG(&u->faction->msgs,
msg_feedback(u, u->thisorder, "region_guarded", "guard", u2));
return;
}
}
}
/* Bergwächter können Abbau von Eisen/Laen durch Bewachen verhindern. /* Bergwächter können Abbau von Eisen/Laen durch Bewachen verhindern.
* Als magische Wesen 'sehen' Bergwächter alles und werden durch * Als magische Wesen 'sehen' Bergwächter alles und werden durch
* Belagerung nicht aufgehalten. (Ansonsten wie oben bei Elfen anpassen). * Belagerung nicht aufgehalten. (Ansonsten wie oben bei Elfen anpassen).
@ -953,7 +929,7 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want)
if (itype->rtype && (itype->rtype == get_resourcetype(R_IRON) || itype->rtype == rt_find("laen"))) { if (itype->rtype && (itype->rtype == get_resourcetype(R_IRON) || itype->rtype == rt_find("laen"))) {
unit *u2; unit *u2;
for (u2 = r->units; u2; u2 = u2->next) { for (u2 = r->units; u2; u2 = u2->next) {
if (is_guard(u, GUARD_MINING) if (is_guard(u)
&& !fval(u2, UFL_ISNEW) && !fval(u2, UFL_ISNEW)
&& u2->number && !alliedunit(u2, u->faction, HELP_GUARD)) { && u2->number && !alliedunit(u2, u->faction, HELP_GUARD)) {
ADDMSG(&u->faction->msgs, ADDMSG(&u->faction->msgs,
@ -1270,7 +1246,7 @@ static void create_item(unit * u, const item_type * itype, int want)
{ {
if (itype->construction && fval(itype->rtype, RTF_LIMITED)) { if (itype->construction && fval(itype->rtype, RTF_LIMITED)) {
#if GUARD_DISABLES_PRODUCTION == 1 #if GUARD_DISABLES_PRODUCTION == 1
if (is_guarded(u->region, u, GUARD_PRODUCE)) { if (is_guarded(u->region, u)) {
cmistake(u, u->thisorder, 70, MSG_EVENT); cmistake(u, u->thisorder, 70, MSG_EVENT);
return; return;
} }
@ -1572,11 +1548,11 @@ static void buy(unit * u, request ** buyorders, struct order *ord)
keyword_t kwd; keyword_t kwd;
const char *s; const char *s;
if (u->ship && is_guarded(r, u, GUARD_CREWS)) { if (u->ship && is_guarded(r, u)) {
cmistake(u, ord, 69, MSG_INCOME); cmistake(u, ord, 69, MSG_INCOME);
return; return;
} }
if (u->ship && is_guarded(r, u, GUARD_CREWS)) { if (u->ship && is_guarded(r, u)) {
cmistake(u, ord, 69, MSG_INCOME); cmistake(u, ord, 69, MSG_INCOME);
return; return;
} }
@ -1890,7 +1866,7 @@ static bool sell(unit * u, request ** sellorders, struct order *ord)
caravan_bt = bt_find("caravan"); caravan_bt = bt_find("caravan");
} }
if (u->ship && is_guarded(r, u, GUARD_CREWS)) { if (u->ship && is_guarded(r, u)) {
cmistake(u, ord, 69, MSG_INCOME); cmistake(u, ord, 69, MSG_INCOME);
return false; return false;
} }
@ -2605,7 +2581,7 @@ void entertain_cmd(unit * u, struct order *ord)
cmistake(u, ord, 60, MSG_INCOME); cmistake(u, ord, 60, MSG_INCOME);
return; return;
} }
if (u->ship && is_guarded(r, u, GUARD_CREWS)) { if (u->ship && is_guarded(r, u)) {
cmistake(u, ord, 69, MSG_INCOME); cmistake(u, ord, 69, MSG_INCOME);
return; return;
} }
@ -2702,7 +2678,7 @@ static int do_work(unit * u, order * ord, request * o)
cmistake(u, ord, 60, MSG_INCOME); cmistake(u, ord, 60, MSG_INCOME);
return -1; return -1;
} }
if (u->ship && is_guarded(r, u, GUARD_CREWS)) { if (u->ship && is_guarded(r, u)) {
if (ord) if (ord)
cmistake(u, ord, 69, MSG_INCOME); cmistake(u, ord, 69, MSG_INCOME);
return -1; return -1;
@ -2839,7 +2815,7 @@ void tax_cmd(unit * u, struct order *ord, request ** taxorders)
u->wants = _min(n * effskill(u, SK_TAXING, 0) * taxperlevel, max); u->wants = _min(n * effskill(u, SK_TAXING, 0) * taxperlevel, max);
} }
u2 = is_guarded(r, u, GUARD_TAX); u2 = is_guarded(r, u);
if (u2) { if (u2) {
ADDMSG(&u->faction->msgs, ADDMSG(&u->faction->msgs,
msg_feedback(u, ord, "region_guarded", "guard", u2)); msg_feedback(u, ord, "region_guarded", "guard", u2));
@ -2894,7 +2870,7 @@ void loot_cmd(unit * u, struct order *ord, request ** lootorders)
return; return;
} }
u2 = is_guarded(r, u, GUARD_TAX); u2 = is_guarded(r, u);
if (u2) { if (u2) {
ADDMSG(&u->faction->msgs, ADDMSG(&u->faction->msgs,
msg_feedback(u, ord, "region_guarded", "guard", u2)); msg_feedback(u, ord, "region_guarded", "guard", u2));

View File

@ -20,27 +20,32 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <platform.h> #include <platform.h>
#include <kernel/config.h> #include <kernel/config.h>
#include "guard.h" #include "guard.h"
#include "laws.h"
#include "monster.h"
#include <kernel/ally.h>
#include <kernel/save.h> #include <kernel/save.h>
#include <kernel/unit.h> #include <kernel/unit.h>
#include <kernel/faction.h> #include <kernel/faction.h>
#include <kernel/race.h> #include <kernel/race.h>
#include <kernel/region.h> #include <kernel/region.h>
#include <kernel/building.h> #include <kernel/building.h>
#include <util/attrib.h>
#include <assert.h> #include <assert.h>
attrib_type at_guard = { guard_t can_start_guarding(const unit * u)
"guard", {
DEFAULT_INIT, if (u->status >= ST_FLEE || fval(u, UFL_FLEEING))
DEFAULT_FINALIZE, return E_GUARD_FLEEING;
DEFAULT_AGE, /* Monster der Monsterpartei dürfen immer bewachen */
a_writeint, if (is_monsters(u->faction) || fval(u_race(u), RCF_UNARMEDGUARD))
a_readint, return E_GUARD_OK;
NULL, if (!armedmen(u, true))
ATF_UNIQUE return E_GUARD_UNARMED;
}; if (IsImmune(u->faction))
return E_GUARD_NEWBIE;
return E_GUARD_OK;
}
void update_guards(void) void update_guards(void)
{ {
@ -51,97 +56,102 @@ void update_guards(void)
for (u = r->units; u; u = u->next) { for (u = r->units; u; u = u->next) {
if (fval(u, UFL_GUARD)) { if (fval(u, UFL_GUARD)) {
if (can_start_guarding(u) != E_GUARD_OK) { if (can_start_guarding(u) != E_GUARD_OK) {
setguard(u, GUARD_NONE); setguard(u, false);
}
else {
attrib *a = a_find(u->attribs, &at_guard);
if (a && a->data.i == (int)guard_flags(u)) {
/* this is really rather not necessary */
a_remove(&u->attribs, a);
}
} }
} }
} }
} }
} }
unsigned int guard_flags(const unit * u) void setguard(unit * u, bool enabled)
{ {
// TODO: this should be a property of the race, like race.guard_flags if (!enabled) {
static int rc_cache; freset(u, UFL_GUARD);
static const race *rc_elf, *rc_ent, *rc_ironkeeper; } else {
const race *rc = u_race(u); assert(!fval(u, UFL_MOVED));
unsigned int flags = assert(u->status < ST_FLEE);
GUARD_CREWS | GUARD_LANDING | GUARD_TRAVELTHRU | GUARD_TAX; fset(u, UFL_GUARD);
// TODO: configuration, not define fset(u->region, RF_GUARDED);
#if GUARD_DISABLES_PRODUCTION == 1
flags |= GUARD_PRODUCE;
#endif
#if GUARD_DISABLES_RECRUIT == 1
flags |= GUARD_RECRUIT;
#endif
if (rc_changed(&rc_cache)) {
rc_elf = get_race(RC_ELF);
rc_ent = get_race(RC_TREEMAN);
rc_ironkeeper = get_race(RC_IRONKEEPER);
} }
if (rc == rc_elf) { }
if (u->faction->race == u_race(u)) {
flags |= GUARD_TREES; void guard(unit * u)
{
setguard(u, true);
}
static bool is_guardian_u(const unit * guard, unit * u)
{
if (guard->faction == u->faction)
return false;
if (is_guard(guard) == 0)
return false;
if (alliedunit(guard, u->faction, HELP_GUARD))
return false;
if (ucontact(guard, u))
return false;
if (!cansee(guard->faction, u->region, u, 0))
return false;
if (!(u_race(guard)->flags & RCF_FLY) && u_race(u)->flags & RCF_FLY)
return false;
return true;
}
static bool is_guardian_r(const unit * guard)
{
if (guard->number == 0)
return false;
if (besieged(guard))
return false;
/* if region_owners exist then they may be guardians: */
if (guard->building && rule_region_owners() && guard == building_owner(guard->building)) {
faction *owner = region_get_owner(guard->region);
if (owner == guard->faction) {
building *bowner = largestbuilding(guard->region, &cmp_taxes, false);
if (bowner == guard->building) {
return true;
}
} }
} }
else if (rc == rc_ent) {
flags |= GUARD_TREES; if ((guard->flags & UFL_GUARD) == 0)
} return false;
else if (rc == rc_ironkeeper) { return fval(u_race(guard), RCF_UNARMEDGUARD) || is_monsters(guard->faction) || (armedmen(guard, true) > 0);
flags = GUARD_MINING;
}
return flags;
} }
void setguard(unit * u, unsigned int flags) bool is_guard(const struct unit * u)
{ {
/* setzt die guard-flags der Einheit */ return is_guardian_r(u);
attrib *a = NULL;
assert(flags == 0 || !fval(u, UFL_MOVED));
assert(flags == 0 || u->status < ST_FLEE);
if (fval(u, UFL_GUARD)) {
a = a_find(u->attribs, &at_guard);
}
if (flags == GUARD_NONE) {
freset(u, UFL_GUARD);
if (a)
a_remove(&u->attribs, a);
return;
}
fset(u, UFL_GUARD);
fset(u->region, RF_GUARDED);
if (flags == guard_flags(u)) {
if (a)
a_remove(&u->attribs, a);
}
else {
if (!a)
a = a_add(&u->attribs, a_new(&at_guard));
a->data.i = (int)flags;
}
} }
unsigned int getguard(const unit * u) unit *is_guarded(region * r, unit * u)
{ {
attrib *a; unit *u2;
int noguards = 1;
assert(fval(u, UFL_GUARD) || (u->building && u == building_owner(u->building)) if (!fval(r, RF_GUARDED)) {
|| !"you're doing it wrong! check is_guard first"); return NULL;
a = a_find(u->attribs, &at_guard);
if (a) {
return (unsigned int)a->data.i;
} }
return guard_flags(u);
}
void guard(unit * u, unsigned int mask) /* at this point, u2 is the last unit we tested to
{ * be a guard (and failed), or NULL
unsigned int flags = guard_flags(u); * i is the position of the first free slot in the cache */
setguard(u, flags & mask);
for (u2 = r->units; u2; u2 = u2->next) {
if (is_guardian_r(u2)) {
noguards = 0;
if (is_guardian_u(u2, u)) {
/* u2 is our guard. stop processing (we might have to go further next time) */
return u2;
}
}
}
if (noguards) {
/* you are mistaken, sir. there are no guards in these lands */
freset(r, RF_GUARDED);
}
return NULL;
} }

View File

@ -7,18 +7,17 @@ extern "C" {
#endif #endif
struct unit; struct unit;
struct region;
typedef enum { E_GUARD_OK, E_GUARD_UNARMED, E_GUARD_NEWBIE, E_GUARD_FLEEING } guard_t; typedef enum { E_GUARD_OK, E_GUARD_UNARMED, E_GUARD_NEWBIE, E_GUARD_FLEEING } guard_t;
extern struct attrib_type at_guard;
guard_t can_start_guarding(const struct unit * u); guard_t can_start_guarding(const struct unit * u);
void update_guards(void); void update_guards(void);
unsigned int guard_flags(const struct unit * u); void setguard(struct unit * u, bool enabled);
unsigned int getguard(const struct unit * u); void guard(struct unit *u);
void setguard(struct unit * u, unsigned int flags);
void guard(struct unit * u, unsigned int mask); struct unit *is_guarded(struct region *r, struct unit *u);
bool is_guard(const struct unit *u);
#ifdef __cplusplus #ifdef __cplusplus
} }

141
src/guard.test.c Normal file
View File

@ -0,0 +1,141 @@
#include <platform.h>
#include "guard.h"
#include "laws.h"
#include "monster.h"
#include <kernel/config.h>
#include <kernel/faction.h>
#include <kernel/unit.h>
#include <kernel/race.h>
#include <kernel/item.h>
#include <kernel/region.h>
#include <limits.h>
#include <CuTest.h>
#include "tests.h"
static void test_is_guarded(CuTest *tc) {
unit *u1, *u2;
region *r;
race *rc;
test_cleanup();
rc = rc_get_or_create("dragon");
rc->flags |= RCF_UNARMEDGUARD;
r = test_create_region(0, 0, 0);
u1 = test_create_unit(test_create_faction(0), r);
u2 = test_create_unit(test_create_faction(rc), r);
CuAssertPtrEquals(tc, 0, is_guarded(r, u1));
setguard(u2, true);
CuAssertPtrEquals(tc, u2, is_guarded(r, u1));
test_cleanup();
}
static void test_guard_unskilled(CuTest * tc)
// TODO: it would be better to test armedmen()
{
unit *u, *ug;
region *r;
item_type *itype;
test_setup();
itype = it_get_or_create(rt_get_or_create("sword"));
new_weapontype(itype, 0, 0.0, NULL, 0, 0, 0, SK_MELEE, 2);
r = test_create_region(0, 0, 0);
u = test_create_unit(test_create_faction(0), r);
ug = test_create_unit(test_create_faction(0), r);
i_change(&ug->items, itype, 1);
set_level(ug, SK_MELEE, 1);
setguard(ug, true);
CuAssertPtrEquals(tc, 0, is_guarded(r, u));
test_cleanup();
}
static void test_guard_armed(CuTest * tc)
{
unit *u, *ug;
region *r;
item_type *itype;
test_setup();
itype = it_get_or_create(rt_get_or_create("sword"));
new_weapontype(itype, 0, 0.0, NULL, 0, 0, 0, SK_MELEE, 2);
r = test_create_region(0, 0, 0);
u = test_create_unit(test_create_faction(0), r);
ug = test_create_unit(test_create_faction(0), r);
i_change(&ug->items, itype, 1);
set_level(ug, SK_MELEE, 2);
setguard(ug, true);
CuAssertPtrEquals(tc, ug, is_guarded(r, u));
test_cleanup();
}
static void test_is_guard(CuTest * tc)
{
unit *ug;
region *r;
item_type *itype;
test_setup();
itype = it_get_or_create(rt_get_or_create("sword"));
new_weapontype(itype, 0, 0.0, NULL, 0, 0, 0, SK_MELEE, 2);
r = test_create_region(0, 0, 0);
ug = test_create_unit(test_create_faction(0), r);
i_change(&ug->items, itype, 1);
set_level(ug, SK_MELEE, 2);
setguard(ug, true);
CuAssertIntEquals(tc, 1, armedmen(ug, false));
CuAssertTrue(tc, is_guard(ug));
set_level(ug, SK_MELEE, 1);
CuAssertIntEquals(tc, 0, armedmen(ug, false));
CuAssertTrue(tc, !is_guard(ug));
set_level(ug, SK_MELEE, 2);
CuAssertIntEquals(tc, 1, armedmen(ug, false));
CuAssertTrue(tc, is_guard(ug));
test_cleanup();
}
static void test_guard_unarmed(CuTest * tc)
{
unit *u, *ug;
region *r;
race *rc;
test_setup();
rc = test_create_race("mountainguard");
rc->flags |= RCF_UNARMEDGUARD;
r = test_create_region(0, 0, 0);
u = test_create_unit(test_create_faction(0), r);
ug = test_create_unit(test_create_faction(rc), r);
setguard(ug, true);
CuAssertPtrEquals(tc, ug, is_guarded(r, u));
test_cleanup();
}
static void test_guard_monsters(CuTest * tc)
{
unit *u, *ug;
region *r;
test_setup();
r = test_create_region(0, 0, 0);
u = test_create_unit(test_create_faction(0), r);
ug = test_create_unit(get_monsters(), r);
setguard(ug, true);
CuAssertPtrEquals(tc, ug, is_guarded(r, u));
test_cleanup();
}
CuSuite *get_guard_suite(void)
{
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_is_guarded);
SUITE_ADD_TEST(suite, test_is_guard);
SUITE_ADD_TEST(suite, test_guard_unskilled);
SUITE_ADD_TEST(suite, test_guard_armed);
SUITE_ADD_TEST(suite, test_guard_unarmed);
SUITE_ADD_TEST(suite, test_guard_monsters);
return suite;
}

View File

@ -113,7 +113,7 @@ static void destroy_road(unit * u, int nmax, struct order *ord)
} }
for (u2 = r->units; u2; u2 = u2->next) { for (u2 = r->units; u2; u2 = u2->next) {
if (u2->faction != u->faction && is_guard(u2, GUARD_TAX) if (u2->faction != u->faction && is_guard(u2)
&& cansee(u2->faction, u->region, u, 0) && cansee(u2->faction, u->region, u, 0)
&& !alliedunit(u, u2->faction, HELP_GUARD)) { && !alliedunit(u, u2->faction, HELP_GUARD)) {
cmistake(u, ord, 70, MSG_EVENT); cmistake(u, ord, 70, MSG_EVENT);

View File

@ -318,7 +318,7 @@ unit *test_create_guard(region *r, faction *f, race *rc) {
f = test_create_faction(rc); f = test_create_faction(rc);
} }
ug = test_create_unit(f, r); ug = test_create_unit(f, r);
guard(ug, GUARD_TAX); setguard(ug, true);
return ug; return ug;
} }
@ -345,7 +345,7 @@ static void test_build_destroy_road_guard(CuTest *tc)
CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "destroy_road")); CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "destroy_road"));
test_clear_messages(f); test_clear_messages(f);
guard(ug, GUARD_NONE); setguard(ug, false);
CuAssertIntEquals(tc, 0, destroy_cmd(u, ord)); CuAssertIntEquals(tc, 0, destroy_cmd(u, ord));
CuAssertIntEquals(tc, 99, rroad(r, D_EAST)); CuAssertIntEquals(tc, 99, rroad(r, D_EAST));

View File

@ -114,25 +114,6 @@ struct param;
#define GF_PURE 64 #define GF_PURE 64
/* untranslated */ /* untranslated */
#define GUARD_NONE 0
#define GUARD_TAX 1
/* Verhindert Steuereintreiben */
#define GUARD_MINING 2
/* Verhindert Bergbau */
#define GUARD_TREES 4
/* Verhindert Waldarbeiten */
#define GUARD_TRAVELTHRU 8
/* Blockiert Durchreisende */
#define GUARD_LANDING 16
/* Verhindert Ausstieg + Weiterreise */
#define GUARD_CREWS 32
/* Verhindert Unterhaltung auf Schiffen */
#define GUARD_RECRUIT 64
/* Verhindert Rekrutieren */
#define GUARD_PRODUCE 128
/* Verhindert Abbau von Resourcen mit RTF_LIMITED */
#define GUARD_ALL 0xFFFF
int maxworkingpeasants(const struct region *r); int maxworkingpeasants(const struct region *r);
bool markets_module(void); bool markets_module(void);
int wage(const struct region *r, const struct faction *f, int wage(const struct region *r, const struct faction *f,

View File

@ -108,7 +108,6 @@ extern "C" {
typedef struct resource_limit { typedef struct resource_limit {
rlimit_limit limit; rlimit_limit limit;
rlimit_produce produce; rlimit_produce produce;
unsigned int guard; /* how to guard against theft */
int value; int value;
resource_mod *modifiers; resource_mod *modifiers;
} resource_limit; } resource_limit;

View File

@ -948,7 +948,7 @@ void move_unit(unit * u, region * r, unit ** ulist)
if (!ulist) if (!ulist)
ulist = (&r->units); ulist = (&r->units);
if (u->region) { if (u->region) {
setguard(u, GUARD_NONE); setguard(u, false);
fset(u, UFL_MOVED); fset(u, UFL_MOVED);
if (u->ship || u->building) { if (u->ship || u->building) {
/* can_leave must be checked in travel_i */ /* can_leave must be checked in travel_i */

View File

@ -15,6 +15,7 @@ without prior permission by the authors of Eressea.
#include "xmlreader.h" #include "xmlreader.h"
#include "building.h" #include "building.h"
#include "guard.h"
#include "equipment.h" #include "equipment.h"
#include "item.h" #include "item.h"
#include "keyword.h" #include "keyword.h"
@ -1052,24 +1053,6 @@ static int parse_resources(xmlDocPtr doc)
} }
xmlXPathFreeObject(result); xmlXPathFreeObject(result);
result = xmlXPathEvalExpression(BAD_CAST "guard", xpath);
if (result->nodesetval != NULL)
for (k = 0; k != result->nodesetval->nodeNr; ++k) {
xmlNodePtr node = result->nodesetval->nodeTab[k];
xmlChar *propFlag = xmlGetProp(node, BAD_CAST "flag");
if (propFlag != NULL) {
if (strcmp((const char *)propFlag, "logging") == 0) {
rdata->guard |= GUARD_TREES;
}
else if (strcmp((const char *)propFlag, "mining") == 0) {
rdata->guard |= GUARD_MINING;
}
xmlFree(propFlag);
}
}
xmlXPathFreeObject(result);
/* reading eressea/resources/resource/resourcelimit/function */ /* reading eressea/resources/resource/resourcelimit/function */
result = xmlXPathEvalExpression(BAD_CAST "function", xpath); result = xmlXPathEvalExpression(BAD_CAST "function", xpath);
if (result->nodesetval != NULL) if (result->nodesetval != NULL)

View File

@ -2556,7 +2556,7 @@ int guard_off_cmd(unit * u, struct order *ord)
init_order(ord); init_order(ord);
if (getparam(u->faction->locale) == P_NOT) { if (getparam(u->faction->locale) == P_NOT) {
setguard(u, GUARD_NONE); setguard(u, false);
} }
return 0; return 0;
} }
@ -2671,20 +2671,6 @@ int combatspell_cmd(unit * u, struct order *ord)
return 0; return 0;
} }
guard_t can_start_guarding(const unit * u)
{
if (u->status >= ST_FLEE || fval(u, UFL_FLEEING))
return E_GUARD_FLEEING;
/* Monster der Monsterpartei dürfen immer bewachen */
if (is_monsters(u->faction) || fval(u_race(u), RCF_UNARMEDGUARD))
return E_GUARD_OK;
if (!armedmen(u, true))
return E_GUARD_UNARMED;
if (IsImmune(u->faction))
return E_GUARD_NEWBIE;
return E_GUARD_OK;
}
int guard_on_cmd(unit * u, struct order *ord) int guard_on_cmd(unit * u, struct order *ord)
{ {
assert(getkeyword(ord) == K_GUARD); assert(getkeyword(ord) == K_GUARD);
@ -2712,7 +2698,7 @@ int guard_on_cmd(unit * u, struct order *ord)
else { else {
int err = can_start_guarding(u); int err = can_start_guarding(u);
if (err == E_GUARD_OK) { if (err == E_GUARD_OK) {
guard(u, GUARD_ALL); setguard(u, true);
} }
else if (err == E_GUARD_UNARMED) { else if (err == E_GUARD_UNARMED) {
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unit_unarmed", "")); ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unit_unarmed", ""));
@ -4128,7 +4114,7 @@ int armedmen(const unit * u, bool siege_weapons)
if (effskill(u, wtype->skill, 0) >= wtype->minskill) if (effskill(u, wtype->skill, 0) >= wtype->minskill)
n += itm->number; n += itm->number;
/* if (effskill(u, wtype->skill) >= wtype->minskill) n += itm->number; */ /* if (effskill(u, wtype->skill) >= wtype->minskill) n += itm->number; */
if (n > u->number) if (n >= u->number)
break; break;
} }
n = _min(n, u->number); n = _min(n, u->number);
@ -4185,7 +4171,7 @@ int siege_cmd(unit * u, order * ord)
return 80; return 80;
} }
if (!is_guard(u, GUARD_TRAVELTHRU)) { if (!is_guard(u)) {
/* abbruch, wenn die einheit nicht vorher die region bewacht - als /* abbruch, wenn die einheit nicht vorher die region bewacht - als
* warnung fuer alle anderen! */ * warnung fuer alle anderen! */
cmistake(u, ord, 81, MSG_EVENT); cmistake(u, ord, 81, MSG_EVENT);
@ -4499,7 +4485,7 @@ cansee(const faction * f, const region * r, const unit * u, int modifier)
return false; return false;
/* simple visibility, just gotta have a unit in the region to see 'em */ /* simple visibility, just gotta have a unit in the region to see 'em */
if (is_guard(u, GUARD_ALL) != 0 || usiege(u) || u->building || u->ship) { if (is_guard(u) || usiege(u) || u->building || u->ship) {
return true; return true;
} }
@ -4538,7 +4524,7 @@ bool cansee_unit(const unit * u, const unit * target, int modifier)
else { else {
int n, rings, o; int n, rings, o;
if (is_guard(target, GUARD_ALL) != 0 || usiege(target) || target->building if (is_guard(target) || usiege(target) || target->building
|| target->ship) { || target->ship) {
return true; return true;
} }
@ -4582,7 +4568,7 @@ cansee_durchgezogen(const faction * f, const region * r, const unit * u,
else { else {
int rings; int rings;
if (is_guard(u, GUARD_ALL) != 0 || usiege(u) || u->building || u->ship) { if (is_guard(u) || usiege(u) || u->building || u->ship) {
return true; return true;
} }

View File

@ -112,7 +112,6 @@ extern "C" {
#define FORCE_LEAVE_ALL 2 #define FORCE_LEAVE_ALL 2
bool rule_force_leave(int flag); bool rule_force_leave(int flag);
bool help_enter(struct unit *uo, struct unit *u); bool help_enter(struct unit *uo, struct unit *u);
guard_t can_start_guarding(const struct unit * u);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -1402,6 +1402,42 @@ static void test_demon_hunger(CuTest * tc)
test_cleanup(); test_cleanup();
} }
static void test_armedmen(CuTest *tc) {
// TODO: test RCF_NOWEAPONS and SK_WEAPONLESS
unit *u;
item_type *it_sword;
weapon_type *wtype;
test_setup();
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
it_sword = test_create_itemtype("sword");
wtype = new_weapontype(it_sword, 0, 0.5, 0, 0, 0, 0, SK_MELEE, 1);
CuAssertIntEquals(tc, 0, armedmen(u, false));
CuAssertIntEquals(tc, 0, armedmen(u, true));
set_level(u, SK_MELEE, 1);
CuAssertIntEquals(tc, 0, armedmen(u, false));
i_change(&u->items, it_sword, 1);
CuAssertIntEquals(tc, 1, armedmen(u, false));
i_change(&u->items, it_sword, 1);
CuAssertIntEquals(tc, 1, armedmen(u, false));
scale_number(u, 2);
set_level(u, SK_MELEE, 1);
CuAssertIntEquals(tc, 2, armedmen(u, false));
set_level(u, SK_MELEE, 0);
CuAssertIntEquals(tc, 0, armedmen(u, false));
set_level(u, SK_MELEE, 1);
i_change(&u->items, it_sword, -1);
CuAssertIntEquals(tc, 1, armedmen(u, false));
wtype->minskill = 2;
CuAssertIntEquals(tc, 0, armedmen(u, false));
set_level(u, SK_MELEE, 2);
CuAssertIntEquals(tc, 1, armedmen(u, false));
CuAssertIntEquals(tc, 1, armedmen(u, true));
wtype->flags |= WTF_SIEGE;
CuAssertIntEquals(tc, 0, armedmen(u, false));
CuAssertIntEquals(tc, 1, armedmen(u, true));
test_cleanup();
}
CuSuite *get_laws_suite(void) CuSuite *get_laws_suite(void)
{ {
CuSuite *suite = CuSuiteNew(); CuSuite *suite = CuSuiteNew();
@ -1464,6 +1500,7 @@ CuSuite *get_laws_suite(void)
SUITE_ADD_TEST(suite, test_show_race); SUITE_ADD_TEST(suite, test_show_race);
SUITE_ADD_TEST(suite, test_immigration); SUITE_ADD_TEST(suite, test_immigration);
SUITE_ADD_TEST(suite, test_demon_hunger); SUITE_ADD_TEST(suite, test_demon_hunger);
SUITE_ADD_TEST(suite, test_armedmen);
return suite; return suite;
} }

View File

@ -262,27 +262,6 @@ static int setup_signal_handler(void)
} }
#endif #endif
#undef CRTDBG
#ifdef CRTDBG
#include <crtdbg.h>
void init_crtdbg(void)
{
#if (defined(_MSC_VER))
int flags = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
if (memdebug == 1) {
flags |= _CRTDBG_CHECK_ALWAYS_DF; /* expensive */
} else if (memdebug == 2) {
flags = (flags & 0x0000FFFF) | _CRTDBG_CHECK_EVERY_16_DF;
} else if (memdebug == 3) {
flags = (flags & 0x0000FFFF) | _CRTDBG_CHECK_EVERY_128_DF;
} else if (memdebug == 4) {
flags = (flags & 0x0000FFFF) | _CRTDBG_CHECK_EVERY_1024_DF;
}
_CrtSetDbgFlag(flags);
#endif
}
#endif
void locale_init(void) void locale_init(void)
{ {
setlocale(LC_CTYPE, ""); setlocale(LC_CTYPE, "");
@ -310,10 +289,6 @@ int main(int argc, char **argv)
locale_init(); locale_init();
#ifdef CRTDBG
init_crtdbg();
#endif
L = lua_init(); L = lua_init();
game_init(); game_init();
bind_monsters(L); bind_monsters(L);

View File

@ -202,7 +202,7 @@ static order *get_money_for_dragon(region * r, unit * udragon, int wanted)
/* falls der drache launisch ist, oder das regionssilber knapp, greift er alle an /* falls der drache launisch ist, oder das regionssilber knapp, greift er alle an
* und holt sich Silber von Einheiten, vorausgesetzt er bewacht bereits */ * und holt sich Silber von Einheiten, vorausgesetzt er bewacht bereits */
money = 0; money = 0;
if (attacks && is_guard(udragon, GUARD_TAX)) { if (attacks && is_guard(udragon)) {
money += monster_attacks(udragon, true, true); money += monster_attacks(udragon, true, true);
} }
@ -735,7 +735,7 @@ void plan_monsters(faction * f)
setstatus(u, ST_FIGHT); setstatus(u, ST_FIGHT);
/* all monsters fight */ /* all monsters fight */
} }
if (attacking && (!r->land || is_guard(u, GUARD_TAX))) { if (attacking && (!r->land || is_guard(u))) {
monster_attacks(u, true, false); monster_attacks(u, true, false);
} }

View File

@ -74,7 +74,7 @@ static void test_monsters_attack(CuTest * tc)
create_monsters(&f, &f2, &u, &m); create_monsters(&f, &f2, &u, &m);
guard(m, GUARD_TAX); setguard(m, true);
config_set("rules.monsters.attack_chance", "1"); config_set("rules.monsters.attack_chance", "1");
@ -111,7 +111,7 @@ static void test_monsters_waiting(CuTest * tc)
unit *u, *m; unit *u, *m;
create_monsters(&f, &f2, &u, &m); create_monsters(&f, &f2, &u, &m);
guard(m, GUARD_TAX); setguard(m, true);
fset(m, UFL_ISNEW); fset(m, UFL_ISNEW);
monster_attacks(m, false, false); monster_attacks(m, false, false);
CuAssertPtrEquals(tc, 0, find_order("attack 1", m)); CuAssertPtrEquals(tc, 0, find_order("attack 1", m));
@ -150,8 +150,8 @@ static void test_monsters_attack_not(CuTest * tc)
create_monsters(&f, &f2, &u, &m); create_monsters(&f, &f2, &u, &m);
guard(m, GUARD_TAX); setguard(m, true);
guard(u, GUARD_TAX); setguard(u, true);
config_set("rules.monsters.attack_chance", "0"); config_set("rules.monsters.attack_chance", "0");
@ -170,7 +170,7 @@ static void test_dragon_attacks_the_rich(CuTest * tc)
create_monsters(&f, &f2, &u, &m); create_monsters(&f, &f2, &u, &m);
init_resources(); init_resources();
guard(m, GUARD_TAX); setguard(m, true);
set_level(m, SK_WEAPONLESS, 10); set_level(m, SK_WEAPONLESS, 10);
rsetmoney(findregion(0, 0), 1); rsetmoney(findregion(0, 0), 1);

View File

@ -934,7 +934,7 @@ static unit *bewegung_blockiert_von(unit * reisender, region * r)
if (fval(u_race(reisender), RCF_ILLUSIONARY)) if (fval(u_race(reisender), RCF_ILLUSIONARY))
return NULL; return NULL;
for (u = r->units; u; u = u->next) { for (u = r->units; u; u = u->next) {
if (is_guard(u, GUARD_TRAVELTHRU)) { if (is_guard(u)) {
int sk = effskill(u, SK_PERCEPTION, r); int sk = effskill(u, SK_PERCEPTION, r);
if (invisible(reisender, u) >= reisender->number) if (invisible(reisender, u) >= reisender->number)
continue; continue;
@ -977,82 +977,6 @@ static unit *bewegung_blockiert_von(unit * reisender, region * r)
return NULL; return NULL;
} }
static bool is_guardian_u(const unit * guard, unit * u, unsigned int mask)
{
if (guard->faction == u->faction)
return false;
if (is_guard(guard, mask) == 0)
return false;
if (alliedunit(guard, u->faction, HELP_GUARD))
return false;
if (ucontact(guard, u))
return false;
if (!cansee(guard->faction, u->region, u, 0))
return false;
if (!(u_race(guard)->flags & RCF_FLY) && u_race(u)->flags & RCF_FLY)
return false;
return true;
}
static bool is_guardian_r(const unit * guard)
{
if (guard->number == 0)
return false;
if (besieged(guard))
return false;
/* if region_owners exist then they may be guardians: */
if (guard->building && rule_region_owners() && guard == building_owner(guard->building)) {
faction *owner = region_get_owner(guard->region);
if (owner == guard->faction) {
building *bowner = largestbuilding(guard->region, &cmp_taxes, false);
if (bowner == guard->building) {
return true;
}
}
}
if ((guard->flags & UFL_GUARD) == 0)
return false;
return armedmen(guard, true) > 0 || fval(u_race(guard), RCF_UNARMEDGUARD);
}
bool is_guard(const struct unit * u, unsigned int mask)
{
return is_guardian_r(u) && (getguard(u) & mask) != 0;
}
unit *is_guarded(region * r, unit * u, unsigned int mask)
{
unit *u2;
int noguards = 1;
if (!fval(r, RF_GUARDED)) {
return NULL;
}
/* at this point, u2 is the last unit we tested to
* be a guard (and failed), or NULL
* i is the position of the first free slot in the cache */
for (u2 = r->units; u2; u2 = u2->next) {
if (is_guardian_r(u2)) {
noguards = 0;
if (is_guardian_u(u2, u, mask)) {
/* u2 is our guard. stop processing (we might have to go further next time) */
return u2;
}
}
}
if (noguards) {
/* you are mistaken, sir. there are no guards in these lands */
freset(r, RF_GUARDED);
}
return NULL;
}
bool move_blocked(const unit * u, const region * r, const region * r2) bool move_blocked(const unit * u, const region * r, const region * r2)
{ {
connection *b; connection *b;
@ -1691,7 +1615,7 @@ static const region_list *travel_route(unit * u,
/* the unit has moved at least one region */ /* the unit has moved at least one region */
int walkmode; int walkmode;
setguard(u, GUARD_NONE); setguard(u, false);
cycle_route(ord, u, steps); cycle_route(ord, u, steps);
if (mode == TRAVEL_RUNNING) { if (mode == TRAVEL_RUNNING) {
@ -1719,7 +1643,7 @@ static const region_list *travel_route(unit * u,
/* make orders for the followers */ /* make orders for the followers */
} }
fset(u, UFL_LONGACTION | UFL_NOTMOVING); fset(u, UFL_LONGACTION | UFL_NOTMOVING);
setguard(u, GUARD_NONE); setguard(u, false);
assert(u->region == current); assert(u->region == current);
return iroute; return iroute;
} }
@ -2217,7 +2141,7 @@ static void travel(unit * u, region_list ** routep)
sh = NULL; sh = NULL;
} }
if (sh) { if (sh) {
unit *guard = is_guarded(r, u, GUARD_LANDING); unit *guard = is_guarded(r, u);
if (guard) { if (guard) {
ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder,
"region_guarded", "guard", guard)); "region_guarded", "guard", guard));

View File

@ -60,8 +60,6 @@ extern "C" {
int personcapacity(const struct unit *u); int personcapacity(const struct unit *u);
void movement(void); void movement(void);
void run_to(struct unit *u, struct region *to); void run_to(struct unit *u, struct region *to);
struct unit *is_guarded(struct region *r, struct unit *u, unsigned int mask);
bool is_guard(const struct unit *u, unsigned int mask);
int enoughsailors(const struct ship *sh, int sumskill); int enoughsailors(const struct ship *sh, int sumskill);
bool canswim(struct unit *u); bool canswim(struct unit *u);
bool canfly(struct unit *u); bool canfly(struct unit *u);

View File

@ -2,7 +2,6 @@
#include <stdlib.h> #include <stdlib.h>
#include "move.h" #include "move.h"
#include "guard.h"
#include "keyword.h" #include "keyword.h"
#include <kernel/config.h> #include <kernel/config.h>
@ -201,30 +200,6 @@ static void test_walkingcapacity(CuTest *tc) {
test_cleanup(); test_cleanup();
} }
static void test_is_guarded(CuTest *tc) {
unit *u1, *u2;
region *r;
race *rc;
test_cleanup();
rc = rc_get_or_create("dragon");
rc->flags |= RCF_UNARMEDGUARD;
r = test_create_region(0, 0, 0);
u1 = test_create_unit(test_create_faction(0), r);
u2 = test_create_unit(test_create_faction(rc), r);
CuAssertPtrEquals(tc, 0, is_guarded(r, u1, GUARD_TRAVELTHRU));
CuAssertPtrEquals(tc, 0, is_guarded(r, u1, GUARD_PRODUCE));
CuAssertPtrEquals(tc, 0, is_guarded(r, u1, GUARD_TREES));
CuAssertPtrEquals(tc, 0, is_guarded(r, u1, GUARD_MINING));
guard(u2, GUARD_MINING | GUARD_PRODUCE);
CuAssertIntEquals(tc, GUARD_CREWS | GUARD_LANDING | GUARD_TRAVELTHRU | GUARD_TAX | GUARD_PRODUCE | GUARD_RECRUIT, guard_flags(u2));
CuAssertPtrEquals(tc, 0, is_guarded(r, u1, GUARD_TRAVELTHRU));
CuAssertPtrEquals(tc, 0, is_guarded(r, u1, GUARD_TREES));
CuAssertPtrEquals(tc, 0, is_guarded(r, u1, GUARD_MINING));
CuAssertPtrEquals(tc, u2, is_guarded(r, u1, GUARD_PRODUCE));
test_cleanup();
}
static void test_ship_trails(CuTest *tc) { static void test_ship_trails(CuTest *tc) {
ship *sh; ship *sh;
region *r1, *r2, *r3; region *r1, *r2, *r3;
@ -526,7 +501,6 @@ CuSuite *get_move_suite(void)
SUITE_ADD_TEST(suite, test_ship_has_harbormaster_contact); SUITE_ADD_TEST(suite, test_ship_has_harbormaster_contact);
SUITE_ADD_TEST(suite, test_ship_has_harbormaster_ally); SUITE_ADD_TEST(suite, test_ship_has_harbormaster_ally);
SUITE_ADD_TEST(suite, test_ship_has_harbormaster_same_faction); SUITE_ADD_TEST(suite, test_ship_has_harbormaster_same_faction);
SUITE_ADD_TEST(suite, test_is_guarded);
SUITE_ADD_TEST(suite, test_ship_trails); SUITE_ADD_TEST(suite, test_ship_trails);
SUITE_ADD_TEST(suite, test_age_trails); SUITE_ADD_TEST(suite, test_age_trails);
SUITE_ADD_TEST(suite, test_ship_no_overload); SUITE_ADD_TEST(suite, test_ship_no_overload);

View File

@ -1671,7 +1671,7 @@ static void guards(stream *out, const region * r, const faction * see)
/* Bewachung */ /* Bewachung */
for (u = r->units; u; u = u->next) { for (u = r->units; u; u = u->next) {
if (is_guard(u, GUARD_ALL) != 0) { if (is_guard(u) != 0) {
faction *f = u->faction; faction *f = u->faction;
faction *fv = visible_faction(see, u); faction *fv = visible_faction(see, u);

View File

@ -141,9 +141,9 @@ size_t report_status(const unit * u, const struct locale *lang, char *fsbuf, siz
if (!status) { if (!status) {
const char *lname = locale_name(lang); const char *lname = locale_name(lang);
struct locale *wloc = get_or_create_locale(lname); struct locale *wloc = get_or_create_locale(lname);
log_error("no translation for combat status %s in %s", combatstatus[u->status], lname); log_warning("no translation for combat status %s in %s", combatstatus[u->status], lname);
locale_setstring(wloc, combatstatus[u->status], combatstatus[u->status]); locale_setstring(wloc, combatstatus[u->status], combatstatus[u->status]+7);
len = strlcpy(fsbuf, combatstatus[u->status], buflen); len = strlcpy(fsbuf, combatstatus[u->status]+7, buflen);
} }
else { else {
len = strlcpy(fsbuf, status, buflen); len = strlcpy(fsbuf, status, buflen);
@ -582,7 +582,7 @@ size_t size)
} }
} }
} }
if (is_guard(u, GUARD_ALL) != 0) { if (is_guard(u)) {
bufp = STRLCPY(bufp, ", ", size); bufp = STRLCPY(bufp, ", ", size);
bufp = STRLCPY(bufp, LOC(f->locale, "unit_guards"), size); bufp = STRLCPY(bufp, LOC(f->locale, "unit_guards"), size);
} }

View File

@ -10,10 +10,6 @@
without prior permission by the authors of Eressea. without prior permission by the authors of Eressea.
*/ */
/*
* Contains defines for the "free" game (Eressea) .
* Include this file from settings.h to make eressea work.
*/
#define ENTERTAINFRACTION 20 #define ENTERTAINFRACTION 20
#define TEACHDIFFERENCE 2 #define TEACHDIFFERENCE 2
#define GUARD_DISABLES_RECRUIT 1 #define GUARD_DISABLES_RECRUIT 1

View File

@ -2196,7 +2196,7 @@ static int sp_ironkeeper(castorder * co)
/*keeper->age = cast_level + 2; */ /*keeper->age = cast_level + 2; */
setstatus(keeper, ST_AVOID); /* kaempft nicht */ setstatus(keeper, ST_AVOID); /* kaempft nicht */
guard(keeper, GUARD_MINING); setguard(keeper, true);
fset(keeper, UFL_ISNEW); fset(keeper, UFL_ISNEW);
/* Parteitarnen, damit man nicht sofort weiß, wer dahinter steckt */ /* Parteitarnen, damit man nicht sofort weiß, wer dahinter steckt */
if (rule_stealth_anon()) { if (rule_stealth_anon()) {
@ -2386,7 +2386,6 @@ void patzer_peasantmob(const castorder * co)
create_unit(r, f, n, get_race(RC_PEASANT), 0, LOC(f->locale, "angry_mob"), create_unit(r, f, n, get_race(RC_PEASANT), 0, LOC(f->locale, "angry_mob"),
NULL); NULL);
fset(u, UFL_ISNEW); fset(u, UFL_ISNEW);
/* guard(u, GUARD_ALL); hier zu frueh! Befehl BEWACHE setzten */
addlist(&u->orders, create_order(K_GUARD, lang, NULL)); addlist(&u->orders, create_order(K_GUARD, lang, NULL));
set_order(&u->thisorder, default_order(lang)); set_order(&u->thisorder, default_order(lang));
a = a_new(&at_unitdissolve); a = a_new(&at_unitdissolve);
@ -3746,7 +3745,7 @@ static int sp_rallypeasantmob(castorder * co)
rsetpeasants(r, rpeasants(r) + u->number); rsetpeasants(r, rpeasants(r) + u->number);
rsetmoney(r, rmoney(r) + get_money(u)); rsetmoney(r, rmoney(r) + get_money(u));
set_money(u, 0); set_money(u, 0);
setguard(u, GUARD_NONE); setguard(u, false);
set_number(u, 0); set_number(u, 0);
erfolg = cast_level; erfolg = cast_level;
} }
@ -3813,7 +3812,7 @@ static int sp_raisepeasantmob(castorder * co)
create_unit(r, monsters, n, get_race(RC_PEASANT), 0, LOC(monsters->locale, create_unit(r, monsters, n, get_race(RC_PEASANT), 0, LOC(monsters->locale,
"furious_mob"), NULL); "furious_mob"), NULL);
fset(u, UFL_ISNEW); fset(u, UFL_ISNEW);
guard(u, GUARD_ALL); setguard(u, true);
a = a_new(&at_unitdissolve); a = a_new(&at_unitdissolve);
a->data.ca[0] = 1; /* An rpeasants(r). */ a->data.ca[0] = 1; /* An rpeasants(r). */
a->data.ca[1] = 15; /* 15% */ a->data.ca[1] = 15; /* 15% */

View File

@ -1437,7 +1437,7 @@ int sp_denyattack(struct castorder * co)
leave(mage, false); leave(mage, false);
} }
/* und bewachen nicht */ /* und bewachen nicht */
setguard(mage, GUARD_NONE); setguard(mage, false);
/* irgendwie den langen befehl sperren */ /* irgendwie den langen befehl sperren */
/* fset(fi, FIG_ATTACKED); */ /* fset(fi, FIG_ATTACKED); */
@ -1800,7 +1800,7 @@ int sp_undeadhero(struct castorder * co)
unit_setinfo(u, NULL); unit_setinfo(u, NULL);
} }
setstatus(u, du->status); setstatus(u, du->status);
setguard(u, GUARD_NONE); setguard(u, false);
for (ilist = &du->items; *ilist;) { for (ilist = &du->items; *ilist;) {
item *itm = *ilist; item *itm = *ilist;
int loot = itm->number * j / du->number; int loot = itm->number * j / du->number;

View File

@ -463,7 +463,7 @@ static void sink_ship(region * r, ship * sh, unit * saboteur)
} }
leave_ship(u); leave_ship(u);
if (r != safety) { if (r != safety) {
setguard(u, GUARD_NONE); setguard(u, false);
} }
while (u->items) { while (u->items) {
i_remove(&u->items, u->items); i_remove(&u->items, u->items);

View File

@ -111,6 +111,7 @@ int RunAllTests(int argc, char *argv[])
ADD_SUITE(ally); ADD_SUITE(ally);
ADD_SUITE(messages); ADD_SUITE(messages);
/* gamecode */ /* gamecode */
ADD_SUITE(guard);
ADD_SUITE(report); ADD_SUITE(report);
ADD_SUITE(creport); ADD_SUITE(creport);
ADD_SUITE(prefix); ADD_SUITE(prefix);