Merge pull request #891 from ennorehling/develop

Development updates
This commit is contained in:
Enno Rehling 2020-02-08 22:05:39 +01:00 committed by GitHub
commit 1ce051549c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 159 additions and 58 deletions

15
doc/befehle.txt Normal file
View File

@ -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.

View File

@ -1187,7 +1187,6 @@ function test_promote_after_recruit()
local r1 = region.create(0, 0, 'plain') local r1 = region.create(0, 0, 'plain')
local r2 = region.create(1, 0, 'plain') local r2 = region.create(1, 0, 'plain')
local u1 = unit.create(f, r1, 1) local u1 = unit.create(f, r1, 1)
u1.name = 'Xolgrim'
local u2 = unit.create(f, r2, 55) local u2 = unit.create(f, r2, 55)
u2:add_order('REKRUTIERE 1') u2:add_order('REKRUTIERE 1')
u1:add_order('BEFOERDERE') u1:add_order('BEFOERDERE')

View File

@ -2,16 +2,8 @@ require "lunit"
module("tests.e2.allies", package.seeall, lunit.testcase) module("tests.e2.allies", package.seeall, lunit.testcase)
function skip_test_get_set_ally() function setup()
local f1 = faction.create("human") eressea.free_game()
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 end
function test_get_allies() function test_get_allies()
@ -28,3 +20,16 @@ function test_get_allies()
assert_equal(1, #allies[f2.id]) assert_equal(1, #allies[f2.id])
assert_equal("give", allies[f2.id][1]) assert_equal("give", allies[f2.id][1])
end 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

View File

@ -41,7 +41,6 @@ function test_build_tunnel_limited()
u:add_item('iron', 2) u:add_item('iron', 2)
u:add_item('money', 700) u:add_item('money', 700)
u.building = b u.building = b
u.name = 'Xolgrim'
u:add_order('MACHE 2 BURG ' .. itoa36(b.id)) u:add_order('MACHE 2 BURG ' .. itoa36(b.id))
b.size = 99 b.size = 99
process_orders() process_orders()

View File

@ -12,6 +12,26 @@ function setup()
eressea.settings.set("rules.peasants.growth.factor", "0") eressea.settings.set("rules.peasants.growth.factor", "0")
end 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() function test_give_unit()
local r = region.create(0, 0, "plain") local r = region.create(0, 0, "plain")
local f1 = faction.create('elf') local f1 = faction.create('elf')

View File

@ -1,7 +1,6 @@
require 'tests.e2.trolls'
require 'tests.e2.trees' require 'tests.e2.trees'
require 'tests.e2.buildings' require 'tests.e2.buildings'
require 'tests.e2.allies'
require 'tests.e2.quit'
require 'tests.e2.movement' require 'tests.e2.movement'
require 'tests.e2.carts' require 'tests.e2.carts'
require 'tests.e2.quit' require 'tests.e2.quit'
@ -10,6 +9,7 @@ require 'tests.e2.spells'
require 'tests.e2.e2features' require 'tests.e2.e2features'
require 'tests.e2.insects' require 'tests.e2.insects'
require 'tests.e2.production' require 'tests.e2.production'
require 'tests.e2.allies'
require 'tests.e2.adamantium' require 'tests.e2.adamantium'
require 'tests.e2.undead' require 'tests.e2.undead'
require 'tests.e2.shiplanding' require 'tests.e2.shiplanding'

View File

@ -3,7 +3,7 @@ require "lunit"
module("tests.e2.spells", package.seeall, lunit.testcase) module("tests.e2.spells", package.seeall, lunit.testcase)
function setup() function setup()
eressea.free_game() eressea.game.reset()
eressea.settings.set("nmr.removenewbie", "0") eressea.settings.set("nmr.removenewbie", "0")
eressea.settings.set("nmr.timeout", "0") eressea.settings.set("nmr.timeout", "0")
eressea.settings.set("NewbieImmunity", "0") eressea.settings.set("NewbieImmunity", "0")
@ -21,9 +21,6 @@ function test_undead_cannot_enter_holyground()
local u1 = unit.create(f, r1, 1) local u1 = unit.create(f, r1, 1)
local u2 = unit.create(f, r2, 1) local u2 = unit.create(f, r2, 1)
u2.name = "Xolgrim's Magier"
u1.name = "Xolgrim's Opfer"
u2.magic = 'gwyrrd' u2.magic = 'gwyrrd'
u2:set_skill('magic', 100) u2:set_skill('magic', 100)
u2.aura = 200 u2.aura = 200
@ -227,7 +224,6 @@ function test_bug_2517()
local uf = nil local uf = nil
eressea.settings.set("magic.familiar.race", "lynx") eressea.settings.set("magic.familiar.race", "lynx")
f.magic = 'gwyrrd' f.magic = 'gwyrrd'
um.name = 'Xolgrim'
um.magic = 'gwyrrd' um.magic = 'gwyrrd'
um.race = 'elf' um.race = 'elf'
um:set_skill('magic', 10) um:set_skill('magic', 10)

View File

@ -15,7 +15,7 @@ function test_no_growth()
set_turn(204) set_turn(204)
assert_equal('spring', get_season()) assert_equal('spring', get_season())
local r = region.create(0, 0, 'plain') 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('seed', 0)
r:set_resource('sapling', 0) r:set_resource('sapling', 0)
r:set_resource('tree', 0) r:set_resource('tree', 0)
@ -30,7 +30,7 @@ function test_spring_growth()
set_turn(204) set_turn(204)
assert_equal('spring', get_season()) assert_equal('spring', get_season())
local r = region.create(0, 0, 'plain') 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('seed', 6)
r:set_resource('sapling', 17) r:set_resource('sapling', 17)
r:set_resource('tree', 0) r:set_resource('tree', 0)
@ -46,7 +46,7 @@ function test_plant_fail()
assert_equal('summer', get_season()) assert_equal('summer', get_season())
local f = faction.create('goblin') local f = faction.create('goblin')
local r = region.create(0, 0, 'plain') 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('seed', 0)
r:set_resource('sapling', 0) r:set_resource('sapling', 0)
r:set_resource('tree', 0) r:set_resource('tree', 0)
@ -67,7 +67,7 @@ function test_plant_summer()
assert_equal('summer', get_season()) assert_equal('summer', get_season())
local f = faction.create('goblin') local f = faction.create('goblin')
local r = region.create(0, 0, 'plain') 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('seed', 0)
r:set_resource('sapling', 0) r:set_resource('sapling', 0)
r:set_resource('tree', 0) r:set_resource('tree', 0)
@ -89,7 +89,7 @@ function test_plant_spring_saplings()
local f = faction.create('goblin') local f = faction.create('goblin')
local r = region.create(0, 0, 'plain') local r = region.create(0, 0, 'plain')
local u = unit.create(f, r) 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('seed', 0)
r:set_resource('sapling', 0) r:set_resource('sapling', 0)
r:set_resource('tree', 0) r:set_resource('tree', 0)
@ -117,7 +117,7 @@ function test_plant_spring_seeds()
local f = faction.create('goblin') local f = faction.create('goblin')
local r = region.create(0, 0, 'plain') local r = region.create(0, 0, 'plain')
local u = unit.create(f, r) 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('seed', 0)
r:set_resource('sapling', 0) r:set_resource('sapling', 0)
r:set_resource('tree', 0) r:set_resource('tree', 0)

View File

@ -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

View File

@ -28,7 +28,6 @@ function test_undead_reserve_other()
u1.race = "undead" u1.race = "undead"
u1:clear_orders() u1:clear_orders()
u1:add_order("RESERVIERE 1 Holz") u1:add_order("RESERVIERE 1 Holz")
u1.name = 'Xolgrim'
process_orders() process_orders()
if 0 ~= u1:get_item("log") then if 0 ~= u1:get_item("log") then

View File

@ -294,7 +294,7 @@ static race *rc_find_i(const char *name)
return rc; return rc;
} }
const race * rc_find(const char *name) { race * rc_find(const char *name) {
return rc_find_i(name); return rc_find_i(name);
} }

