From 52ee682a4891660fdfceb2c4ed6ec2afab1685b6 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 2 Nov 2019 19:09:15 +0100 Subject: [PATCH 1/9] =?UTF-8?q?Bug=202617:=20Berechnung=20von=20=C3=9Cberl?= =?UTF-8?q?adung=20berechnet=20Flotten=20korrekt.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/move.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/move.c b/src/move.c index 0fc6f6411..e444ead56 100644 --- a/src/move.c +++ b/src/move.c @@ -501,7 +501,7 @@ static double overload(const region * r, ship * sh) double ovl; getshipweight(sh, &n, &p); - ovl = n / (double)sh->type->cargo; + ovl = n / (double)(sh->type->cargo * sh->number); if (mcabins) { ovl = fmax(ovl, p / (double)mcabins); } @@ -746,7 +746,7 @@ double damage_overload(double overload) } /* message to all factions in ship, start from firstu, end before lastu (may be NULL) */ -static void msg_to_ship_inmates(ship *sh, unit **firstu, unit **lastu, message *msg) { +static void msg_to_passengers(ship *sh, unit **firstu, unit **lastu, message *msg) { unit *u, *shipfirst = NULL; for (u = *firstu; u != *lastu; u = u->next) { if (u->ship == sh) { @@ -836,19 +836,19 @@ static void drifting_ships(region * r) if (rnext && firstu) { message *msg = msg_message("ship_drift", "ship dir", sh, dir); - msg_to_ship_inmates(sh, &firstu, &lastu, msg); + msg_to_passengers(sh, &firstu, &lastu, msg); } fset(sh, SF_DRIFTED); if (ovl >= overload_start()) { damage_ship(sh, damage_overload(ovl)); - msg_to_ship_inmates(sh, &firstu, &lastu, msg_message("massive_overload", "ship", sh)); + msg_to_passengers(sh, &firstu, &lastu, msg_message("massive_overload", "ship", sh)); } else { damage_ship(sh, damage_drift); } if (sh->damage >= sh->size * DAMAGE_SCALE) { - msg_to_ship_inmates(sh, &firstu, &lastu, msg_message("shipsink", "ship", sh)); + msg_to_passengers(sh, &firstu, &lastu, msg_message("shipsink", "ship", sh)); sink_ship(sh); remove_ship(shp, sh); } From fd1b981983f58b86838921fb2dcdfba655e69d33 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 2 Nov 2019 21:32:11 +0100 Subject: [PATCH 2/9] simplify sail/travel, remove route from arguments. --- src/move.c | 44 +++++++++++++++++--------------------------- 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/src/move.c b/src/move.c index e444ead56..d33987d54 100644 --- a/src/move.c +++ b/src/move.c @@ -1683,12 +1683,13 @@ bool can_takeoff(const ship * sh, const region * from, const region * to) return true; } -static void sail(unit * u, order * ord, region_list ** routep, bool drifting) +static void sail(unit * u, order * ord, bool drifting) { + region_list *route = NULL; region *starting_point = u->region; region *current_point, *last_point; int k, step = 0; - region_list **iroute = routep; + region_list **iroute = &route; ship *sh = u->ship; faction *f = u->faction; region *next_point = NULL; @@ -1698,10 +1699,6 @@ static void sail(unit * u, order * ord, region_list ** routep, bool drifting) int lighthouse_div = config_get_int("rules.storm.lighthouse.divisor", 0); const char *token = getstrtoken(); - if (routep) { - *routep = NULL; - } - error = movewhere(u, token, starting_point, &next_point); if (error) { message *msg = movement_error(u, token, ord, error); @@ -1940,7 +1937,7 @@ static void sail(unit * u, order * ord, region_list ** routep, bool drifting) if (fval(u, UFL_FOLLOWING)) caught_target(current_point, u); - move_ship(sh, starting_point, current_point, routep ? *routep : NULL); + move_ship(sh, starting_point, current_point, route); /* Hafengebuehren ? */ @@ -1982,6 +1979,7 @@ static void sail(unit * u, order * ord, region_list ** routep, bool drifting) } } } + free_regionlist(route); } /* Segeln, Wandern, Reiten @@ -2088,14 +2086,12 @@ static const region_list *travel_i(unit * u, const region_list * route_begin, /** traveling without ships * walking, flying or riding units use this function */ -static void travel(unit * u, order *ord, region_list ** routep) +static void travel(unit * u, order *ord) { - region *r = u->region; - region_list *route_begin; - follower *followers = NULL; + region_list *route = NULL; - assert(routep); - *routep = NULL; + region *r = u->region; + follower *followers = NULL; /* a few pre-checks that need not be done for each step: */ if (!fval(r->terrain, SEA_REGION)) { @@ -2131,12 +2127,10 @@ static void travel(unit * u, order *ord, region_list ** routep) return; } - make_route(u, ord, routep); - route_begin = *routep; - - if (route_begin) { + make_route(u, ord, &route); + if (route) { /* und ab die post: */ - travel_i(u, route_begin, NULL, ord, TRAVEL_NORMAL, &followers); + travel_i(u, route, NULL, ord, TRAVEL_NORMAL, &followers); /* followers */ while (followers != NULL) { @@ -2157,34 +2151,30 @@ static void travel(unit * u, order *ord, region_list ** routep) follow_order = create_order(K_FOLLOW, lang, "%s %i", s, ut->no); - route_end = reroute(uf, route_begin, route_end); - travel_i(uf, route_begin, route_end, follow_order, TRAVEL_FOLLOWING, + route_end = reroute(uf, route, route_end); + travel_i(uf, route, route_end, follow_order, TRAVEL_FOLLOWING, &followers); caught_target(uf->region, uf); free_order(follow_order); } } + free_regionlist(route); } } void move_cmd(unit * u, order * ord) { - region_list *route = NULL; - assert(u->number); if (u->ship && u == ship_owner(u->ship)) { bool drifting = (getkeyword(ord) == K_MOVE); - sail(u, ord, &route, drifting); + sail(u, ord, drifting); } else { - travel(u, ord, &route); + travel(u, ord); } fset(u, UFL_LONGACTION | UFL_NOTMOVING); set_order(&u->thisorder, NULL); - - if (route != NULL) - free_regionlist(route); } static void age_traveldir(region * r) From 7850e84cea5f48983a3e5ef3cf1fed8186a4e077 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 2 Nov 2019 21:37:33 +0100 Subject: [PATCH 3/9] let's try increasing MAX_UNITSIZE to 128K --- src/kernel/unit.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/unit.h b/src/kernel/unit.h index 863dccd13..c77cfdb7a 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -54,7 +54,7 @@ extern "C" { /* Flags, die gespeichert werden sollen: */ #define UFL_SAVEMASK (UFL_DEFENDER|UFL_MOVED|UFL_NOAID|UFL_ANON_FACTION|UFL_LOCKED|UFL_HUNGER|UFL_TAKEALL|UFL_GUARD|UFL_STEALTH|UFL_GROUP|UFL_HERO) -#define UNIT_MAXSIZE 50000 +#define UNIT_MAXSIZE 128 * 1024 extern int maxheroes(const struct faction *f); extern int countheroes(const struct faction *f); From 75000f266306d7f940c94f9f3381f12d316c290d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 17 Nov 2019 19:55:41 +0100 Subject: [PATCH 4/9] reduce struct person by 12 bytes on a 32-bit arch. --- src/battle.c | 18 ++++-------------- src/battle.h | 16 ++++++++-------- src/exparse.c | 2 +- src/kernel/item.c | 2 +- src/kernel/item.h | 4 ++-- src/spells/combatspells.c | 2 +- 6 files changed, 17 insertions(+), 27 deletions(-) diff --git a/src/battle.c b/src/battle.c index 835917e62..a0e03f1f9 100644 --- a/src/battle.c +++ b/src/battle.c @@ -104,8 +104,6 @@ const troop no_troop = { 0, 0 }; #define LOOT_KEEPLOOT (1<<4) #define DAMAGE_CRITICAL (1<<0) -#define DAMAGE_MELEE_BONUS (1<<1) -#define DAMAGE_MISSILE_BONUS (1<<2) /* deprecated */ #define DAMAGE_SKILL_BONUS (1<<4) static int max_turns; @@ -117,7 +115,7 @@ static int flee_chance_skill_bonus; static int skill_formula; static int rule_cavalry_skill; static int rule_population_damage; -static int rule_hero_speed; +static unsigned char rule_hero_speed; static bool rule_anon_battle; static bool rule_igjarjuk_curse; static int rule_goblin_bonus; @@ -139,7 +137,7 @@ static void init_rules(void) rule_nat_armor = config_get_int("rules.combat.nat_armor", 0); rule_tactics_formula = config_get_int("rules.tactics.formula", 0); rule_goblin_bonus = config_get_int("rules.combat.goblinbonus", 10); - rule_hero_speed = config_get_int("rules.combat.herospeed", 10); + rule_hero_speed = (unsigned char)config_get_int("rules.combat.herospeed", 10); rule_population_damage = config_get_int("rules.combat.populationdamage", 20); rule_anon_battle = config_get_int("rules.stealth.anon_battle", 1) != 0; rule_igjarjuk_curse = config_get_int("rules.combat.igjarjuk_curse", 0) != 0; @@ -157,12 +155,6 @@ static void init_rules(void) if (config_get_int("rules.combat.critical", 1)) { rule_damage |= DAMAGE_CRITICAL; } - if (config_get_int("rules.combat.melee_bonus", 1)) { - rule_damage |= DAMAGE_MELEE_BONUS; - } - if (config_get_int("rules.combat.missile_bonus", 1)) { /* deprecated */ - rule_damage |= DAMAGE_MISSILE_BONUS; - } if (config_get_int("rules.combat.skill_bonus", 1)) { rule_damage |= DAMAGE_SKILL_BONUS; } @@ -1304,9 +1296,7 @@ terminate(troop dt, troop at, int type, const char *damage_formula, bool missile if (awtype == NULL || !fval(awtype, WTF_MISSILE)) { /* melee bonus */ - if (rule_damage & DAMAGE_MELEE_BONUS) { - damage += af->person[at.index].damage; - } + damage += af->person[at.index].damage; } /* Skilldifferenzbonus */ @@ -3158,7 +3148,7 @@ fighter *make_fighter(battle * b, unit * u, side * s1, bool attack) fig->person[i].hp++; if (i < speeded) - fig->person[i].speed = speed; + fig->person[i].speed = (unsigned char) speed; else fig->person[i].speed = 1; diff --git a/src/battle.h b/src/battle.h index 0ce76bfea..83bcaf09a 100644 --- a/src/battle.h +++ b/src/battle.h @@ -81,9 +81,9 @@ extern "C" { int nsides; struct selist *meffects; int max_tactics; - int turn; + unsigned char turn; + signed char keeploot; /* keep (50 + keeploot) percent of items as loot */ bool has_tactics_turn; - int keeploot; bool reelarrow; int alive; struct { @@ -153,13 +153,13 @@ extern "C" { int catmsg; /* Merkt sich, ob Katapultmessage schon generiert. */ struct person { int hp; /* Trefferpunkte der Personen */ - int attack; - int defense; - int damage; int flags; - int speed; - int reload; - int last_action; + int attack; /* weapon skill bonus for attacker */ + int defense; /* weapon skill bonus for defender */ + char damage; /* bonus damage for melee attacks (e.g. troll belt) */ + unsigned char speed; + unsigned char reload; + unsigned char last_action; struct weapon *missile; /* missile weapon */ struct weapon *melee; /* melee weapon */ } *person; diff --git a/src/exparse.c b/src/exparse.c index 4160b32ba..a9c21b025 100644 --- a/src/exparse.c +++ b/src/exparse.c @@ -280,7 +280,7 @@ static void handle_weapon(parseinfo *pi, const XML_Char *el, const XML_Char **at wtype->defmod = xml_int(attr[i + 1]); } else if (xml_strequal(attr[i], "reload")) { - wtype->reload = xml_int(attr[i + 1]); + wtype->reload = (unsigned char) xml_int(attr[i + 1]); } else if (xml_strequal(attr[i], "skill")) { wtype->skill = findskill(attr[i + 1]); diff --git a/src/kernel/item.c b/src/kernel/item.c index 1533d65bc..0d2764412 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -260,7 +260,7 @@ luxury_type *new_luxurytype(item_type * itype, int price) weapon_type *new_weapontype(item_type * itype, int wflags, variant magres, const char *damage[], int offmod, int defmod, - int reload, skill_t sk) + unsigned char reload, skill_t sk) { weapon_type *wtype; diff --git a/src/kernel/item.h b/src/kernel/item.h index 0b90b7b1e..46b27505f 100644 --- a/src/kernel/item.h +++ b/src/kernel/item.h @@ -169,7 +169,7 @@ extern "C" { int offmod; int defmod; variant magres; - int reload; /* time to reload this weapon */ + unsigned char reload; /* time to reload this weapon */ weapon_mod *modifiers; /* --- functions --- */ bool(*attack) (const struct troop *, const struct weapon_type *, @@ -208,7 +208,7 @@ extern "C" { item_type *it_get_or_create(resource_type *rtype); luxury_type *new_luxurytype(item_type * itype, int price); weapon_type *new_weapontype(item_type * itype, int wflags, - variant magres, const char *damage[], int offmod, int defmod, int reload, + variant magres, const char *damage[], int offmod, int defmod, unsigned char reload, skill_t sk); void free_wtype(struct weapon_type *wtype); armor_type *new_armortype(item_type * itype, double penalty, diff --git a/src/spells/combatspells.c b/src/spells/combatspells.c index f4b8b6954..dea37345b 100644 --- a/src/spells/combatspells.c +++ b/src/spells/combatspells.c @@ -1378,7 +1378,7 @@ int sp_keeploot(struct castorder * co) message_all(b, m); msg_release(m); - b->keeploot = (int)fmax(25, b->keeploot + 5 * power); + b->keeploot = (signed char) fmax(25, b->keeploot + 5 * power); return level; } From beffa1d5362002838b97c82c23db1aa5b5720445 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 18 Nov 2019 18:48:28 +0100 Subject: [PATCH 5/9] CID 205842: con is never NULL. --- src/kernel/build.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/kernel/build.c b/src/kernel/build.c index d9e1cc8bc..7e97819dc 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -511,14 +511,13 @@ int build_skill(unit *u, int basesk, int skill_mod) { */ static int build_limited(unit * u, const construction * con, int completed, int number, int want, int basesk, int *skill_total) { int skills = *skill_total; - int made = 0, maxsize = con->maxsize * number; + int made = 0, maxsize; + assert(con); if (want <= 0) { return 0; } - if (con == NULL) { - return ENOMATERIALS; - } + maxsize = con->maxsize * number; if (completed == maxsize) { return ECOMPLETE; } From 1bff7801ff579d1daa55e1241fd59c8f166b244e Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 18 Nov 2019 19:33:37 +0100 Subject: [PATCH 6/9] transfer_faction respects magic schools. --- clibs | 2 +- src/laws.c | 8 ++++++++ src/laws.test.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/clibs b/clibs index f8969f44d..abe774f70 160000 --- a/clibs +++ b/clibs @@ -1 +1 @@ -Subproject commit f8969f44de1ec413cfee82b23c9f4b3c32d49b56 +Subproject commit abe774f70265de14ea7f5e530518ca130562a9c9 diff --git a/src/laws.c b/src/laws.c index eb483aae7..42230e338 100644 --- a/src/laws.c +++ b/src/laws.c @@ -976,9 +976,17 @@ void transfer_faction(faction *fsrc, faction *fdst) { for (i = 0; i != u->skill_size; ++i) { const skill *sv = u->skills + i; skill_t sk = (skill_t)sv->id; + struct sc_mage *mage; + if (skill_count[sk] + u->number > skill_limit[sk]) { break; } + mage = get_mage(u); + if (mage) { + if (fdst->magiegebiet != mage_get_type(mage)) { + break; + } + } } if (i != u->skill_size) { u = u->nextF; diff --git a/src/laws.test.c b/src/laws.test.c index 5dff45a92..ea273d017 100644 --- a/src/laws.test.c +++ b/src/laws.test.c @@ -2083,6 +2083,56 @@ static void test_quit_transfer_limited(CuTest *tc) { test_teardown(); } +/** + * Gifting units with same magic schools. + */ +static void test_quit_transfer_mages(CuTest *tc) { + faction *f1, *f2; + unit *u1, *u2; + region *r; + + test_setup(); + config_set_int("rules.maxskills.magic", 2); + r = test_create_plain(0, 0); + f1 = test_create_faction(NULL); + faction_setpassword(f1, "password"); + u1 = test_create_unit(f1, r); + f2 = test_create_faction(NULL); + u2 = test_create_unit(f2, r); + contact_unit(u2, u1); + u1->thisorder = create_order(K_QUIT, f1->locale, "password %s %s", + LOC(f1->locale, parameters[P_FACTION]), itoa36(f2->no)); + + f1->magiegebiet = M_GWYRRD; + set_level(u1, SK_MAGIC, 1); + create_mage(u1, M_GWYRRD); + + f2->magiegebiet = M_CERDDOR; + set_level(u2, SK_MAGIC, 1); + create_mage(u2, M_CERDDOR); + + quit_cmd(u1, u1->thisorder); + CuAssertPtrEquals(tc, f1, u1->faction); + CuAssertIntEquals(tc, FFL_QUIT, f1->flags & FFL_QUIT); + f1->flags -= FFL_QUIT; + + unit_set_magic(u1, M_CERDDOR); + scale_number(u1, 2); + f1->magiegebiet = M_CERDDOR; + quit_cmd(u1, u1->thisorder); + CuAssertPtrEquals(tc, f1, u1->faction); + CuAssertIntEquals(tc, FFL_QUIT, f1->flags & FFL_QUIT); + f1->flags -= FFL_QUIT; + + unit_set_magic(u1, M_CERDDOR); + scale_number(u1, 1); + f1->magiegebiet = M_CERDDOR; + quit_cmd(u1, u1->thisorder); + CuAssertPtrEquals(tc, f2, u1->faction); + + test_teardown(); +} + /** * Only units of the same race can be gifted to another faction. */ @@ -2248,6 +2298,7 @@ CuSuite *get_laws_suite(void) SUITE_ADD_TEST(suite, test_quit_transfer); SUITE_ADD_TEST(suite, test_quit_transfer_limited); SUITE_ADD_TEST(suite, test_quit_transfer_migrants); + SUITE_ADD_TEST(suite, test_quit_transfer_mages); SUITE_ADD_TEST(suite, test_quit_transfer_hero); SUITE_ADD_TEST(suite, test_transfer_faction); #endif From cd165d94ec083a2a7f31a2f34545e2242a8e264c Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 18 Nov 2019 19:44:24 +0100 Subject: [PATCH 7/9] =?UTF-8?q?Magier=20d=C3=BCrfen=20bei=20STIRB=20nicht?= =?UTF-8?q?=20=C3=BCbergeben=20werden.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/laws.c | 10 +--------- src/laws.test.c | 21 +++------------------ 2 files changed, 4 insertions(+), 27 deletions(-) diff --git a/src/laws.c b/src/laws.c index 42230e338..ddda26f27 100644 --- a/src/laws.c +++ b/src/laws.c @@ -969,24 +969,16 @@ void transfer_faction(faction *fsrc, faction *fdst) { if (u_race(u) == fdst->race) { u->flags &= ~UFL_HERO; - if (give_unit_allowed(u) == 0) { + if (give_unit_allowed(u) == 0 && !get_mage(u)) { if (u->skills) { int i; - for (i = 0; i != u->skill_size; ++i) { const skill *sv = u->skills + i; skill_t sk = (skill_t)sv->id; - struct sc_mage *mage; if (skill_count[sk] + u->number > skill_limit[sk]) { break; } - mage = get_mage(u); - if (mage) { - if (fdst->magiegebiet != mage_get_type(mage)) { - break; - } - } } if (i != u->skill_size) { u = u->nextF; diff --git a/src/laws.test.c b/src/laws.test.c index ea273d017..f6e1ef585 100644 --- a/src/laws.test.c +++ b/src/laws.test.c @@ -2084,7 +2084,7 @@ static void test_quit_transfer_limited(CuTest *tc) { } /** - * Gifting units with same magic schools. + * Mages cannot be transfered. At all. */ static void test_quit_transfer_mages(CuTest *tc) { faction *f1, *f2; @@ -2107,28 +2107,13 @@ static void test_quit_transfer_mages(CuTest *tc) { set_level(u1, SK_MAGIC, 1); create_mage(u1, M_GWYRRD); - f2->magiegebiet = M_CERDDOR; + f2->magiegebiet = M_GWYRRD; set_level(u2, SK_MAGIC, 1); - create_mage(u2, M_CERDDOR); + create_mage(u2, M_GWYRRD); quit_cmd(u1, u1->thisorder); CuAssertPtrEquals(tc, f1, u1->faction); CuAssertIntEquals(tc, FFL_QUIT, f1->flags & FFL_QUIT); - f1->flags -= FFL_QUIT; - - unit_set_magic(u1, M_CERDDOR); - scale_number(u1, 2); - f1->magiegebiet = M_CERDDOR; - quit_cmd(u1, u1->thisorder); - CuAssertPtrEquals(tc, f1, u1->faction); - CuAssertIntEquals(tc, FFL_QUIT, f1->flags & FFL_QUIT); - f1->flags -= FFL_QUIT; - - unit_set_magic(u1, M_CERDDOR); - scale_number(u1, 1); - f1->magiegebiet = M_CERDDOR; - quit_cmd(u1, u1->thisorder); - CuAssertPtrEquals(tc, f2, u1->faction); test_teardown(); } From 1a8b94da59bf28deef71f876414bd6a05df48108 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 24 Nov 2019 16:39:21 +0100 Subject: [PATCH 8/9] =?UTF-8?q?STIRB=20PARTEI=20l=C3=B6scht=20die=20Befehl?= =?UTF-8?q?e=20nicht.=20Reparatur=20des=20Tests=20f=C3=BCr=20VERGESSE=20MA?= =?UTF-8?q?GIE=20(Vertraute)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/tests/economy.lua | 22 +++++++++++++++++++--- src/chaos.c | 1 + src/economy.c | 1 + src/give.c | 1 + src/kernel/unit.c | 9 ++++++--- src/kernel/unit.h | 1 + src/laws.c | 4 ++++ src/monsters.c | 2 ++ src/spells.c | 4 ++-- src/triggers/changefaction.c | 4 +++- 10 files changed, 40 insertions(+), 9 deletions(-) diff --git a/scripts/tests/economy.lua b/scripts/tests/economy.lua index 9c72e7e70..0c140e418 100644 --- a/scripts/tests/economy.lua +++ b/scripts/tests/economy.lua @@ -28,8 +28,6 @@ function test_work() end function test_bug_2361_forget_magic() - -- https://bugs.eressea.de/view.php?id=2361 - -- familiars cannot forget magic local r = region.create(0, 0, "plain") local f = faction.create("human") local u = unit.create(f, r, 1) @@ -38,12 +36,30 @@ function test_bug_2361_forget_magic() u:add_order("VERGESSE Magie") u:set_skill('magic', 5) uf.race = 'unicorn' + u.familiar = uf + process_orders() + assert_equal(0, u:get_skill('magic')) + assert_nil(u.familiar) + -- without a mage, familiars become ghosts: + assert_equal('ghost', uf.race_name) + assert_equal(0, uf:get_skill('magic')) +end + +function test_bug_2361_familiar_cannot_forget_magic_() + -- https://bugs.eressea.de/view.php?id=2361 + local r = region.create(0, 0, "plain") + local f = faction.create("human") + local u = unit.create(f, r, 1) + local uf = unit.create(f, r, 1) + u:clear_orders() + u:set_skill('magic', 5) + uf.race = 'unicorn' uf:clear_orders() uf:add_order("VERGESSE Magie") uf:set_skill('magic', 5) u.familiar = uf process_orders() - assert_equal(0, u:get_skill('magic')) + -- familiars cannot forget magic: assert_equal(5, uf:get_skill('magic')) end diff --git a/src/chaos.c b/src/chaos.c index ef1dffca6..2639592f0 100644 --- a/src/chaos.c +++ b/src/chaos.c @@ -86,6 +86,7 @@ static void chaos(region * r) if (u && playerrace(u_race(u))) { ADDMSG(&u->faction->msgs, msg_message("chaos_disease", "unit", u)); u_setfaction(u, get_monsters()); + u_freeorders(u); u_setrace(u, get_race(RC_GHOUL)); } } diff --git a/src/economy.c b/src/economy.c index 7cd28f6b9..35e08ade6 100644 --- a/src/economy.c +++ b/src/economy.c @@ -292,6 +292,7 @@ static int forget_cmd(unit * u, order * ord) if (ufam) { a_removeall(&ufam->attribs, NULL); u_setfaction(ufam, get_monsters()); + u_freeorders(ufam); unit_convert_race(ufam, NULL, "ghost"); } a_removeall(&u->attribs, &at_mage); diff --git a/src/give.c b/src/give.c index 47f472ec1..ac792da9a 100644 --- a/src/give.c +++ b/src/give.c @@ -709,6 +709,7 @@ void give_unit(unit * u, unit * u2, order * ord) } add_give_person(u, u2, u->number, ord, 0); u_setfaction(u, u2->faction); + u_freeorders(u); u2->faction->newbies += u->number; } diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 06463820c..e9ec8e657 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -886,6 +886,12 @@ struct building *inside_building(const struct unit *u) return NULL; } +void u_freeorders(unit *u) +{ + free_orders(&u->orders); + set_order(&u->thisorder, NULL); +} + void u_setfaction(unit * u, faction * f) { if (u->faction == f) @@ -896,9 +902,6 @@ void u_setfaction(unit * u, faction * f) u->faction->num_people -= u->number; } set_group(u, NULL); - free_orders(&u->orders); - set_order(&u->thisorder, NULL); - if (u->nextF) { u->nextF->prevF = u->prevF; } diff --git a/src/kernel/unit.h b/src/kernel/unit.h index c77cfdb7a..7fc6fa730 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -179,6 +179,7 @@ extern "C" { /* cleanup code for this module */ void free_units(void); void u_setfaction(struct unit *u, struct faction *f); + void u_freeorders(struct unit *u); void set_number(struct unit *u, int count); int invisible(const struct unit *target, const struct unit *viewer); diff --git a/src/laws.c b/src/laws.c index b1ca5e300..285ee3f1c 100644 --- a/src/laws.c +++ b/src/laws.c @@ -3764,6 +3764,10 @@ void process(void) } if (ord) { porder->data.per_order.process(u, ord); + if (!u->orders) { + /* GIVE UNIT or QUIT delete all orders of the unit, stop */ + break; + } } } if (!ord || *ordp == ord) diff --git a/src/monsters.c b/src/monsters.c index 7cdebfd6c..6f20a8c8b 100644 --- a/src/monsters.c +++ b/src/monsters.c @@ -174,6 +174,7 @@ void monsters_desert(struct faction *monsters) ADDMSG(&u->faction->msgs, msg_message("desertion", "unit region", u, r)); u_setfaction(u, monsters); + u_freeorders(u); } } } @@ -1157,6 +1158,7 @@ void monster_kills_peasants(unit * u) void make_zombie(unit * u) { u_setfaction(u, get_monsters()); + u_freeorders(u); scale_number(u, 1); u->hp = unit_max_hp(u) * u->number; u_setrace(u, get_race(RC_ZOMBIE)); diff --git a/src/spells.c b/src/spells.c index 200e87f62..6cff4bb9b 100644 --- a/src/spells.c +++ b/src/spells.c @@ -3553,7 +3553,7 @@ static int sp_charmingsong(castorder * co) /* setze Partei um und loesche langen Befehl aus Sicherheitsgruenden */ u_setfaction(target, mage->faction); - set_order(&target->thisorder, NULL); + u_freeorders(target); /* setze Parteitarnung, damit nicht sofort klar ist, wer dahinter * steckt */ @@ -3796,7 +3796,7 @@ static int sp_migranten(castorder * co) return 0; } u_setfaction(target, mage->faction); - set_order(&target->thisorder, NULL); + u_freeorders(target); /* Erfolg melden */ ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, "sp_migranten", diff --git a/src/triggers/changefaction.c b/src/triggers/changefaction.c index 36e40ed46..85403083b 100644 --- a/src/triggers/changefaction.c +++ b/src/triggers/changefaction.c @@ -48,7 +48,9 @@ static int changefaction_handle(trigger * t, void *data) */ changefaction_data *td = (changefaction_data *)t->data.v; if (td->unit && td->faction) { - u_setfaction(td->unit, td->faction); + unit * u = td->unit; + u_setfaction(u, td->faction); + u_freeorders(u); } else { log_error("could not perform changefaction::handle()\n"); From 633866c814f5a437cd34c76487967f284ac9f975 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 30 Nov 2019 16:29:23 +0100 Subject: [PATCH 9/9] =?UTF-8?q?STIRB=20PARTEI:=20Versuche,=20Helden=20zu?= =?UTF-8?q?=20=C3=BCbernehmen.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/laws.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/laws.c b/src/laws.c index 285ee3f1c..10975c6a7 100644 --- a/src/laws.c +++ b/src/laws.c @@ -924,6 +924,7 @@ int leave_cmd(unit * u, struct order *ord) void transfer_faction(faction *fsrc, faction *fdst) { unit *u; skill_t sk; + int hmax, hnow; int skill_count[MAXSKILLS]; int skill_limit[MAXSKILLS]; @@ -945,12 +946,21 @@ void transfer_faction(faction *fsrc, faction *fdst) { } } + hnow = countheroes(fdst); + hmax = maxheroes(fdst); u = fsrc->units; while (u) { unit *unext = u->nextF; if (u_race(u) == fdst->race) { - u->flags &= ~UFL_HERO; + if (u->flags & UFL_HERO) { + if (u->number + hnow > hmax) { + u->flags &= ~UFL_HERO; + } + else { + hnow += u->number; + } + } if (give_unit_allowed(u) == 0 && !get_mage(u)) { if (u->skills) { int i;