diff --git a/doc/befehle.txt b/doc/befehle.txt new file mode 100644 index 000000000..0c725fb7b --- /dev/null +++ b/doc/befehle.txt @@ -0,0 +1,15 @@ +# Befehlsverarbeitung in Eressea + +Einheiten haben zwei Listen von Befehlen: orders und old_orders. + +1. `read_unit`: Aus dem Datenfile gelesene (Default-)Befehl der Vorwoche werden in u->orders gespeichert. +2. `begin_orders`: Wenn die Einheit neue Befehle erhält, werden "wiederholbare" Befehle (Handel, lange Befehle ausser NACH) aus u->orders nach u->old_orders kopiert. +3. `unitorders`: Die neuen Befehle werden in u->orders gelesen. +4. `update_long_order`: u->thisorder wird auf den ersten "langen" Befehl in u->orders gesetzt. +5. Auswertung: Für lange Befehle wird in u->thisorder geschaut, für kurze und andere (inkl. KAUFE/ATTACKIERE) in u->orders. +6. `movement`: NACH löscht u->thisorder, damit es nicht bei Auswertung der Zielregion ein zweites Mal ausgeführt werden kann. Das hat allerdings keine Auswirkung auf die beiden Listen. +7. `build_building`: Wenn ein MACHE GEBAEUDE Befehl "fertig" ist, wird der Befehl in u->orders durch ein ARBEITE ersetzt (aber u->thisorder nicht geändert, das sollte also nichts tun). +8. `defaultorders`: Nach allen langen Befehlen wird der DEFAULT Befehl gesetzt. Dieser löscht zuerst alle nicht-kurzen Befehle aus u->orders und u->old_orders, und hängt dann den neuen Befehl in u->old_orders an. +9.1: `cr_output_unit`: In den CR werden alle "dauerhaften" Befehle aus u->old_orders geschrieben, d.h. kurze Befehle mit @ Prefix, Kommentare mit // und lange Befehle ausser NACH. +9.2: `cr_output_unit`: In den CR werden alle "dauerhaften" Befehle aus u->orders geschrieben, d.h. kurze Befehle mit @ Prefix, Kommentare mit // und lange Befehle ausser NACH. Wenn u->old_orders nicht leer ist, werden "wiederholbare" Befehle dabei ignoriert. + diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index 96069d4a5..70ff2527d 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -1187,7 +1187,6 @@ function test_promote_after_recruit() local r1 = region.create(0, 0, 'plain') local r2 = region.create(1, 0, 'plain') local u1 = unit.create(f, r1, 1) - u1.name = 'Xolgrim' local u2 = unit.create(f, r2, 55) u2:add_order('REKRUTIERE 1') u1:add_order('BEFOERDERE') diff --git a/scripts/tests/e2/allies.lua b/scripts/tests/e2/allies.lua index ef38a97bf..8c0352923 100644 --- a/scripts/tests/e2/allies.lua +++ b/scripts/tests/e2/allies.lua @@ -2,16 +2,8 @@ require "lunit" module("tests.e2.allies", package.seeall, lunit.testcase) -function skip_test_get_set_ally() - local f1 = faction.create("human") - local f2 = faction.create("human") - - assert_equal(false, f1:get_ally(f2, "guard")) - f1:set_ally(f2, "guard", true) - assert_equal(true, f1:get_ally(f2, "guard")) - assert_equal(false, f1:get_ally(f2, "give")) - f1:set_ally(f2, "give", true) - assert_equal(true, f1:get_ally(f2, "give")) +function setup() + eressea.free_game() end function test_get_allies() @@ -28,3 +20,16 @@ function test_get_allies() assert_equal(1, #allies[f2.id]) assert_equal("give", allies[f2.id][1]) end + +function test_get_set_ally() + local f1 = faction.create("human") + local f2 = faction.create("human") + + assert_equal(false, f1:get_ally(f2, "guard")) + f1:set_ally(f2, "guard", true) + assert_equal(true, f1:get_ally(f2, "guard")) + assert_equal(false, f1:get_ally(f2, "give")) + f1:set_ally(f2, "give", true) + assert_equal(true, f1:get_ally(f2, "give")) +end + diff --git a/scripts/tests/e2/buildings.lua b/scripts/tests/e2/buildings.lua index 845c4ba7d..a2407335b 100644 --- a/scripts/tests/e2/buildings.lua +++ b/scripts/tests/e2/buildings.lua @@ -41,7 +41,6 @@ function test_build_tunnel_limited() u:add_item('iron', 2) u:add_item('money', 700) u.building = b - u.name = 'Xolgrim' u:add_order('MACHE 2 BURG ' .. itoa36(b.id)) b.size = 99 process_orders() diff --git a/scripts/tests/e2/e2features.lua b/scripts/tests/e2/e2features.lua index b0233c3fb..3175a091e 100644 --- a/scripts/tests/e2/e2features.lua +++ b/scripts/tests/e2/e2features.lua @@ -12,6 +12,26 @@ function setup() eressea.settings.set("rules.peasants.growth.factor", "0") end +function disabled_double_default() + local r = region.create(0, 0, "plain") + local f = faction.create("human") + local u = unit.create(f, r, 1) + region.create(1, 0, "plain") + region.create(2, 0, "plain") + region.create(3, 0, "plain") + + u:add_order('NACH O') + u:add_order('DEFAULT "NACH O"') + u:add_order('DEFAULT "DEFAULT ARBEITE"') + process_orders() + assert_equal(1, u.region.x) + process_orders() + assert_equal(2, u.region.x) + process_orders() + assert_equal(2, u.region.x) + assert_equal("ARBEITE", u:get_order()) +end + function test_give_unit() local r = region.create(0, 0, "plain") local f1 = faction.create('elf') diff --git a/scripts/tests/e2/init.lua b/scripts/tests/e2/init.lua index bbd714521..4246fd288 100644 --- a/scripts/tests/e2/init.lua +++ b/scripts/tests/e2/init.lua @@ -1,7 +1,6 @@ +require 'tests.e2.trolls' require 'tests.e2.trees' require 'tests.e2.buildings' -require 'tests.e2.allies' -require 'tests.e2.quit' require 'tests.e2.movement' require 'tests.e2.carts' require 'tests.e2.quit' @@ -10,6 +9,7 @@ require 'tests.e2.spells' require 'tests.e2.e2features' require 'tests.e2.insects' require 'tests.e2.production' +require 'tests.e2.allies' require 'tests.e2.adamantium' require 'tests.e2.undead' require 'tests.e2.shiplanding' diff --git a/scripts/tests/e2/spells.lua b/scripts/tests/e2/spells.lua index 9cdc28b96..8942ee1f5 100644 --- a/scripts/tests/e2/spells.lua +++ b/scripts/tests/e2/spells.lua @@ -3,7 +3,7 @@ require "lunit" module("tests.e2.spells", package.seeall, lunit.testcase) function setup() - eressea.free_game() + eressea.game.reset() eressea.settings.set("nmr.removenewbie", "0") eressea.settings.set("nmr.timeout", "0") eressea.settings.set("NewbieImmunity", "0") @@ -21,9 +21,6 @@ function test_undead_cannot_enter_holyground() local u1 = unit.create(f, r1, 1) local u2 = unit.create(f, r2, 1) - u2.name = "Xolgrim's Magier" - u1.name = "Xolgrim's Opfer" - u2.magic = 'gwyrrd' u2:set_skill('magic', 100) u2.aura = 200 @@ -227,7 +224,6 @@ function test_bug_2517() local uf = nil eressea.settings.set("magic.familiar.race", "lynx") f.magic = 'gwyrrd' - um.name = 'Xolgrim' um.magic = 'gwyrrd' um.race = 'elf' um:set_skill('magic', 10) diff --git a/scripts/tests/e2/trees.lua b/scripts/tests/e2/trees.lua index 933ae78e0..739d9f1e6 100644 --- a/scripts/tests/e2/trees.lua +++ b/scripts/tests/e2/trees.lua @@ -15,7 +15,7 @@ function test_no_growth() set_turn(204) assert_equal('spring', get_season()) local r = region.create(0, 0, 'plain') - r:set_flag(2, 0) -- no mallorn + r:set_flag(1, false) -- no mallorn r:set_resource('seed', 0) r:set_resource('sapling', 0) r:set_resource('tree', 0) @@ -30,7 +30,7 @@ function test_spring_growth() set_turn(204) assert_equal('spring', get_season()) local r = region.create(0, 0, 'plain') - r:set_flag(2, 0) -- no mallorn + r:set_flag(1, false) -- no mallorn r:set_resource('seed', 6) r:set_resource('sapling', 17) r:set_resource('tree', 0) @@ -46,7 +46,7 @@ function test_plant_fail() assert_equal('summer', get_season()) local f = faction.create('goblin') local r = region.create(0, 0, 'plain') - r:set_flag(2, 0) -- no mallorn + r:set_flag(1, false) -- no mallorn r:set_resource('seed', 0) r:set_resource('sapling', 0) r:set_resource('tree', 0) @@ -67,7 +67,7 @@ function test_plant_summer() assert_equal('summer', get_season()) local f = faction.create('goblin') local r = region.create(0, 0, 'plain') - r:set_flag(2, 0) -- no mallorn + r:set_flag(1, false) -- no mallorn r:set_resource('seed', 0) r:set_resource('sapling', 0) r:set_resource('tree', 0) @@ -89,7 +89,7 @@ function test_plant_spring_saplings() local f = faction.create('goblin') local r = region.create(0, 0, 'plain') local u = unit.create(f, r) - r:set_flag(2, 0) -- no mallorn + r:set_flag(1, false) -- no mallorn r:set_resource('seed', 0) r:set_resource('sapling', 0) r:set_resource('tree', 0) @@ -117,7 +117,7 @@ function test_plant_spring_seeds() local f = faction.create('goblin') local r = region.create(0, 0, 'plain') local u = unit.create(f, r) - r:set_flag(2, 0) -- no mallorn + r:set_flag(1, false) -- no mallorn r:set_resource('seed', 0) r:set_resource('sapling', 0) r:set_resource('tree', 0) diff --git a/scripts/tests/e2/trolls.lua b/scripts/tests/e2/trolls.lua new file mode 100644 index 000000000..b6d96b015 --- /dev/null +++ b/scripts/tests/e2/trolls.lua @@ -0,0 +1,50 @@ +require "lunit" + +module("tests.e2.trolls", package.seeall, lunit.testcase ) + +function setup() + eressea.free_game() +end + +function test_trolls_with_horses() + local r0 = region.create(0, 0, 'plain') + local r1 = region.create(1, 0, 'plain') + local r2 = region.create(2, 0, 'plain') + local r3 = region.create(3, 0, 'plain') + local r4 = region.create(4, 0, 'plain') + local r5 = region.create(5, 0, 'plain') + + local f = faction.create('troll') + -- 1. 20 trolls can pull 5 loaded carts: + assert_not_nil(r0) + local u1 = unit.create(f, r0, 20) + u1:add_item('cart', 5) + -- trolls carry 10.8 GE, carts carry 100 GE: + u1:add_item('money', 100 * (5 * 100 + 2 * 108)) + u1:add_order('NACH O O O') + + process_orders() + assert_equal(r1, u1.region) + + -- 20 trolls can also lead 20 horses + u1:add_item('horse', 20) + u1:add_item('money', 100 * 20 * 20) + + process_orders() + assert_equal(r2, u1.region) + + -- test if trolls are still "lazy". If yes they should still manage 10 full carts behind the 20 horses (5 more) + u1:add_item('cart', 5) + u1:add_item('money', 100 * 5 * 100) + + process_orders() + assert_equal(r3, u1.region) + + -- test if trolls are still "lazy". If not they should manage 15 full carts, 5 behind trolls and 10 behind 20 horses (again 5 more) + u1:add_item('cart', 5) + u1:add_item('money', 100 * 5 * 100) + + process_orders() + assert_equal(r4, u1.region) + +end diff --git a/scripts/tests/e2/undead.lua b/scripts/tests/e2/undead.lua index f7586ee4b..b283d1fcc 100644 --- a/scripts/tests/e2/undead.lua +++ b/scripts/tests/e2/undead.lua @@ -28,7 +28,6 @@ function test_undead_reserve_other() u1.race = "undead" u1:clear_orders() u1:add_order("RESERVIERE 1 Holz") - u1.name = 'Xolgrim' process_orders() if 0 ~= u1:get_item("log") then diff --git a/src/kernel/race.c b/src/kernel/race.c index 95239bd3f..23b25c891 100644 --- a/src/kernel/race.c +++ b/src/kernel/race.c @@ -294,7 +294,7 @@ static race *rc_find_i(const char *name) return rc; } -const race * rc_find(const char *name) { +race * rc_find(const char *name) { return rc_find_i(name); } diff --git a/src/kernel/race.h b/src/kernel/race.h index bce12912d..4cc07564e 100644 --- a/src/kernel/race.h +++ b/src/kernel/race.h @@ -155,7 +155,7 @@ extern "C" { race *rc_create(const char *zName); race *rc_get_or_create(const char *name); bool rc_changed(int *cache); - const race *rc_find(const char *); + race *rc_find(const char *); void free_races(void); bool rc_can_use(const struct race *rc, const struct item_type *itype); diff --git a/src/laws.c b/src/laws.c index 00fa600af..97d9b774f 100644 --- a/src/laws.c +++ b/src/laws.c @@ -980,7 +980,7 @@ int quit_cmd(unit * u, struct order *ord) if (p == P_FACTION) { #ifdef QUIT_WITH_TRANSFER faction *f2 = getfaction(); - if (f2 == NULL) { + if (f2 == NULL || f2 == u->faction) { cmistake(u, ord, 66, MSG_EVENT); flags = 0; } diff --git a/src/monsters.c b/src/monsters.c index 76a0fabb6..08b65ce3a 100644 --- a/src/monsters.c +++ b/src/monsters.c @@ -142,18 +142,39 @@ static void reduce_weight(unit * u) } } +static bool monster_is_waiting(const unit * u) +{ + int test = fval(u_race(u), RCF_ATTACK_MOVED) ? UFL_ISNEW : UFL_ISNEW | UFL_MOVED; + if (fval(u, test)) + return true; + return false; +} + +static bool monster_can_attack(const unit * u) +{ + if (u->status >= ST_AVOID) { + return false; + } + if (u->region->land) { + return is_guard(u); + } + else if (fval(u->region->terrain, SEA_REGION)) { + return fval(u_race(u), RCF_SWIM); + } + return fval(u_race(u), RCF_FLY); +} + static order *monster_attack(unit * u, const unit * target) { assert(u->region == target->region); assert(u->faction != target->faction); - if (!cansee(u->faction, u->region, target, 0)) - return NULL; - if (monster_is_waiting(u)) - return NULL; - - if (u->region->land && (u->region->flags & RF_GUARDED) == 0) { + if (!cansee(u->faction, u->region, target, 0)) { return NULL; } + if (monster_is_waiting(u)) { + return NULL; + } + return create_order(K_ATTACK, u->faction->locale, "%i", target->no); } @@ -185,7 +206,8 @@ int monster_attacks(unit * monster, bool rich_only) { const race *rc_serpent = get_race(RC_SEASERPENT); int result = -1; - if (monster->status < ST_AVOID) { + + if (monster_can_attack(monster)) { region *r = monster->region; unit *u2; int money = 0; @@ -231,7 +253,7 @@ static order *get_money_for_dragon(region * r, unit * u, int wanted) /* falls der drache launisch ist, oder das regionssilber knapp, greift er alle an * und holt sich Silber von Einheiten, vorausgesetzt er bewacht bereits */ money = 0; - if (attacks && is_guard(u)) { + if (attacks && monster_can_attack(u)) { int m = monster_attacks(u, true); if (m > 0) money += m; } @@ -774,7 +796,7 @@ void plan_monsters(faction * f) ta = a_find(u->attribs, &at_hate); if (ta && !monster_is_waiting(u)) { unit *tu = (unit *)ta->data.v; - if (tu && tu->region == r) { + if (tu && tu->region == r && monster_can_attack(u)) { order * ord = monster_attack(u, tu); if (ord) { unit_addorder(u, ord); @@ -792,7 +814,7 @@ void plan_monsters(faction * f) else a_remove(&u->attribs, ta); } - else if (!r->land || guarding) { + else if (monster_can_attack(u)) { if (chance(attack_chance)) { int m = monster_attacks(u, false); if (m >= 0) { @@ -1013,14 +1035,6 @@ void spawn_undead(void) } } -bool monster_is_waiting(const unit * u) -{ - int test = fval(u_race(u), RCF_ATTACK_MOVED) ? UFL_ISNEW : UFL_ISNEW | UFL_MOVED; - if (fval(u, test)) - return true; - return false; -} - static void eaten_by_monster(unit * u) { /* adjustment for smaller worlds */ diff --git a/src/monsters.h b/src/monsters.h index 99d60a3fb..e799c68c4 100644 --- a/src/monsters.h +++ b/src/monsters.h @@ -18,7 +18,6 @@ extern "C" { void monsters_desert(struct faction *monsters); void monster_kills_peasants(struct unit *u); - bool monster_is_waiting(const struct unit *u); void make_zombie(struct unit * u); void spawn_undead(void); diff --git a/src/monsters.test.c b/src/monsters.test.c index 75a2cbc97..695e2f5e2 100644 --- a/src/monsters.test.c +++ b/src/monsters.test.c @@ -97,6 +97,7 @@ static void test_monsters_attack_ocean(CuTest * tc) { region *r; unit *u, *m; + race *rc; test_setup(); create_monsters(&u, &m); @@ -105,12 +106,18 @@ static void test_monsters_attack_ocean(CuTest * tc) unit_setid(u, 2); m = test_create_unit(m->faction, r); assert(!m->region->land); - + config_set("rules.monsters.attack_chance", "1"); + rc = rc_find(m->_race->_name); + freset(rc, RCF_SWIM); plan_monsters(m->faction); + CuAssertPtrEquals(tc, NULL, find_order("attack 2", m)); + fset(rc, RCF_SWIM); + plan_monsters(m->faction); CuAssertPtrNotNull(tc, find_order("attack 2", m)); + test_teardown(); } @@ -145,7 +152,7 @@ static void test_seaserpent_piracy(CuTest * tc) u_setrace(m, rc = test_create_race("seaserpent")); assert(!m->region->land); fset(m, UFL_MOVED); - fset(rc, RCF_ATTACK_MOVED); + fset(rc, RCF_ATTACK_MOVED|RCF_SWIM); config_set("rules.monsters.attack_chance", "1"); diff --git a/src/report.c b/src/report.c index 7fdf8e690..1560f42e2 100644 --- a/src/report.c +++ b/src/report.c @@ -1718,23 +1718,23 @@ nr_ship(struct stream *out, const region *r, const ship * sh, const faction * f, char buffer[1024]; char ch; sbstring sbs; + const char *stname; sbs_init(&sbs, buffer, sizeof(buffer)); newline(out); + stname = locale_plural(f->locale, sh->type->_name, sh->number, true); if (captain && captain->faction == f) { int n = 0, p = 0; - const char *stname; getshipweight(sh, &n, &p); n = (n + 99) / 100; /* 1 Silber = 1 GE */ - stname = locale_plural(f->locale, sh->type->_name, sh->number, true); sbs_printf(&sbs, "%s, %d %s, (%d/%d)", shipname(sh), sh->number, stname, n, ship_capacity(sh) / 100); } else { - sbs_printf(&sbs, "%s, %s", shipname(sh), LOC(f->locale, sh->type->_name)); + sbs_printf(&sbs, "%s, %d %s", shipname(sh), sh->number, stname); } if (!ship_finished(sh)) { diff --git a/src/spells.c b/src/spells.c index 6cff4bb9b..de2036225 100644 --- a/src/spells.c +++ b/src/spells.c @@ -2358,9 +2358,8 @@ static void patzer_peasantmob(const castorder * co) rsetpeasants(r, rpeasants(r) - n); assert(rpeasants(r) >= 0); - u = - create_unit(r, f, n, get_race(RC_PEASANT), 0, LOC(f->locale, "angry_mob"), - NULL); + u = create_unit(r, f, n, get_race(RC_PEASANT), 0, + LOC(f->locale, "angry_mob"), NULL); fset(u, UFL_ISNEW); unit_addorder(u, create_order(K_GUARD, lang, NULL)); set_order(&u->thisorder, default_order(lang)); diff --git a/src/util/param.c b/src/util/param.c index 31066a4a9..0c486ce5a 100644 --- a/src/util/param.c +++ b/src/util/param.c @@ -106,10 +106,9 @@ param_t findparam_block(const char *s, const struct locale *lang, bool any_local bool isparam(const char *s, const struct locale * lang, param_t param) { - assert(s); assert(param != P_GEBAEUDE); assert(param != P_BUILDING); - if (s[0] > '@') { + if (s && s[0] > '@') { param_t p = findparam(s, lang); return p == param; }