View File

@ -155,7 +155,7 @@ extern "C" {
race *rc_create(const char *zName); race *rc_create(const char *zName);
race *rc_get_or_create(const char *name); race *rc_get_or_create(const char *name);
bool rc_changed(int *cache); bool rc_changed(int *cache);
const race *rc_find(const char *); race *rc_find(const char *);
void free_races(void); void free_races(void);
bool rc_can_use(const struct race *rc, const struct item_type *itype); bool rc_can_use(const struct race *rc, const struct item_type *itype);

View File

@ -980,7 +980,7 @@ int quit_cmd(unit * u, struct order *ord)
if (p == P_FACTION) { if (p == P_FACTION) {
#ifdef QUIT_WITH_TRANSFER #ifdef QUIT_WITH_TRANSFER
faction *f2 = getfaction(); faction *f2 = getfaction();
if (f2 == NULL) { if (f2 == NULL || f2 == u->faction) {
cmistake(u, ord, 66, MSG_EVENT); cmistake(u, ord, 66, MSG_EVENT);
flags = 0; flags = 0;
} }

View File

@ -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) static order *monster_attack(unit * u, const unit * target)
{ {
assert(u->region == target->region); assert(u->region == target->region);
assert(u->faction != target->faction); assert(u->faction != target->faction);
if (!cansee(u->faction, u->region, target, 0)) 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) {
return NULL; return NULL;
} }
if (monster_is_waiting(u)) {
return NULL;
}
return create_order(K_ATTACK, u->faction->locale, "%i", target->no); 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); const race *rc_serpent = get_race(RC_SEASERPENT);
int result = -1; int result = -1;
if (monster->status < ST_AVOID) {
if (monster_can_attack(monster)) {
region *r = monster->region; region *r = monster->region;
unit *u2; unit *u2;
int money = 0; 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 /* 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(u)) { if (attacks && monster_can_attack(u)) {
int m = monster_attacks(u, true); int m = monster_attacks(u, true);
if (m > 0) money += m; if (m > 0) money += m;
} }
@ -774,7 +796,7 @@ void plan_monsters(faction * f)
ta = a_find(u->attribs, &at_hate); ta = a_find(u->attribs, &at_hate);
if (ta && !monster_is_waiting(u)) { if (ta && !monster_is_waiting(u)) {
unit *tu = (unit *)ta->data.v; 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); order * ord = monster_attack(u, tu);
if (ord) { if (ord) {
unit_addorder(u, ord); unit_addorder(u, ord);
@ -792,7 +814,7 @@ void plan_monsters(faction * f)
else else
a_remove(&u->attribs, ta); a_remove(&u->attribs, ta);
} }
else if (!r->land || guarding) { else if (monster_can_attack(u)) {
if (chance(attack_chance)) { if (chance(attack_chance)) {
int m = monster_attacks(u, false); int m = monster_attacks(u, false);
if (m >= 0) { 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) static void eaten_by_monster(unit * u)
{ {
/* adjustment for smaller worlds */ /* adjustment for smaller worlds */

View File

@ -18,7 +18,6 @@ extern "C" {
void monsters_desert(struct faction *monsters); void monsters_desert(struct faction *monsters);
void monster_kills_peasants(struct unit *u); void monster_kills_peasants(struct unit *u);
bool monster_is_waiting(const struct unit *u);
void make_zombie(struct unit * u); void make_zombie(struct unit * u);
void spawn_undead(void); void spawn_undead(void);

View File

@ -97,6 +97,7 @@ static void test_monsters_attack_ocean(CuTest * tc)
{ {
region *r; region *r;
unit *u, *m; unit *u, *m;
race *rc;
test_setup(); test_setup();
create_monsters(&u, &m); create_monsters(&u, &m);
@ -107,10 +108,16 @@ static void test_monsters_attack_ocean(CuTest * tc)
assert(!m->region->land); assert(!m->region->land);
config_set("rules.monsters.attack_chance", "1"); config_set("rules.monsters.attack_chance", "1");
rc = rc_find(m->_race->_name);
freset(rc, RCF_SWIM);
plan_monsters(m->faction); 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)); CuAssertPtrNotNull(tc, find_order("attack 2", m));
test_teardown(); test_teardown();
} }
@ -145,7 +152,7 @@ static void test_seaserpent_piracy(CuTest * tc)
u_setrace(m, rc = test_create_race("seaserpent")); u_setrace(m, rc = test_create_race("seaserpent"));
assert(!m->region->land); assert(!m->region->land);
fset(m, UFL_MOVED); fset(m, UFL_MOVED);
fset(rc, RCF_ATTACK_MOVED); fset(rc, RCF_ATTACK_MOVED|RCF_SWIM);
config_set("rules.monsters.attack_chance", "1"); config_set("rules.monsters.attack_chance", "1");

View File

@ -1718,23 +1718,23 @@ nr_ship(struct stream *out, const region *r, const ship * sh, const faction * f,
char buffer[1024]; char buffer[1024];
char ch; char ch;
sbstring sbs; sbstring sbs;
const char *stname;
sbs_init(&sbs, buffer, sizeof(buffer)); sbs_init(&sbs, buffer, sizeof(buffer));
newline(out); newline(out);
stname = locale_plural(f->locale, sh->type->_name, sh->number, true);
if (captain && captain->faction == f) { if (captain && captain->faction == f) {
int n = 0, p = 0; int n = 0, p = 0;
const char *stname;
getshipweight(sh, &n, &p); getshipweight(sh, &n, &p);
n = (n + 99) / 100; /* 1 Silber = 1 GE */ 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, sbs_printf(&sbs, "%s, %d %s, (%d/%d)", shipname(sh), sh->number,
stname, n, ship_capacity(sh) / 100); stname, n, ship_capacity(sh) / 100);
} }
else { 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)) { if (!ship_finished(sh)) {

View File

@ -2358,9 +2358,8 @@ static void patzer_peasantmob(const castorder * co)
rsetpeasants(r, rpeasants(r) - n); rsetpeasants(r, rpeasants(r) - n);
assert(rpeasants(r) >= 0); assert(rpeasants(r) >= 0);
u = u = create_unit(r, f, n, get_race(RC_PEASANT), 0,
create_unit(r, f, n, get_race(RC_PEASANT), 0, LOC(f->locale, "angry_mob"), LOC(f->locale, "angry_mob"), NULL);
NULL);
fset(u, UFL_ISNEW); fset(u, UFL_ISNEW);
unit_addorder(u, create_order(K_GUARD, lang, NULL)); unit_addorder(u, create_order(K_GUARD, lang, NULL));
set_order(&u->thisorder, default_order(lang)); set_order(&u->thisorder, default_order(lang));

View File

@ -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) bool isparam(const char *s, const struct locale * lang, param_t param)
{ {
assert(s);
assert(param != P_GEBAEUDE); assert(param != P_GEBAEUDE);
assert(param != P_BUILDING); assert(param != P_BUILDING);
if (s[0] > '@') { if (s && s[0] > '@') {
param_t p = findparam(s, lang); param_t p = findparam(s, lang);
return p == param; return p == param;
} }