From e5b4d925c67cf47c713d8d80d4855176ceef00d0 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 20 May 2021 20:52:44 +0200 Subject: [PATCH 01/12] paused factions: resume when new orders arrive --- src/kernel/faction.h | 7 ++++--- src/orderfile.c | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/kernel/faction.h b/src/kernel/faction.h index 144961cd8..d40ea4a41 100644 --- a/src/kernel/faction.h +++ b/src/kernel/faction.h @@ -27,14 +27,15 @@ extern "C" { #define FFL_PWMSG (1<<2) /* received a "new password" message */ #define FFL_QUIT (1<<3) #define FFL_CURSED (1<<4) /* you're going to have a bad time */ -#define FFL_SELECT (1<<22) /* ehemals f->dh, u->dh, r->dh, etc... */ -#define FFL_MARK (1<<23) /* fuer markierende algorithmen, die das +#define FFL_PAUSED (1<<5) /* faction is parked until it receives orders again */ +#define FFL_SELECT (1<<6) /* ehemals f->dh, u->dh, r->dh, etc... */ +#define FFL_MARK (1<<7) /* fuer markierende algorithmen, die das * hinterher auch wieder loeschen muessen! * (FFL_SELECT muss man vorher initialisieren, * FL_MARK hinterher loeschen) */ #define FFL_NOIDLEOUT (1<<24) /* Partei stirbt nicht an NMRs */ #define FFL_NPC (1<<25) /* eine Partei mit Monstern */ -#define FFL_SAVEMASK (FFL_NPC|FFL_NOIDLEOUT|FFL_CURSED) +#define FFL_SAVEMASK (FFL_NPC|FFL_NOIDLEOUT|FFL_CURSED|FFL_PAUSED) typedef struct origin { struct origin *next; diff --git a/src/orderfile.c b/src/orderfile.c index bba2b177b..f03c9a2b1 100644 --- a/src/orderfile.c +++ b/src/orderfile.c @@ -66,6 +66,7 @@ static void handle_faction(void *userData, int no, const char *password) { if (checkpasswd(f, password)) { state->f = f; f->lastorders = turn; + freset(f, FFL_PAUSED); } else { log_debug("invalid password for faction %s", itoa36(no)); From bed6cdff585f8817481cbac15737968c75ae4e3d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 20 May 2021 21:09:45 +0200 Subject: [PATCH 02/12] paused units have no weekly maintenance cost. --- src/kernel/faction.h | 3 ++- src/kernel/unit.c | 6 +++++- src/upkeep.c | 5 +++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/kernel/faction.h b/src/kernel/faction.h index d40ea4a41..acf1e5776 100644 --- a/src/kernel/faction.h +++ b/src/kernel/faction.h @@ -163,7 +163,8 @@ extern "C" { struct faction *get_or_create_monsters(void); void save_special_items(struct unit *u); -#define is_monsters(f) (f->no==MONSTER_ID) +#define is_monsters(f) ((f)->no==MONSTER_ID) +#define is_paused(f) ((f)->flags & FFL_PAUSED) #ifdef __cplusplus } diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 3bdd64862..64ac33396 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -1789,8 +1789,12 @@ bool has_horses(const unit * u) #define MAINTENANCE 10 int maintenance_cost(const struct unit *u) { - if (u == NULL) + if (u == NULL) { return MAINTENANCE; + } + if (is_paused(u->faction)) { + return 0; + } return u_race(u)->maintenance * u->number; } diff --git a/src/upkeep.c b/src/upkeep.c index d5b5bf8d9..fbd12d7d9 100644 --- a/src/upkeep.c +++ b/src/upkeep.c @@ -23,13 +23,14 @@ #include -int lifestyle(const unit * u) +int lifestyle(const unit *u) { int need; plane *pl; - if (is_monsters(u->faction)) + if (is_monsters(u->faction)) { return 0; + } need = maintenance_cost(u); From 0fcc1b8d29ceff97e19dbd033011baf703b12be3 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 20 May 2021 22:04:50 +0200 Subject: [PATCH 03/12] fix compilation, add tests for upkeep --- src/kernel/unit.test.c | 19 +++++++++++++++++++ src/orderfile.c | 2 +- src/upkeep.test.c | 21 +++++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/kernel/unit.test.c b/src/kernel/unit.test.c index e77c51ea2..4c1987806 100644 --- a/src/kernel/unit.test.c +++ b/src/kernel/unit.test.c @@ -681,6 +681,24 @@ static void test_get_modifier_cursed(CuTest *tc) { test_teardown(); } +static void test_maintenance_cost(CuTest *tc) { + unit *u; + race *rc; + test_setup(); + CuAssertIntEquals(tc, 10, maintenance_cost(NULL)); + u = test_create_unit(test_create_faction(), test_create_plain(0, 0)); + CuAssertIntEquals(tc, 10, maintenance_cost(u)); + u->number = 4; + CuAssertIntEquals(tc, 40, maintenance_cost(u)); + rc = test_create_race("smurf"); + rc->maintenance = 15; + u_setrace(u, rc); + CuAssertIntEquals(tc, 60, maintenance_cost(u)); + u->faction->flags |= FFL_PAUSED; + CuAssertIntEquals(tc, 0, maintenance_cost(u)); + test_teardown(); +} + static void test_gift_items(CuTest *tc) { unit *u, *u1, *u2; region *r; @@ -770,5 +788,6 @@ CuSuite *get_unit_suite(void) SUITE_ADD_TEST(suite, test_get_modifier); SUITE_ADD_TEST(suite, test_get_modifier_cursed); SUITE_ADD_TEST(suite, test_gift_items); + SUITE_ADD_TEST(suite, test_maintenance_cost); return suite; } diff --git a/src/orderfile.c b/src/orderfile.c index f03c9a2b1..582d1fc56 100644 --- a/src/orderfile.c +++ b/src/orderfile.c @@ -66,7 +66,7 @@ static void handle_faction(void *userData, int no, const char *password) { if (checkpasswd(f, password)) { state->f = f; f->lastorders = turn; - freset(f, FFL_PAUSED); + f->flags &= ~(FFL_PAUSED); } else { log_debug("invalid password for faction %s", itoa36(no)); diff --git a/src/upkeep.test.c b/src/upkeep.test.c index 92cc5f71c..7020f2195 100644 --- a/src/upkeep.test.c +++ b/src/upkeep.test.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -137,6 +138,25 @@ void test_upkeep_from_friend(CuTest * tc) test_teardown(); } +void test_lifestyle(CuTest *tc) +{ + unit *u; + race *rc; + + test_setup(); + u = test_create_unit(test_create_faction(), test_create_plain(0, 0)); + CuAssertIntEquals(tc, 10, lifestyle(u)); + u->number = 2; + CuAssertIntEquals(tc, 20, lifestyle(u)); + rc = test_create_race("smurf"); + rc->maintenance = 15; + u_setrace(u, rc); + CuAssertIntEquals(tc, 30, lifestyle(u)); + u->faction->flags |= FFL_PAUSED; + CuAssertIntEquals(tc, 0, lifestyle(u)); + test_teardown(); +} + void test_upkeep_free(CuTest * tc) { region *r; @@ -168,5 +188,6 @@ CuSuite *get_upkeep_suite(void) SUITE_ADD_TEST(suite, test_upkeep_from_friend); SUITE_ADD_TEST(suite, test_upkeep_hunger_damage); SUITE_ADD_TEST(suite, test_upkeep_free); + SUITE_ADD_TEST(suite, test_lifestyle); return suite; } From 48fd0bd4af5b9eaa2fed160978810cb8a1680a9c Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 21 May 2021 04:14:39 +0200 Subject: [PATCH 04/12] paused factions do not execute orders, do not join battles. lots of change, didn't write any tests for this yet. --- src/automate.c | 3 ++- src/battle.c | 12 ++++++------ src/economy.c | 19 ++++++++++++------- src/kernel/alliance.c | 2 +- src/laws.c | 30 +++++++++++++++++++++--------- src/laws.h | 2 +- src/laws.test.c | 21 ++++++++++++++++----- src/magic.c | 2 +- src/move.c | 7 +++++-- src/randenc.c | 1 + src/recruit.c | 2 ++ src/renumber.c | 9 ++++++--- src/sort.c | 2 +- 13 files changed, 75 insertions(+), 37 deletions(-) diff --git a/src/automate.c b/src/automate.c index 53ac074a7..4ab2e49d7 100644 --- a/src/automate.c +++ b/src/automate.c @@ -39,7 +39,7 @@ int autostudy_init(scholar scholars[], int max_scholars, unit **units, skill_t * if (kwd == K_AUTOSTUDY) { if (f == u->faction) { unext = u->next; - if (long_order_allowed(u)) { + if (long_order_allowed(u, false)) { scholar * st = scholars + nscholars; skill_t sk = getskill(u->faction->locale); if (skill == NOSKILL && sk != NOSKILL) { @@ -198,6 +198,7 @@ void do_autostudy(region *r) assert(batchsize <= MAXSCHOLARS); } for (u = r->units; u; u = u->next) { + if (is_paused(u->faction)) continue; if (!fval(u, UFL_MARK)) { unit *ulist = u; int sum_scholars = 0; diff --git a/src/battle.c b/src/battle.c index 974b2d0f5..e2379c0e7 100644 --- a/src/battle.c +++ b/src/battle.c @@ -3524,6 +3524,8 @@ static void join_allies(battle * b) faction *f = u->faction; fighter *c = NULL; + if (is_paused(u->faction)) continue; + for (s = b->sides; s != s_end; ++s) { side *se; /* Wenn alle attackierten noch FFL_NOAID haben, dann kaempfe nicht mit. */ @@ -3648,8 +3650,7 @@ static bool start_battle(region * r, battle ** bp) bool fighting = false; for (u = r->units; u != NULL; u = u->next) { - if (fval(u, UFL_LONGACTION)) - continue; + if (!long_order_allowed(u, true)) continue; if (u->number > 0) { order *ord; @@ -3683,10 +3684,6 @@ static bool start_battle(region * r, battle ** bp) continue; } - /* ist ein Fluechtling aus einem andern Kampf */ - if (fval(u, UFL_LONGACTION)) - continue; - if (curse_active(get_curse(r->attribs, &ct_peacezone))) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "peace_active", "")); continue; @@ -3922,6 +3919,9 @@ void force_leave(region *r, battle *b) { for (u = r->units; u; u = u->next) { unit *uo = NULL; + + if (is_paused(u->faction)) continue; + if (u->building) { uo = building_owner(u->building); } diff --git a/src/economy.c b/src/economy.c index 6ed5eda1e..40624328b 100644 --- a/src/economy.c +++ b/src/economy.c @@ -392,6 +392,9 @@ void economics(region * r) for (u = r->units; u; u = u->next) { order *ord; + + if (is_paused(u->faction)) continue; + if (u->number > 0) { order* transfer = NULL; for (ord = u->orders; ord; ord = ord->next) { @@ -428,6 +431,8 @@ void destroy(region *r) { for (u = r->units; u; u = u->next) { order *ord = u->thisorder; keyword_t kwd = getkeyword(ord); + + if (is_paused(u->faction)) continue; if (kwd == K_DESTROY) { if (destroy_cmd(u, ord) == 0) { fset(u, UFL_LONGACTION | UFL_NOTMOVING); @@ -2299,7 +2304,7 @@ void auto_work(region * r) long total = 0; for (u = r->units; u; u = u->next) { - if (!(u->flags & UFL_LONGACTION) && !is_monsters(u->faction)) { + if (long_order_allowed(u, false) && !is_monsters(u->faction)) { int work = work_cmd(u, NULL, &nextrequest); if (work) { total += work; @@ -2403,12 +2408,7 @@ void produce(struct region *r) bool trader = false; keyword_t todo; - if (fval(u, UFL_LONGACTION)) - continue; - - if (u_race(u) == rc_insect && r_insectstalled(r) && - !is_cursed(u->attribs, &ct_insectfur)) - continue; + if (!long_order_allowed(u, false)) continue; if (fval(u, UFL_LONGACTION) && u->thisorder == NULL) { /* this message was already given in laws.c:update_long_order @@ -2417,6 +2417,11 @@ void produce(struct region *r) continue; } + if (u_race(u) == rc_insect && r_insectstalled(r) && + !is_cursed(u->attribs, &ct_insectfur)) { + continue; + } + for (ord = u->orders; ord; ord = ord->next) { keyword_t kwd = getkeyword(ord); if (kwd == K_BUY) { diff --git a/src/kernel/alliance.c b/src/kernel/alliance.c index f71df27bd..e840d0265 100644 --- a/src/kernel/alliance.c +++ b/src/kernel/alliance.c @@ -327,7 +327,7 @@ static void execute(keyword_t kwd) unit **up = &r->units; while (*up) { unit *u = *up; - if (u->number) { + if (u->number > 0 && !is_paused(u->faction)) { const struct locale *lang = u->faction->locale; order *ord; for (ord = u->orders; ord; ord = ord->next) { diff --git a/src/laws.c b/src/laws.c index 373bbfb62..8170b1005 100644 --- a/src/laws.c +++ b/src/laws.c @@ -789,7 +789,7 @@ void nmr_warnings(void) faction *f, *fa; #define HELP_NMR (HELP_GUARD|HELP_MONEY) for (f = factions; f; f = f->next) { - if (!fval(f, FFL_NOIDLEOUT) && turn > f->lastorders) { + if (!fval(f, FFL_NOIDLEOUT|FFL_PAUSED) && turn > f->lastorders) { ADDMSG(&f->msgs, msg_message("nmr_warning", "")); if (turn - f->lastorders == NMRTimeout() - 1) { ADDMSG(&f->msgs, msg_message("nmr_warning_final", "")); @@ -1188,6 +1188,9 @@ static void do_contact(region * r) unit * u; for (u = r->units; u; u = u->next) { order *ord; + + if (is_paused(u->faction)) continue; + for (ord = u->orders; ord; ord = ord->next) { keyword_t kwd = getkeyword(ord); if (kwd == K_CONTACT) { @@ -1205,6 +1208,8 @@ void do_enter(struct region *r, bool is_final_attempt) unit *u = *uptr; order **ordp = &u->orders; + if (is_paused(u->faction)) continue; + while (*ordp) { order *ord = *ordp; if (getkeyword(ord) == K_ENTER) { @@ -1349,7 +1354,7 @@ void quit(void) faction **fptr = &factions; while (*fptr) { faction *f = *fptr; - if (f->flags & FFL_QUIT) { + if ((f->flags & FFL_QUIT) && !is_paused(f)) { destroyfaction(fptr); } else { @@ -2939,6 +2944,8 @@ void new_units(void) for (u = r->units; u; u = u->next) { order **ordp = &u->orders; + if (is_paused(u->faction)) continue; + /* this needs to happen very early in the game somewhere. since this is ** pretty much the first function called per turn, and I am lazy, I ** decree that it goes here */ @@ -3588,20 +3595,23 @@ void add_proc_unit(int priority, void(*process) (unit *), const char *name) } } -bool long_order_allowed(const unit *u) +bool long_order_allowed(const unit *u, bool flags_only) { const region *r = u->region; + + if (is_paused(u->faction)) return false; if (fval(u, UFL_LONGACTION)) { /* this message was already given in laws.update_long_order cmistake(u, ord, 52, MSG_PRODUCE); */ return false; } - else if (fval(r->terrain, SEA_REGION) - && u_race(u) != get_race(RC_AQUARIAN) - && !(u_race(u)->flags & RCF_SWIM)) { - /* error message disabled by popular demand */ - return false; + if (fval(r->terrain, SEA_REGION) && !(u_race(u)->flags & RCF_SWIM)) { + if (flags_only) return false; + else if (u_race(u) != get_race(RC_AQUARIAN)) { + /* error message disabled by popular demand */ + return false; + } } return true; } @@ -3650,6 +3660,8 @@ void process(void) for (u = r->units; u; u = u->next) { processor *porder, *punit = pregion; + if (is_paused(u->faction)) continue; + while (punit && punit->priority == prio && punit->type == PR_UNIT) { punit->data.per_unit.process(u); punit = punit->next; @@ -3680,7 +3692,7 @@ void process(void) cmistake(u, ord, 224, MSG_MAGIC); ord = NULL; } - else if (!long_order_allowed(u)) { + else if (!long_order_allowed(u, false)) { ord = NULL; } } diff --git a/src/laws.h b/src/laws.h index 521e28f2b..f165ad6da 100755 --- a/src/laws.h +++ b/src/laws.h @@ -47,7 +47,7 @@ extern "C" { void update_long_order(struct unit *u); void sinkships(struct region * r); void do_enter(struct region *r, bool is_final_attempt); - bool long_order_allowed(const struct unit *u); + bool long_order_allowed(const struct unit *u, bool flags_only); bool password_wellformed(const char *password); int locale_cmd(struct unit *u, struct order *ord); diff --git a/src/laws.test.c b/src/laws.test.c index cf57224d5..3726bbca0 100644 --- a/src/laws.test.c +++ b/src/laws.test.c @@ -1892,9 +1892,12 @@ static void test_long_orders(CuTest *tc) { test_setup(); u = test_create_unit(test_create_faction(), test_create_plain(0, 0)); - CuAssertTrue(tc, long_order_allowed(u)); + CuAssertTrue(tc, long_order_allowed(u, true)); u->flags |= UFL_LONGACTION; - CuAssertTrue(tc, !long_order_allowed(u)); + CuAssertTrue(tc, !long_order_allowed(u, true)); + u->flags -= UFL_LONGACTION; + u->faction->flags |= FFL_PAUSED; + CuAssertTrue(tc, !long_order_allowed(u, true)); test_teardown(); } @@ -1905,13 +1908,21 @@ static void test_long_order_on_ocean(CuTest *tc) { test_setup(); rc = test_create_race("pikachu"); u = test_create_unit(test_create_faction_ex(rc, NULL), test_create_ocean(0, 0)); - CuAssertTrue(tc, !long_order_allowed(u)); + CuAssertTrue(tc, !long_order_allowed(u, false)); rc->flags |= RCF_SWIM; - CuAssertTrue(tc, long_order_allowed(u)); + CuAssertTrue(tc, long_order_allowed(u, false)); + u->faction->flags |= FFL_PAUSED; + CuAssertTrue(tc, !long_order_allowed(u, false)); + u->faction->flags -= FFL_PAUSED; rc = test_create_race("aquarian"); u = test_create_unit(test_create_faction_ex(rc, NULL), u->region); - CuAssertTrue(tc, long_order_allowed(u)); + CuAssertTrue(tc, long_order_allowed(u, false)); + CuAssertTrue(tc, !long_order_allowed(u, true)); + u->faction->flags |= FFL_PAUSED; + CuAssertTrue(tc, !long_order_allowed(u, true)); + CuAssertTrue(tc, !long_order_allowed(u, false)); + u->faction->flags -= FFL_PAUSED; test_teardown(); } diff --git a/src/magic.c b/src/magic.c index 275219ee2..5642db417 100644 --- a/src/magic.c +++ b/src/magic.c @@ -2760,7 +2760,7 @@ void magic(void) !is_cursed(u->attribs, &ct_insectfur)) continue; - if (fval(u, UFL_WERE | UFL_LONGACTION)) { + if (fval(u, UFL_WERE | UFL_LONGACTION) || is_paused(u->faction)) { continue; } diff --git a/src/move.c b/src/move.c index f5b1b54b5..e420a2fe9 100644 --- a/src/move.c +++ b/src/move.c @@ -1184,6 +1184,7 @@ static bool transport(unit * ut, unit * u) static bool can_move(const unit * u) { + if (is_paused(u->faction)) return false; if (u_race(u)->flags & RCF_CANNOTMOVE) return false; if (get_movement(&u->attribs, MV_CANNOTMOVE)) @@ -2366,7 +2367,7 @@ static void move_followers(void) while (*up != NULL) { unit *u = *up; - if (!fval(u, UFL_MOVED | UFL_NOTMOVING)) { + if (!fval(u, UFL_MOVED | UFL_NOTMOVING) && !is_paused(u->faction)) { order *ord; for (ord = u->orders; ord; ord = ord->next) { @@ -2419,7 +2420,7 @@ static void move_pirates(void) while (*up) { unit *u = *up; - if (!fval(u, UFL_NOTMOVING) && getkeyword(u->thisorder) == K_PIRACY) { + if (!fval(u, UFL_NOTMOVING) && !is_paused(u->faction) && getkeyword(u->thisorder) == K_PIRACY) { piracy_cmd(u); fset(u, UFL_LONGACTION | UFL_NOTMOVING); } @@ -2450,6 +2451,7 @@ void move_units(void) while (*up) { unit* u = *up; up = &u->next; + if (is_paused(u->faction)) continue; if (!u->ship || ship_owner(u->ship) != u) { keyword_t kword = getkeyword(u->thisorder); @@ -2503,6 +2505,7 @@ void move_ships(void) { unit* u = *up; up = &u->next; + if (is_paused(u->faction)) continue; if (u->ship && !fval(u->ship, SF_DRIFTED)) { keyword_t kword = getkeyword(u->thisorder); diff --git a/src/randenc.c b/src/randenc.c index 56e53832e..0661b17c1 100644 --- a/src/randenc.c +++ b/src/randenc.c @@ -431,6 +431,7 @@ static void demon_skillchanges(void) for (r = regions; r; r = r->next) { unit *u; for (u = r->units; u; u = u->next) { + if (is_paused(u->faction)) continue; if (u_race(u) == rc_demon) { demon_skillchange(u); } diff --git a/src/recruit.c b/src/recruit.c index a48768890..567052611 100644 --- a/src/recruit.c +++ b/src/recruit.c @@ -479,6 +479,8 @@ void recruit(region * r) for (u = r->units; u; u = u->next) { order *ord; + if (is_paused(u->faction)) continue; + if ((rules_recruit & RECRUIT_MERGE) || u->number == 0) { for (ord = u->orders; ord; ord = ord->next) { if (getkeyword(ord) == K_RECRUIT) { diff --git a/src/renumber.c b/src/renumber.c index 5fb5310e9..500f4edfb 100644 --- a/src/renumber.c +++ b/src/renumber.c @@ -36,12 +36,15 @@ void renumber_factions(void) } *renum = NULL, *rp; faction *f; for (f = factions; f; f = f->next) { - attrib *a = a_find(f->attribs, &at_number); + attrib *a; int want; struct renum **rn; - if (!a) - continue; + if (is_paused(f)) continue; + + a = a_find(f->attribs, &at_number); + if (!a) continue; + want = a->data.i; if (!faction_id_is_unused(want)) { a_remove(&f->attribs, a); diff --git a/src/sort.c b/src/sort.c index 17da43563..066897ac5 100644 --- a/src/sort.c +++ b/src/sort.c @@ -21,7 +21,7 @@ void restack_units(void) bool sorted = false; while (*up) { unit *u = *up; - if (!fval(u, UFL_MARK)) { + if (!fval(u, UFL_MARK) && !is_paused(u->faction)) { struct order *ord; for (ord = u->orders; ord; ord = ord->next) { if (getkeyword(ord) == K_SORT) { From 202642e7d0b12922c25e31770cb87057cb251930 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 21 May 2021 21:37:07 +0200 Subject: [PATCH 05/12] paused factions are not allied to anyone. --- src/kernel/ally.c | 4 ++-- src/kernel/ally.test.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/kernel/ally.c b/src/kernel/ally.c index e63d85cd2..b2796032f 100644 --- a/src/kernel/ally.c +++ b/src/kernel/ally.c @@ -308,7 +308,7 @@ alliedgroup(const struct faction *f, allies *all = g ? g->allies : f->allies; int status; - if (!(faction_alive(f) && faction_alive(f2))) { + if (is_paused(f) || (!(faction_alive(f) && faction_alive(f2)))) { return 0; } status = ally_get(all, f2) & mask; @@ -329,7 +329,7 @@ int alliedunit(const unit * u, const faction * f2, int mask) if (u->faction == f2) { return mask; } - if (!faction_alive(f2)) { + if (is_paused(u->faction) || !faction_alive(f2)) { return 0; } if (u->faction != NULL && f2 != NULL) { diff --git a/src/kernel/ally.test.c b/src/kernel/ally.test.c index 05477d372..48c8cc541 100644 --- a/src/kernel/ally.test.c +++ b/src/kernel/ally.test.c @@ -66,12 +66,54 @@ static void test_allies_set(CuTest *tc) { test_teardown(); } +static void test_alliedfaction(CuTest *tc) { + struct faction *f1, *f2; + struct allies * al = NULL; + + test_setup(); + f1 = test_create_faction(); + f2 = test_create_faction(); + + CuAssertIntEquals(tc, 0, alliedfaction(f1, f2, HELP_ALL)); + ally_set(&f1->allies, f2, HELP_GIVE); + CuAssertIntEquals(tc, HELP_GIVE, alliedfaction(f1, f2, HELP_ALL)); + ally_set(&f1->allies, f2, HELP_ALL); + CuAssertIntEquals(tc, HELP_ALL, alliedfaction(f1, f2, HELP_ALL)); + f1->flags |= FFL_PAUSED; + CuAssertIntEquals(tc, 0, alliedfaction(f1, f2, HELP_ALL)); + + test_teardown(); +} + +static void test_alliedunit(CuTest *tc) { + struct faction *f2, *f1; + struct unit *u; + struct allies *al = NULL; + + test_setup(); + u = test_create_unit(f1 = test_create_faction(), test_create_plain(0, 0)); + f2 = test_create_faction(); + + CuAssertIntEquals(tc, 0, alliedunit(u, f2, HELP_ALL)); + ally_set(&f1->allies, f2, HELP_GIVE); + CuAssertIntEquals(tc, HELP_GIVE, alliedunit(u, f2, HELP_ALL)); + ally_set(&f1->allies, f2, HELP_ALL); + CuAssertIntEquals(tc, HELP_ALL, alliedunit(u, f2, HELP_ALL)); + f1->flags |= FFL_PAUSED; + CuAssertIntEquals(tc, 0, alliedunit(u, f2, HELP_ALL)); + + test_teardown(); +} + + CuSuite *get_ally_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_allies); SUITE_ADD_TEST(suite, test_allies_clone); SUITE_ADD_TEST(suite, test_allies_set); + SUITE_ADD_TEST(suite, test_alliedfaction); + SUITE_ADD_TEST(suite, test_alliedunit); return suite; } From d2cc7bde69313f2b3f4711b1fa4b2b9c746f437e Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 21 May 2021 22:13:03 +0200 Subject: [PATCH 06/12] unused variables --- src/kernel/ally.test.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/kernel/ally.test.c b/src/kernel/ally.test.c index 48c8cc541..9be916b3c 100644 --- a/src/kernel/ally.test.c +++ b/src/kernel/ally.test.c @@ -68,7 +68,6 @@ static void test_allies_set(CuTest *tc) { static void test_alliedfaction(CuTest *tc) { struct faction *f1, *f2; - struct allies * al = NULL; test_setup(); f1 = test_create_faction(); @@ -88,7 +87,6 @@ static void test_alliedfaction(CuTest *tc) { static void test_alliedunit(CuTest *tc) { struct faction *f2, *f1; struct unit *u; - struct allies *al = NULL; test_setup(); u = test_create_unit(f1 = test_create_faction(), test_create_plain(0, 0)); From e0d6bb410ee99ad8540a2be7b6a8ef2fc7d82c93 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 22 May 2021 05:36:54 +0200 Subject: [PATCH 07/12] Endlosschleife in BETRETE --- src/laws.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/laws.c b/src/laws.c index 8170b1005..e921a5530 100644 --- a/src/laws.c +++ b/src/laws.c @@ -1208,7 +1208,10 @@ void do_enter(struct region *r, bool is_final_attempt) unit *u = *uptr; order **ordp = &u->orders; - if (is_paused(u->faction)) continue; + if (is_paused(u->faction)) { + uptr = &u->next; + continue; + } while (*ordp) { order *ord = *ordp; From a3916b8271e4d8dd23c475b59707a1fcbce446ca Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 22 May 2021 12:45:34 +0200 Subject: [PATCH 08/12] PAusierte Parteien: HELFE BEWACHE bleibt erhalten. --- src/kernel/ally.c | 9 ++++++--- src/kernel/ally.test.c | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/kernel/ally.c b/src/kernel/ally.c index b2796032f..695d71738 100644 --- a/src/kernel/ally.c +++ b/src/kernel/ally.c @@ -308,10 +308,13 @@ alliedgroup(const struct faction *f, allies *all = g ? g->allies : f->allies; int status; - if (is_paused(f) || (!(faction_alive(f) && faction_alive(f2)))) { + if (!(faction_alive(f) && faction_alive(f2))) { return 0; } status = ally_get(all, f2) & mask; + if (is_paused(f)) { + status &= HELP_GUARD; + } return alliance_status(f, f2, status); } @@ -329,8 +332,8 @@ int alliedunit(const unit * u, const faction * f2, int mask) if (u->faction == f2) { return mask; } - if (is_paused(u->faction) || !faction_alive(f2)) { - return 0; + if (!faction_alive(f2)) { + return mask; } if (u->faction != NULL && f2 != NULL) { group *g; diff --git a/src/kernel/ally.test.c b/src/kernel/ally.test.c index 9be916b3c..8eec67048 100644 --- a/src/kernel/ally.test.c +++ b/src/kernel/ally.test.c @@ -79,7 +79,7 @@ static void test_alliedfaction(CuTest *tc) { ally_set(&f1->allies, f2, HELP_ALL); CuAssertIntEquals(tc, HELP_ALL, alliedfaction(f1, f2, HELP_ALL)); f1->flags |= FFL_PAUSED; - CuAssertIntEquals(tc, 0, alliedfaction(f1, f2, HELP_ALL)); + CuAssertIntEquals(tc, HELP_GUARD, alliedfaction(f1, f2, HELP_ALL)); test_teardown(); } @@ -98,7 +98,7 @@ static void test_alliedunit(CuTest *tc) { ally_set(&f1->allies, f2, HELP_ALL); CuAssertIntEquals(tc, HELP_ALL, alliedunit(u, f2, HELP_ALL)); f1->flags |= FFL_PAUSED; - CuAssertIntEquals(tc, 0, alliedunit(u, f2, HELP_ALL)); + CuAssertIntEquals(tc, HELP_GUARD, alliedunit(u, f2, HELP_ALL)); test_teardown(); } From e6da5d92d8acba087aa03f0cdd6d2545a4adebba Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 22 May 2021 12:48:06 +0200 Subject: [PATCH 09/12] Pausierte Parteien bewachen nicht. --- src/guard.c | 18 +++++++++--------- src/guard.test.c | 6 ++++++ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/guard.c b/src/guard.c index 17ab8581e..bb1b59c51 100644 --- a/src/guard.c +++ b/src/guard.c @@ -84,25 +84,25 @@ static bool is_guardian_u(const unit * guard, unit * u) return true; } -static bool is_guardian_r(const unit * guard) +static bool is_guardian_r(const unit * u) { - if (guard->number == 0) + if (u->number == 0 || is_paused(u->faction)) 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) { + if (u->building && rule_region_owners() && u == building_owner(u->building)) { + faction *owner = region_get_owner(u->region); + if (owner == u->faction) { + building *bowner = largestbuilding(u->region, cmp_taxes, false); + if (bowner == u->building) { return true; } } } - if ((guard->flags & UFL_GUARD) == 0) + if ((u->flags & UFL_GUARD) == 0) return false; - return fval(u_race(guard), RCF_UNARMEDGUARD) || is_monsters(guard->faction) || (armedmen(guard, true) > 0); + return fval(u_race(u), RCF_UNARMEDGUARD) || is_monsters(u->faction) || (armedmen(u, true) > 0); } bool is_guard(const struct unit * u) diff --git a/src/guard.test.c b/src/guard.test.c index 53c9652fe..6f81d405f 100644 --- a/src/guard.test.c +++ b/src/guard.test.c @@ -97,6 +97,12 @@ static void test_is_guard(CuTest * tc) set_level(ug, SK_MELEE, 1); CuAssertIntEquals(tc, 1, armedmen(ug, false)); CuAssertTrue(tc, is_guard(ug)); + + ug->faction->flags |= FFL_PAUSED; + CuAssertTrue(tc, !is_guard(ug)); + i_change(&ug->items, itype, -1); + CuAssertIntEquals(tc, 0, armedmen(ug, false)); + CuAssertTrue(tc, !is_guard(ug)); test_teardown(); } From ab5669a514970d729dd2b633f41ab589f505ea10 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 30 May 2021 15:14:55 +0200 Subject: [PATCH 10/12] monsters do not attack paused factions --- src/monsters.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/monsters.c b/src/monsters.c index 4f69806e8..3fbda5215 100644 --- a/src/monsters.c +++ b/src/monsters.c @@ -167,6 +167,9 @@ static order *monster_attack(unit * u, const unit * target) { assert(u->region == target->region); assert(u->faction != target->faction); + if (is_paused(target->faction)) { + return NULL; + } if (!cansee(u->faction, u->region, target, 0)) { return NULL; } From 062e5ff7ae9f8379615b01006ef13e89aaf183a4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 6 Jun 2021 16:34:17 +0200 Subject: [PATCH 11/12] paused units do not sort. --- src/sort.test.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/sort.test.c b/src/sort.test.c index d8e0eadd3..58171ca36 100644 --- a/src/sort.test.c +++ b/src/sort.test.c @@ -123,6 +123,30 @@ static void test_sort_before_owner(CuTest *tc) { test_teardown(); } +static void test_sort_paused(CuTest *tc) { + unit *u1, *u2; + faction *f; + region *r; + + test_setup(); + u1 = test_create_unit(f = test_create_faction(), r = test_create_plain(0, 0)); + u2 = test_create_unit(f, r); + unit_addorder(u2, create_order(K_SORT, f->locale, "%s %s", + LOC(f->locale, parameters[P_BEFORE]), itoa36(u1->no))); + CuAssertPtrEquals(tc, u1, r->units); + CuAssertPtrEquals(tc, u2, u1->next); + CuAssertPtrEquals(tc, NULL, u2->next); + + /* paused faction, so nothing happens: */ + f->flags |= FFL_PAUSED; + restack_units(); + CuAssertPtrEquals(tc, u1, r->units); + CuAssertPtrEquals(tc, u2, u1->next); + CuAssertPtrEquals(tc, NULL, u2->next); + CuAssertPtrEquals(tc, NULL, f->msgs); + + test_teardown(); +} CuSuite *get_sort_suite(void) { @@ -130,5 +154,6 @@ CuSuite *get_sort_suite(void) SUITE_ADD_TEST(suite, test_sort_before_owner); SUITE_ADD_TEST(suite, test_sort_after); SUITE_ADD_TEST(suite, test_sort_before); + SUITE_ADD_TEST(suite, test_sort_paused); return suite; } From 4a7580e8eb486de37235552c013ec7e0bbae2392 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 6 Jun 2021 17:52:34 +0200 Subject: [PATCH 12/12] SORTIERE VOR eine pausierte Einheit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Automatische Kommandoübergabe inklusive. --- src/sort.c | 47 +++++++++++++++++++++-------- src/sort.test.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+), 12 deletions(-) diff --git a/src/sort.c b/src/sort.c index 066897ac5..150f35785 100644 --- a/src/sort.c +++ b/src/sort.c @@ -13,6 +13,17 @@ #include "util/param.h" #include "util/parser.h" +void sort_before(unit *v, unit **up) { + unit *u = *up; + region *r = u->region; + unit **vp = &r->units; + while (*vp != v) + vp = &(*vp)->next; + *vp = u; + *up = u->next; + u->next = v; +} + void restack_units(void) { region *r; @@ -37,7 +48,13 @@ void restack_units(void) id = getid(); v = findunit(id); - if (!v || v->faction != u->faction || v->region != r) { + if (v == u) { + syntax_error(u, ord); + } + else if (!v || v->region != r) { + cmistake(u, ord, 258, MSG_EVENT); + } + else if (v->faction != u->faction && !is_paused(v->faction)) { cmistake(u, ord, 258, MSG_EVENT); } else if (v->building != u->building || v->ship != u->ship) { @@ -49,9 +66,6 @@ void restack_units(void) else if (u->ship && ship_owner(u->ship) == u) { cmistake(u, ord, 260, MSG_EVENT); } - else if (v == u) { - syntax_error(u, ord); - } else { switch (p) { case P_AFTER: @@ -63,18 +77,27 @@ void restack_units(void) break; case P_BEFORE: if (v->ship && ship_owner(v->ship) == v) { - cmistake(v, ord, 261, MSG_EVENT); + if (is_paused(v->faction)) { + sort_before(v, up); + ship_set_owner(u); + } + else { + cmistake(v, ord, 261, MSG_EVENT); + break; + } } else if (v->building && building_owner(v->building) == v) { - cmistake(v, ord, 261, MSG_EVENT); + if (is_paused(v->faction)) { + sort_before(v, up); + building_set_owner(u); + } + else { + cmistake(v, ord, 261, MSG_EVENT); + break; + } } else { - unit **vp = &r->units; - while (*vp != v) - vp = &(*vp)->next; - *vp = u; - *up = u->next; - u->next = v; + sort_before(v, up); } fset(u, UFL_MARK); sorted = true; diff --git a/src/sort.test.c b/src/sort.test.c index 58171ca36..b9d4a144c 100644 --- a/src/sort.test.c +++ b/src/sort.test.c @@ -123,6 +123,84 @@ static void test_sort_before_owner(CuTest *tc) { test_teardown(); } +static void test_sort_before_paused_building_owner(CuTest *tc) { + unit *u1, *u2; + faction *f; + region *r; + building *b; + + test_setup(); + u1 = test_create_unit(f = test_create_faction(), r = test_create_plain(0, 0)); + f->flags |= FFL_PAUSED; + b = test_create_building(r, NULL); + + u2 = test_create_unit(f = test_create_faction(), r); + unit_addorder(u2, create_order(K_SORT, f->locale, "%s %s", + LOC(f->locale, parameters[P_BEFORE]), itoa36(u1->no))); + u1->building = b; + building_update_owner(b); + CuAssertPtrEquals(tc, u1, r->units); + CuAssertPtrEquals(tc, u2, u1->next); + CuAssertPtrEquals(tc, NULL, u2->next); + + /* not in building, nothing happend: */ + restack_units(); + CuAssertPtrEquals(tc, u1, r->units); + CuAssertPtrEquals(tc, u2, u1->next); + CuAssertPtrEquals(tc, NULL, u2->next); + CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error259")); + test_clear_messagelist(&f->msgs); + + /* u1 allows u2 to steal the top spot: */ + u2->building = b; + restack_units(); + CuAssertPtrEquals(tc, u2, r->units); + CuAssertPtrEquals(tc, u1, u2->next); + CuAssertPtrEquals(tc, NULL, u1->next); + CuAssertPtrEquals(tc, u2, building_owner(b)); + CuAssertPtrEquals(tc, NULL, f->msgs); + test_teardown(); +} + +static void test_sort_before_paused_ship_owner(CuTest *tc) { + unit *u1, *u2; + faction *f; + region *r; + ship *sh; + + test_setup(); + u1 = test_create_unit(f = test_create_faction(), r = test_create_plain(0, 0)); + f->flags |= FFL_PAUSED; + sh = test_create_ship(r, NULL); + + u2 = test_create_unit(f = test_create_faction(), r); + unit_addorder(u2, create_order(K_SORT, f->locale, "%s %s", + LOC(f->locale, parameters[P_BEFORE]), itoa36(u1->no))); + u1->ship = sh; + ship_update_owner(sh); + CuAssertPtrEquals(tc, u1, r->units); + CuAssertPtrEquals(tc, u2, u1->next); + CuAssertPtrEquals(tc, NULL, u2->next); + + /* not in ship, nothing happend: */ + restack_units(); + CuAssertPtrEquals(tc, u1, r->units); + CuAssertPtrEquals(tc, u2, u1->next); + CuAssertPtrEquals(tc, NULL, u2->next); + CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error259")); + test_clear_messagelist(&f->msgs); + + /* u1 allows u2 to steal the top spot: */ + u2->ship = sh; + restack_units(); + CuAssertPtrEquals(tc, u2, r->units); + CuAssertPtrEquals(tc, u1, u2->next); + CuAssertPtrEquals(tc, NULL, u1->next); + CuAssertPtrEquals(tc, u2, ship_owner(sh)); + CuAssertPtrEquals(tc, NULL, f->msgs); + test_teardown(); +} + static void test_sort_paused(CuTest *tc) { unit *u1, *u2; faction *f; @@ -152,6 +230,8 @@ CuSuite *get_sort_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_sort_before_owner); + SUITE_ADD_TEST(suite, test_sort_before_paused_ship_owner); + SUITE_ADD_TEST(suite, test_sort_before_paused_building_owner); SUITE_ADD_TEST(suite, test_sort_after); SUITE_ADD_TEST(suite, test_sort_before); SUITE_ADD_TEST(suite, test_sort_paused);