From 5b2538b72d7df1bef26cda9b1aa9516381232116 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 21 Jun 2015 18:32:57 +0200 Subject: [PATCH 01/17] increase build number --- src/buildno.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/buildno.h b/src/buildno.h index d1f3c3fcf..813baf03b 100644 --- a/src/buildno.h +++ b/src/buildno.h @@ -1,3 +1,3 @@ #define VERSION_MAJOR 3 #define VERSION_MINOR 5 -#define VERSION_BUILD 2 +#define VERSION_BUILD 3 From 730996bedf8a4d6e325ff939d053b5e6cb936fa0 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 7 Jul 2015 15:32:24 +0200 Subject: [PATCH 02/17] send signals from travis to slack --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index cbf3ff239..013487ff3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,3 +9,6 @@ before_install: os: - linux - osx +notifications: + slack: + secure: F89aXLWaE125PaJIlETv12jT4EfH6wLXJmGCPZzrN3OcLn2ahDWqjwuzR7lOEDf2nAISmeMPyDZMhEHXLNHAE5qP6lg9yliYQw5hzGmDK9m1xUq/pPEne/b2Y7K3my1mkRZ6n3asbHgSmBWAfCIk1JN8R5Rv+rmbLuWLc+zofts= From 57268d3cd2fd1e6133cca1fe8dd57c2327932a65 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 11 Jul 2015 12:55:13 +0200 Subject: [PATCH 03/17] remove old iniparser --- .gitmodules | 3 --- 1 file changed, 3 deletions(-) diff --git a/.gitmodules b/.gitmodules index e5eb61079..2848986e4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -19,9 +19,6 @@ [submodule "cutest"] path = cutest url = git://github.com/badgerman/cutest.git -[submodule "iniparser"] - path = iniparser - url = git://github.com/badgerman/iniparser.git [submodule "cJSON"] path = cJSON url = git://github.com/badgerman/cJSON.git From 2630b6203d9da7bfff72309812e8a1943421aaea Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 11 Jul 2015 14:33:09 +0200 Subject: [PATCH 04/17] updte submoduiles before building --- s/build | 1 + 1 file changed, 1 insertion(+) diff --git a/s/build b/s/build index 068a669a1..9711e6da8 100755 --- a/s/build +++ b/s/build @@ -29,6 +29,7 @@ if [ ! -d $ROOT/$BIN_DIR ]; then exit fi +git submodule update cd $ROOT/$BIN_DIR make $MAKEOPTS && make test cd $OLDPWD From 65b7fc7ff803cb8af450f3d061f97d4f73af4a7d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 12 Jul 2015 04:49:40 +0200 Subject: [PATCH 05/17] prefer clang --- s/build | 1 + s/cmake-init | 1 + s/runtests | 1 + 3 files changed, 3 insertions(+) diff --git a/s/build b/s/build index 9711e6da8..3cddebc6e 100755 --- a/s/build +++ b/s/build @@ -6,6 +6,7 @@ done [ -z $BUILD ] && BUILD=Debug MACHINE=`uname -m` +[ -z "$CC" ] && [ ! -z `which clang` ] && CC="clang" [ -z "$CC" ] && [ ! -z `which gcc` ] && CC="gcc" [ -z "$CC" ] && [ ! -z `which tcc` ] && CC="tcc" [ -z "$CC" ] && [ ! -z `which cc` ] && CC="cc" diff --git a/s/cmake-init b/s/cmake-init index 913aef82b..22facb053 100755 --- a/s/cmake-init +++ b/s/cmake-init @@ -10,6 +10,7 @@ done [ -z $BUILD ] && BUILD=Debug MACHINE=`uname -m` +[ -z "$CC" ] && [ ! -z `which clang` ] && CC="clang" [ -z "$CC" ] && [ ! -z `which gcc` ] && CC="gcc" [ -z "$CC" ] && [ ! -z `which tcc` ] && CC="tcc" [ -z "$CC" ] && [ ! -z `which cc` ] && CC="cc" diff --git a/s/runtests b/s/runtests index 3f3b61548..840fc1119 100755 --- a/s/runtests +++ b/s/runtests @@ -7,6 +7,7 @@ while [ ! -d $ROOT/.git ]; do done MACHINE=`uname -m` +[ -z "$CC" ] && [ ! -z `which clang` ] && CC="clang" [ -z "$CC" ] && [ ! -z `which gcc` ] && CC="gcc" [ -z "$CC" ] && [ ! -z `which tcc` ] && CC="tcc" [ -z "$CC" ] && [ ! -z `which cc` ] && CC="cc" From 009993f2f4f87a814db149cca68292c732fe5407 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 21 Jul 2015 09:01:11 +0200 Subject: [PATCH 06/17] address some PVS comments --- src/sqlite.c | 2 +- src/util/translation.c | 24 +++++++++++++++--------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/sqlite.c b/src/sqlite.c index c19aa6903..fd46c4f1f 100644 --- a/src/sqlite.c +++ b/src/sqlite.c @@ -123,9 +123,9 @@ static void update_faction(sqlite3 *db, const faction *f) { "INSERT INTO faction_data (faction_id, code, name, email, lang, turn)" " VALUES (?, ?, ?, ?, ?, ?)"; sqlite3_stmt *stmt = 0; + strcpy(code, itoa36(f->no)); sqlite3_prepare_v2(db, sql, -1, &stmt, 0); sqlite3_bind_int(stmt, 1, f->subscription); - strcpy(code, itoa36(f->no)); sqlite3_bind_text(stmt, 2, code, -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 3, f->name, -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 4, f->email, -1, SQLITE_STATIC); diff --git a/src/util/translation.c b/src/util/translation.c index d73074294..16d3e684f 100644 --- a/src/util/translation.c +++ b/src/util/translation.c @@ -31,7 +31,7 @@ typedef struct opstack { variant *begin; variant *top; - int size; + unsigned int size; } opstack; variant opstack_pop(opstack ** stackp) @@ -53,10 +53,16 @@ void opstack_push(opstack ** stackp, variant data) stack->top = stack->begin; *stackp = stack; } - if (stack->top - stack->begin == stack->size) { + if (stack->top == stack->begin + stack->size) { size_t pos = stack->top - stack->begin; + void *tmp; stack->size += stack->size; - stack->begin = realloc(stack->begin, sizeof(variant) * stack->size); + tmp = realloc(stack->begin, sizeof(variant) * stack->size); + if (!tmp) { + log_error("realloc out of memory"); + abort(); + } + stack->begin = (variant *)tmp; stack->top = stack->begin + pos; } *stack->top++ = data; @@ -66,7 +72,7 @@ void opstack_push(opstack ** stackp, variant data) ** static buffer malloc **/ -#define BBUFSIZE 128*1024 +#define BBUFSIZE 0x20000 static struct { char *begin; char *end; @@ -79,7 +85,7 @@ char *balloc(size_t size) static int init = 0; /* STATIC_XCALL: used across calls */ if (!init) { init = 1; - buffer.current = buffer.begin = malloc(BBUFSIZE); + buffer.current = buffer.begin = malloc(BBUFSIZE * sizeof(char)); buffer.end = buffer.begin + BBUFSIZE; } if (buffer.current + size > buffer.end) { @@ -269,7 +275,7 @@ static const char *parse_string(opstack ** stack, const char *in, } else { int ch = (unsigned char)(*ic); - int bytes; + size_t bytes; switch (ch) { case '\\': @@ -285,8 +291,8 @@ static const char *parse_string(opstack ** stack, const char *in, if (ic == NULL) return NULL; c = (char *)opop_v(stack); - bytes = (int)(c ? strlcpy(oc, c, size) : 0); - if (bytes < (int)size) + bytes = (c ? strlcpy(oc, c, size) : 0); + if (bytes < size) oc += bytes; else oc += size; @@ -363,7 +369,7 @@ static const char *parse(opstack ** stack, const char *inn, const char *translate(const char *format, const void *userdata, const char *vars, variant args[]) { - int i = 0; + unsigned int i = 0; const char *ic = vars; char symbol[32]; char *oc = symbol; From a119f7617fb541514a972f510bb7c0da640870fd Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 2 Aug 2015 21:17:21 +0200 Subject: [PATCH 07/17] add some assertions to make sure update_gbdream is not called without a magician --- src/kernel/config.c | 2 ++ src/kernel/unit.c | 10 ++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/kernel/config.c b/src/kernel/config.c index 2e0f2c32c..7cdf44ea8 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -530,6 +530,8 @@ int alliedunit(const unit * u, const faction * f2, int mode) ally *sf; int automode; + assert(u); + assert(f2); assert(u->region); /* the unit should be in a region, but it's possible that u->number==0 (TEMP units) */ if (u->faction == f2) return mode; diff --git a/src/kernel/unit.c b/src/kernel/unit.c index ea2bbd950..7a992563f 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -1278,10 +1278,12 @@ static int update_gbdream(const unit * u, int bonus, curse *c, const curse_type if (curse_active(c) && c->type == gbdream_ct) { double effect = curse_geteffect(c); unit *mage = c->magician; - /* wir suchen jeweils den groessten Bonus und den groestsen Malus */ + /* wir suchen jeweils den groessten Bonus und den groessten Malus */ if (sign * effect > sign * bonus) { - if (mage == NULL || mage->number == 0 - || sign>0?alliedunit(mage, u->faction, HELP_GUARD):!alliedunit(mage, u->faction, HELP_GUARD)) { + bool allied; + assert(mage && mage->number > 0); + allied = alliedunit(mage, u->faction, HELP_GUARD); + if ((sign>0)?allied:!allied) { bonus = (int)effect; } } @@ -1327,9 +1329,9 @@ int att_modification(const unit * u, skill_t sk) while (a && a->type == &at_curse) { curse *c = (curse *)a->data.v; + assert(c->magician); // update_gbdream makes no sense if there is no caster (calls alliedunit) bonus = update_gbdream(u, bonus, c, gbdream_ct, 1); malus = update_gbdream(u, malus, c, gbdream_ct, -1); - a = a->next; } result = result + bonus + malus; From 17f15b69ee890215292cdbbb5a809b91e8e7252d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 2 Aug 2015 21:37:12 +0200 Subject: [PATCH 08/17] fix some of the unicode replacement symbol bullshit in comments --- src/kernel/save.c | 16 +++--- src/laws.c | 130 +++++++++++++++++++++++----------------------- src/move.c | 80 ++++++++++++++-------------- 3 files changed, 113 insertions(+), 113 deletions(-) diff --git a/src/kernel/save.c b/src/kernel/save.c index d9a18f2b3..3751bea91 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 1998-2015, Enno Rehling Katja Zedel @@ -200,7 +200,7 @@ static unit *unitorders(FILE * F, int enc, struct faction *f) } } } - /* Nun wird der Befehl erzeut und eingehängt */ + /* Nun wird der Befehl erzeut und eingehängt */ *ordp = parse_order(s, u->faction->locale); if (*ordp) { ordp = &(*ordp)->next; @@ -233,8 +233,8 @@ static faction *factionorders(void) f->no, pass)); return 0; } - /* Die Partei hat sich zumindest gemeldet, so daß sie noch - * nicht als untätig gilt */ + /* Die Partei hat sich zumindest gemeldet, so dass sie noch + * nicht als untätig gilt */ /* TODO: +1 ist ein Workaround, weil cturn erst in process_orders * incrementiert wird. */ @@ -308,9 +308,9 @@ int readorders(const char *filename) /* Falls in unitorders() abgebrochen wird, steht dort entweder eine neue * Partei, eine neue Einheit oder das File-Ende. Das switch() wird erneut * durchlaufen, und die entsprechende Funktion aufgerufen. Man darf buf - * auf alle Fälle nicht überschreiben! Bei allen anderen Einträgen hier - * muß buf erneut gefüllt werden, da die betreffende Information in nur - * einer Zeile steht, und nun die nächste gelesen werden muß. */ + * auf alle Fälle nicht überschreiben! Bei allen anderen Einträgen hier + * muss buf erneut gefüllt werden, da die betreffende Information in nur + * einer Zeile steht, und nun die nächste gelesen werden muss. */ case P_NEXT: f = NULL; @@ -331,7 +331,7 @@ int readorders(const char *filename) /* ------------------------------------------------------------- */ /* #define INNER_WORLD */ -/* fürs debuggen nur den inneren Teil der Welt laden */ +/* fürs debuggen nur den inneren Teil der Welt laden */ /* -9;-27;-1;-19;Sumpfloch */ int inner_world(region * r) { diff --git a/src/laws.c b/src/laws.c index fe201670c..b867b9f14 100755 --- a/src/laws.c +++ b/src/laws.c @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 1998-2014, Enno Rehling Katja Zedel next ist dann - * undefiniert, also muessen wir hier schon das nächste + * undefiniert, also muessen wir hier schon das nächste * Element bestimmen */ int effect = get_effect(u, oldpotiontype[P_FOOL]); @@ -193,7 +193,7 @@ static void live(region * r) reduce_skill(u, sb, weeks); ADDMSG(&u->faction->msgs, msg_message("dumbeffect", "unit weeks skill", u, weeks, (skill_t)sb->id)); - } /* sonst Glück gehabt: wer nix weiß, kann nix vergessen... */ + } /* sonst Glück gehabt: wer nix weiss, kann nix vergessen... */ change_effect(u, oldpotiontype[P_FOOL], -effect); } age_unit(r, u); @@ -337,16 +337,16 @@ static void peasants(region * r) peasants += births + luck; } - /* Alle werden satt, oder halt soviele für die es auch Geld gibt */ + /* Alle werden satt, oder halt soviele für die es auch Geld gibt */ satiated = _min(peasants, money / maintenance_cost(NULL)); rsetmoney(r, money - satiated * maintenance_cost(NULL)); /* Von denjenigen, die nicht satt geworden sind, verhungert der - * Großteil. dead kann nie größer als rpeasants(r) - satiated werden, - * so dass rpeasants(r) >= 0 bleiben muß. */ + * Großteil. dead kann nie größer als rpeasants(r) - satiated werden, + * so dass rpeasants(r) >= 0 bleiben muß. */ - /* Es verhungert maximal die unterernährten Bevölkerung. */ + /* Es verhungert maximal die unterernährten Bevölkerung. */ n = _min(peasants - satiated, rpeasants(r)); dead += (int)(0.5F + n * PEASANT_STARVATION_CHANCE); @@ -411,10 +411,10 @@ static void migrate(region * r) rsethorses(r, rhorses(r) + m->horses); /* Was macht das denn hier? * Baumwanderung wird in trees() gemacht. - * wer fragt das? Die Baumwanderung war abhängig von der + * wer fragt das? Die Baumwanderung war abhängig von der * Auswertungsreihenfolge der regionen, - * das hatte ich geändert. jemand hat es wieder gelöscht, toll. - * ich habe es wieder aktiviert, muß getestet werden. + * das hatte ich geändert. jemand hat es wieder gelöscht, toll. + * ich habe es wieder aktiviert, muss getestet werden. */ *hp = m->next; m->next = free_migrants; @@ -454,8 +454,8 @@ static void horses(region * r) /* Pferde wandern in Nachbarregionen. * Falls die Nachbarregion noch berechnet - * werden muß, wird eine migration-Struktur gebildet, - * die dann erst in die Berechnung der Nachbarstruktur einfließt. + * werden muss, wird eine migration-Struktur gebildet, + * die dann erst in die Berechnung der Nachbarstruktur einfließt. */ for (n = 0; n != MAXDIRECTIONS; n++) { @@ -469,7 +469,7 @@ static void horses(region * r) else { migration *nb; /* haben wir die Migration schonmal benutzt? - * wenn nicht, müssen wir sie suchen. + * wenn nicht, müssen wir sie suchen. * Wandernde Pferde vermehren sich nicht. */ nb = get_migrants(r2); @@ -565,11 +565,11 @@ growing_trees(region * r, const int current_season, const int last_weeks_season) a = a_find(r->attribs, &at_germs); if (a && last_weeks_season == SEASON_SPRING) { - /* ungekeimte Samen bleiben erhalten, Sprößlinge wachsen */ + /* ungekeimte Samen bleiben erhalten, Sprößlinge wachsen */ sprout = _min(a->data.sa[1], rtrees(r, 1)); - /* aus dem gesamt Sprößlingepool abziehen */ + /* aus dem gesamt Sprößlingepool abziehen */ rsettrees(r, 1, rtrees(r, 1) - sprout); - /* zu den Bäumen hinzufügen */ + /* zu den Bäumen hinzufügen */ rsettrees(r, 2, rtrees(r, 2) + sprout); a_removeall(&r->attribs, &at_germs); @@ -585,7 +585,7 @@ growing_trees(region * r, const int current_season, const int last_weeks_season) return; /* Grundchance 1.0% */ - /* Jeder Elf in der Region erhöht die Chance marginal */ + /* Jeder Elf in der Region erhöht die Chance marginal */ elves = _min(elves, production(r) / 8); if (elves) { seedchance += 1.0 - pow(0.99999, elves * RESOURCE_QUANTITY); @@ -606,19 +606,19 @@ growing_trees(region * r, const int current_season, const int last_weeks_season) } } - /* Bäume breiten sich in Nachbarregionen aus. */ + /* Bäume breiten sich in Nachbarregionen aus. */ /* Gesamtzahl der Samen: - * bis zu 6% (FORESTGROWTH*3) der Bäume samen in die Nachbarregionen */ + * bis zu 6% (FORESTGROWTH*3) der Bäume samen in die Nachbarregionen */ seeds = (rtrees(r, 2) * FORESTGROWTH * 3) / 1000000; for (d = 0; d != MAXDIRECTIONS; ++d) { region *r2 = rconnect(r, d); if (r2 && fval(r2->terrain, LAND_REGION) && r2->terrain->size) { /* Eine Landregion, wir versuchen Samen zu verteilen: - * Die Chance, das Samen ein Stück Boden finden, in dem sie - * keimen können, hängt von der Bewuchsdichte und der - * verfügbaren Fläche ab. In Gletschern gibt es weniger - * Möglichkeiten als in Ebenen. */ + * Die Chance, das Samen ein Stück Boden finden, in dem sie + * keimen können, hängt von der Bewuchsdichte und der + * verfügbaren Fläche ab. In Gletschern gibt es weniger + * Möglichkeiten als in Ebenen. */ sprout = 0; seedchance = (1000 * maxworkingpeasants(r2)) / r2->terrain->size; for (i = 0; i < seeds / MAXDIRECTIONS; i++) { @@ -635,8 +635,8 @@ growing_trees(region * r, const int current_season, const int last_weeks_season) if (is_cursed(r->attribs, C_CURSED_BY_THE_GODS, 0)) return; - /* in at_germs merken uns die Zahl der Samen und Sprößlinge, die - * dieses Jahr älter werden dürfen, damit nicht ein Same im selben + /* in at_germs merken uns die Zahl der Samen und Sprößlinge, die + * dieses Jahr älter werden dürfen, damit nicht ein Same im selben * Zyklus zum Baum werden kann */ a = a_find(r->attribs, &at_germs); if (!a) { @@ -644,13 +644,13 @@ growing_trees(region * r, const int current_season, const int last_weeks_season) a->data.sa[0] = (short)rtrees(r, 0); a->data.sa[1] = (short)rtrees(r, 1); } - /* wir haben 6 Wochen zum wachsen, jeder Same/Sproß hat 18% Chance + /* wir haben 6 Wochen zum wachsen, jeder Same/Spross hat 18% Chance * zu wachsen, damit sollten nach 5-6 Wochen alle gewachsen sein */ growth = 1800; /* Samenwachstum */ - /* Raubbau abfangen, es dürfen nie mehr Samen wachsen, als aktuell + /* Raubbau abfangen, es dürfen nie mehr Samen wachsen, als aktuell * in der Region sind */ seeds = _min(a->data.sa[0], rtrees(r, 0)); sprout = 0; @@ -663,15 +663,15 @@ growing_trees(region * r, const int current_season, const int last_weeks_season) a->data.sa[0] = (short)(seeds - sprout); /* aus dem gesamt Samenpool abziehen */ rsettrees(r, 0, rtrees(r, 0) - sprout); - /* zu den Sprößlinge hinzufügen */ + /* zu den Sprößlinge hinzufügen */ rsettrees(r, 1, rtrees(r, 1) + sprout); /* Baumwachstum */ - /* hier gehen wir davon aus, das Jungbäume nicht ohne weiteres aus - * der Region entfernt werden können, da Jungbäume in der gleichen - * Runde nachwachsen, wir also nicht mehr zwischen diesjährigen und - * 'alten' Jungbäumen unterscheiden könnten */ + /* hier gehen wir davon aus, das Jungbäume nicht ohne weiteres aus + * der Region entfernt werden können, da Jungbäume in der gleichen + * Runde nachwachsen, wir also nicht mehr zwischen diesjährigen und + * 'alten' Jungbäumen unterscheiden könnten */ sprout = _min(a->data.sa[1], rtrees(r, 1)); grownup_trees = 0; @@ -679,11 +679,11 @@ growing_trees(region * r, const int current_season, const int last_weeks_season) if (rng_int() % 10000 < growth) grownup_trees++; } - /* aus dem Sprößlingepool dieses Jahres abziehen */ + /* aus dem Sprößlingepool dieses Jahres abziehen */ a->data.sa[1] = (short)(sprout - grownup_trees); - /* aus dem gesamt Sprößlingepool abziehen */ + /* aus dem gesamt Sprößlingepool abziehen */ rsettrees(r, 1, rtrees(r, 1) - grownup_trees); - /* zu den Bäumen hinzufügen */ + /* zu den bäumen hinzufügen */ rsettrees(r, 2, rtrees(r, 2) + grownup_trees); } } @@ -691,10 +691,10 @@ growing_trees(region * r, const int current_season, const int last_weeks_season) static void growing_herbs(region * r, const int current_season, const int last_weeks_season) { - /* Jetzt die Kräutervermehrung. Vermehrt wird logistisch: + /* Jetzt die Kräutervermehrung. Vermehrt wird logistisch: * * Jedes Kraut hat eine Wahrscheinlichkeit von (100-(vorhandene - * Kräuter))% sich zu vermehren. */ + * Kräuter))% sich zu vermehren. */ if (current_season != SEASON_WINTER) { int i; for (i = rherbs(r); i > 0; i--) { @@ -1072,7 +1072,7 @@ int enter_building(unit * u, order * ord, int id, bool report) region *r = u->region; building *b; - /* Schwimmer können keine Gebäude betreten, außer diese sind + /* Schwimmer können keine Gebäude betreten, außer diese sind * auf dem Ozean */ if (!fval(u_race(u), RCF_WALK) && !fval(u_race(u), RCF_FLY)) { if (!fval(r->terrain, SEA_REGION)) { @@ -1188,8 +1188,8 @@ void do_enter(struct region *r, bool is_final_attempt) } if (ulast != NULL) { /* Wenn wir hier angekommen sind, war der Befehl - * erfolgreich und wir löschen ihn, damit er im - * zweiten Versuch nicht nochmal ausgeführt wird. */ + * erfolgreich und wir löschen ihn, damit er im + * zweiten Versuch nicht nochmal ausgeführt wird. */ *ordp = ord->next; ord->next = NULL; free_order(ord); @@ -1963,13 +1963,13 @@ int mail_cmd(unit * u, struct order *ord) s = gettoken(token, sizeof(token)); /* Falls kein Parameter, ist das eine Einheitsnummer; - * das Füllwort "AN" muß wegfallen, da gültige Nummer! */ + * das Füllwort "AN" muss wegfallen, da gültige Nummer! */ do { cont = 0; switch (findparam_ex(s, u->faction->locale)) { case P_REGION: - /* können alle Einheiten in der Region sehen */ + /* können alle Einheiten in der Region sehen */ s = getstrtoken(); if (!s || !s[0]) { cmistake(u, ord, 30, MSG_MESSAGE); @@ -2322,7 +2322,7 @@ static bool display_race(faction * f, unit * u, const race * rc) if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - /* b_armor : Rüstung */ + /* b_armor : Rüstung */ if (rc->armor > 0) { bytes = slprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_armor"), rc->armor); @@ -2633,7 +2633,7 @@ int combatspell_cmd(unit * u, struct order *ord) init_order(ord); s = gettoken(token, sizeof(token)); - /* KAMPFZAUBER [NICHT] löscht alle gesetzten Kampfzauber */ + /* KAMPFZAUBER [NICHT] löscht alle gesetzten Kampfzauber */ if (!s || *s == 0 || findparam(s, u->faction->locale) == P_NOT) { unset_combatspell(u, 0); return 0; @@ -2641,7 +2641,7 @@ int combatspell_cmd(unit * u, struct order *ord) /* Optional: STUFE n */ if (findparam(s, u->faction->locale) == P_LEVEL) { - /* Merken, setzen kommt erst später */ + /* Merken, setzen kommt erst später */ level = getint(); level = _max(0, level); s = gettoken(token, sizeof(token)); @@ -2656,7 +2656,7 @@ int combatspell_cmd(unit * u, struct order *ord) s = gettoken(token, sizeof(token)); if (findparam(s, u->faction->locale) == P_NOT) { - /* KAMPFZAUBER "" NICHT löscht diesen speziellen + /* KAMPFZAUBER "" NICHT löscht diesen speziellen * Kampfzauber */ unset_combatspell(u, sp); return 0; @@ -2671,7 +2671,7 @@ int combatspell_cmd(unit * u, struct order *ord) /* ------------------------------------------------------------- */ /* Beachten: einige Monster sollen auch unbewaffent die Region bewachen - * können */ + * können */ enum { E_GUARD_OK, E_GUARD_UNARMED, E_GUARD_NEWBIE, E_GUARD_FLEEING }; @@ -2733,7 +2733,7 @@ int guard_on_cmd(unit * u, struct order *ord) cmistake(u, ord, 95, MSG_EVENT); } else { - /* Monster der Monsterpartei dürfen immer bewachen */ + /* Monster der Monsterpartei dürfen immer bewachen */ if (is_monsters(u->faction)) { guard(u, GUARD_ALL); } @@ -2767,7 +2767,7 @@ void sinkships(struct region * r) if (!sh->type->construction || sh->size >= sh->type->construction->maxsize) { if (fval(r->terrain, SEA_REGION) && (!enoughsailors(sh, r) || get_captain(sh) == NULL)) { - /* Schiff nicht seetüchtig */ + /* Schiff nicht seetüchtig */ float dmg = get_param_flt(global.parameters, "rules.ship.damage.nocrewocean", 0.30F); @@ -3224,7 +3224,7 @@ static void ageing(void) sp = &(*sp)->next; } - /* Gebäude */ + /* Gebäude */ for (bp = &r->buildings; *bp;) { building *b = *bp; age_building(b); @@ -3430,7 +3430,7 @@ void update_long_order(unit * u) freset(u, UFL_MOVED); freset(u, UFL_LONGACTION); if (hunger) { - /* Hungernde Einheiten führen NUR den default-Befehl aus */ + /* Hungernde Einheiten führen NUR den default-Befehl aus */ set_order(&u->thisorder, default_order(u->faction->locale)); } else { @@ -3451,7 +3451,7 @@ void update_long_order(unit * u) continue; if (is_exclusive(ord)) { - /* Über dieser Zeile nur Befehle, die auch eine idle Faction machen darf */ + /* über dieser Zeile nur Befehle, die auch eine idle Faction machen darf */ if (idle(u->faction)) { set_order(&u->thisorder, default_order(u->faction->locale)); } @@ -3463,13 +3463,13 @@ void update_long_order(unit * u) else { keyword_t keyword = getkeyword(ord); switch (keyword) { - /* Wenn gehandelt wird, darf kein langer Befehl ausgeführt + /* Wenn gehandelt wird, darf kein langer Befehl ausgeführt * werden. Da Handel erst nach anderen langen Befehlen kommt, - * muß das vorher abgefangen werden. Wir merken uns also + * muss das vorher abgefangen werden. Wir merken uns also * hier, ob die Einheit handelt. */ case K_BUY: case K_SELL: - /* Wenn die Einheit handelt, muß der Default-Befehl gelöscht + /* Wenn die Einheit handelt, muss der Default-Befehl gelöscht * werden. * Wird je diese Ausschliesslichkeit aufgehoben, muss man aufpassen * mit der Reihenfolge von Kaufen, Verkaufen etc., damit es Spielern @@ -3479,7 +3479,7 @@ void update_long_order(unit * u) case K_CAST: /* dient dazu, das neben Zaubern kein weiterer Befehl - * ausgeführt werden kann, Zaubern ist ein kurzer Befehl */ + * ausgeführt werden kann, Zaubern ist ein kurzer Befehl */ set_order(&u->thisorder, copy_order(ord)); break; @@ -3492,7 +3492,7 @@ void update_long_order(unit * u) if (hunger) { return; } - /* Wenn die Einheit handelt, muß der Default-Befehl gelöscht + /* Wenn die Einheit handelt, muss der Default-Befehl gelöscht * werden. */ if (trade) { @@ -3568,7 +3568,7 @@ void monthly_healing(void) double healingcurse = 0; if (heal_ct != NULL) { - /* bonus zurücksetzen */ + /* bonus zurücksetzen */ curse *c = get_curse(r->attribs, heal_ct); if (c != NULL) { healingcurse = curse_geteffect(c); @@ -3578,8 +3578,8 @@ void monthly_healing(void) int umhp = unit_max_hp(u) * u->number; double p = 1.0; - /* hp über Maximum bauen sich ab. Wird zb durch Elixier der Macht - * oder verändertes Ausdauertalent verursacht */ + /* hp über Maximum bauen sich ab. Wird zb durch Elixier der Macht + * oder verändertes Ausdauertalent verursacht */ if (u->hp > umhp) { u->hp -= (int)ceil((u->hp - umhp) / 2.0); if (u->hp < umhp) @@ -3606,7 +3606,7 @@ void monthly_healing(void) if (btype == bt_find("inn")) { p *= 1.5; } - /* pro punkt 5% höher */ + /* pro punkt 5% höher */ p *= (1.0 + healingcurse * 0.05); maxheal = p * maxheal; @@ -3618,7 +3618,7 @@ void monthly_healing(void) /* Aufaddieren der geheilten HP. */ u->hp = _min(u->hp + addhp, umhp); - /* soll man an negativer regeneration sterben können? */ + /* soll man an negativer regeneration sterben können? */ assert(u->hp > 0); } } @@ -3665,7 +3665,7 @@ void defaultorders(void) ord->next = NULL; free_order(ord); if (!neworders) { - /* lange Befehle aus orders und old_orders löschen zu gunsten des neuen */ + /* lange Befehle aus orders und old_orders löschen zu gunsten des neuen */ remove_exclusive(&u->orders); remove_exclusive(&u->old_orders); neworders = true; @@ -4548,8 +4548,8 @@ void processorders(void) wormholes_update(); } - /* immer ausführen, wenn neue Sprüche dazugekommen sind, oder sich - * Beschreibungen geändert haben */ + /* immer ausführen, wenn neue Sprüche dazugekommen sind, oder sich + * Beschreibungen geändert haben */ update_spells(); warn_password(); } diff --git a/src/move.c b/src/move.c index 54864b89e..6c11372a3 100644 --- a/src/move.c +++ b/src/move.c @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 1998-2014, Enno Rehling Katja Zedel items, &animals, &acap, &vehicles, &vcap); - /* Man trägt sein eigenes Gewicht plus seine Kapazität! Die Menschen - ** tragen nichts (siehe walkingcapacity). Ein Wagen zählt nur, wenn er + /* Man tr�gt sein eigenes Gewicht plus seine Kapazit�t! Die Menschen + ** tragen nichts (siehe walkingcapacity). Ein Wagen z�hlt nur, wenn er ** von zwei Pferden gezogen wird */ animals = _min(animals, effskill(u, SK_RIDING) * u->number * 2); if (fval(u_race(u), RCF_HORSE)) animals += u->number; - /* maximal diese Pferde können zum Ziehen benutzt werden */ + /* maximal diese Pferde k�nnen zum Ziehen benutzt werden */ vehicles = _min(animals / HORSESNEEDED, vehicles); return vehicles * vcap + animals * acap; @@ -282,7 +282,7 @@ int walkingcapacity(const struct unit *u) people = u->number; } - /* maximal diese Pferde können zum Ziehen benutzt werden */ + /* maximal diese Pferde k�nnen zum Ziehen benutzt werden */ wagen_mit_pferden = _min(vehicles, pferde_fuer_wagen / HORSESNEEDED); n = wagen_mit_pferden * vcap; @@ -295,7 +295,7 @@ int walkingcapacity(const struct unit *u) /* Genug Trolle, um die Restwagen zu ziehen? */ wagen_mit_trollen = _min(u->number / 4, wagen_ohne_pferde); - /* Wagenkapazität hinzuzählen */ + /* Wagenkapazit�t hinzuz�hlen */ n += wagen_mit_trollen * vcap; wagen_ohne_pferde -= wagen_mit_trollen; } @@ -357,16 +357,16 @@ static int canwalk(unit * u) if (walkingcapacity(u) - eff_weight(u) >= 0) return E_CANWALK_OK; - /* Stimmt das Gewicht, impliziert dies hier, daß alle Wagen ohne + /* Stimmt das Gewicht, impliziert dies hier, da� alle Wagen ohne * Zugpferde/-trolle als Fracht aufgeladen wurden: zu viele Pferde hat * die Einheit nicht zum Ziehen benutzt, also nicht mehr Wagen gezogen * als erlaubt. */ if (vehicles > maxwagen) return E_CANWALK_TOOMANYCARTS; - /* Es muß nicht zwingend an den Wagen liegen, aber egal... (man - * könnte z.B. auch 8 Eisen abladen, damit ein weiterer Wagen als - * Fracht draufpaßt) */ + /* Es mu� nicht zwingend an den Wagen liegen, aber egal... (man + * k�nnte z.B. auch 8 Eisen abladen, damit ein weiterer Wagen als + * Fracht draufpa�t) */ return E_CANWALK_TOOHEAVY; } @@ -663,7 +663,7 @@ int check_ship_allowed(struct ship *sh, const region * r) bt_harbour = bt_find("harbour"); if (sh->region && r_insectstalled(r)) { - /* insekten dürfen nicht hier rein. haben wir welche? */ + /* insekten d�rfen nicht hier rein. haben wir welche? */ unit *u; for (u = sh->region->units; u != NULL; u = u->next) { @@ -757,13 +757,13 @@ static void drifting_ships(region * r) sh->flags |= SF_FISHING; } - /* Schiff schon abgetrieben oder durch Zauber geschützt? */ + /* Schiff schon abgetrieben oder durch Zauber gesch�tzt? */ if (!drift || fval(sh, SF_DRIFTED) || is_cursed(sh->attribs, C_SHIP_NODRIFT, 0)) { shp = &sh->next; continue; } - /* Kapitän bestimmen */ + /* Kapit�n bestimmen */ for (captain = r->units; captain; captain = captain->next) { if (captain->ship != sh) continue; @@ -773,8 +773,8 @@ static void drifting_ships(region * r) break; } } - /* Kapitän da? Beschädigt? Genügend Matrosen? - * Genügend leicht? Dann ist alles OK. */ + /* Kapit�n da? Besch�digt? Gen�gend Matrosen? + * Gen�gend leicht? Dann ist alles OK. */ assert(sh->type->construction->improvement == NULL); /* sonst ist construction::size nicht ship_type::maxsize */ if (captain && sh->size == sh->type->construction->maxsize @@ -784,7 +784,7 @@ static void drifting_ships(region * r) } /* Auswahl einer Richtung: Zuerst auf Land, dann - * zufällig. Falls unmögliches Resultat: vergiß es. */ + * zuf�llig. Falls unm�gliches Resultat: vergi� es. */ d_offset = rng_int() % MAXDIRECTIONS; for (d = 0; d != MAXDIRECTIONS; ++d) { region *rn; @@ -1475,12 +1475,12 @@ static void make_route(unit * u, order * ord, region_list ** routep) /** calculate the speed of a unit * - * zu Fuß reist man 1 Region, zu Pferd 2 Regionen. Mit Straßen reist - * man zu Fuß 2, mit Pferden 3 weit. + * zu Fu� reist man 1 Region, zu Pferd 2 Regionen. Mit Stra�en reist + * man zu Fu� 2, mit Pferden 3 weit. * - * Berechnet wird das mit BPs. Zu Fuß hat man 4 BPs, zu Pferd 6. - * Normalerweise verliert man 3 BP pro Region, bei Straßen nur 2 BP. - * Außerdem: Wenn Einheit transportiert, nur halbe BP + * Berechnet wird das mit BPs. Zu Fu� hat man 4 BPs, zu Pferd 6. + * Normalerweise verliert man 3 BP pro Region, bei Stra�en nur 2 BP. + * Au�erdem: Wenn Einheit transportiert, nur halbe BP */ static int movement_speed(unit * u) { @@ -1620,7 +1620,7 @@ static const region_list *travel_route(unit * u, landing = true; } else if ((u_race(u)->flags & RCF_WALK) == 0) { - /* Spezialeinheiten, die nicht laufen können. */ + /* Spezialeinheiten, die nicht laufen k�nnen. */ ADDMSG(&u->faction->msgs, msg_message("detectocean", "unit region", u, next)); break; @@ -1633,7 +1633,7 @@ static const region_list *travel_route(unit * u, } } else { - /* Ozeanfelder können nur von Einheiten mit Schwimmen und ohne + /* Ozeanfelder k�nnen nur von Einheiten mit Schwimmen und ohne * Pferde betreten werden. */ if (!(canswim(u) || canfly(u))) { ADDMSG(&u->faction->msgs, msg_message("detectocean", @@ -1728,7 +1728,7 @@ static const region_list *travel_route(unit * u, walkmode = 2; } - /* Berichte über Durchreiseregionen */ + /* Berichte �ber Durchreiseregionen */ if (mode != TRAVEL_TRANSPORTED) { arg_regions *ar = var_copy_regions(route_begin, steps - 1); @@ -1807,7 +1807,7 @@ buildingtype_exists(const region * r, const building_type * bt, bool working) return false; } -/* Prüft, ob Ablegen von einer Küste in eine der erlaubten Richtungen erfolgt. */ +/* Pr�ft, ob Ablegen von einer K�ste in eine der erlaubten Richtungen erfolgt. */ static bool check_takeoff(ship * sh, region * from, region * to) { @@ -1857,18 +1857,18 @@ sail(unit * u, order * ord, bool move_on_land, region_list ** routep) return; /* Wir suchen so lange nach neuen Richtungen, wie es geht. Diese werden - * dann nacheinander ausgeführt. */ + * dann nacheinander ausgef�hrt. */ k = shipspeed(sh, u); last_point = starting_point; current_point = starting_point; - /* die nächste Region, in die man segelt, wird durch movewhere () aus der + /* die n�chste Region, in die man segelt, wird durch movewhere () aus der * letzten Region bestimmt. * * Anfangen tun wir bei starting_point. next_point ist beim ersten - * Durchlauf schon gesetzt (Parameter!). current_point ist die letzte gültige, + * Durchlauf schon gesetzt (Parameter!). current_point ist die letzte g�ltige, * befahrene Region. */ while (next_point && current_point != next_point && step < k) { @@ -1920,7 +1920,7 @@ sail(unit * u, order * ord, bool move_on_land, region_list ** routep) bool storm = true; int d_offset = rng_int() % MAXDIRECTIONS; direction_t d; - /* Sturm nur, wenn nächste Region Hochsee ist. */ + /* Sturm nur, wenn n�chste Region Hochsee ist. */ for (d = 0; d != MAXDIRECTIONS; ++d) { direction_t dnext = (direction_t)((d + d_offset) % MAXDIRECTIONS); region *rn = rconnect(current_point, dnext); @@ -2056,16 +2056,16 @@ sail(unit * u, order * ord, bool move_on_land, region_list ** routep) sh = NULL; } - /* Nun enthält current_point die Region, in der das Schiff seine Runde - * beendet hat. Wir generieren hier ein Ereignis für den Spieler, das - * ihm sagt, bis wohin er gesegelt ist, falls er überhaupt vom Fleck - * gekommen ist. Das ist nicht der Fall, wenn er von der Küste ins + /* Nun enth�lt current_point die Region, in der das Schiff seine Runde + * beendet hat. Wir generieren hier ein Ereignis f�r den Spieler, das + * ihm sagt, bis wohin er gesegelt ist, falls er �berhaupt vom Fleck + * gekommen ist. Das ist nicht der Fall, wenn er von der K�ste ins * Inland zu segeln versuchte */ if (sh != NULL && fval(sh, SF_MOVED)) { unit *harbourmaster; /* nachdem alle Richtungen abgearbeitet wurden, und alle Einheiten - * transferiert wurden, kann der aktuelle Befehl gelöscht werden. */ + * transferiert wurden, kann der aktuelle Befehl gel�scht werden. */ cycle_route(ord, u, step); set_order(&u->thisorder, NULL); if (!move_on_land) { @@ -2090,7 +2090,7 @@ sail(unit * u, order * ord, bool move_on_land, region_list ** routep) sh = move_ship(sh, starting_point, current_point, *routep); - /* Hafengebühren ? */ + /* Hafengeb�hren ? */ harbourmaster = owner_buildingtyp(current_point, bt_find("harbour")); if (sh && harbourmaster != NULL) { @@ -2438,7 +2438,7 @@ static void piracy_cmd(unit * u, struct order *ord) /* Wenn nicht, sehen wir, ob wir ein Ziel finden. */ if (target_dir == NODIRECTION) { - /* Einheit ist also Kapitän. Jetzt gucken, in wievielen + /* Einheit ist also Kapit�n. Jetzt gucken, in wievielen * Nachbarregionen potentielle Opfer sind. */ for (dir = 0; dir < MAXDIRECTIONS; dir++) { @@ -2497,7 +2497,7 @@ static void piracy_cmd(unit * u, struct order *ord) set_order(&u->thisorder, create_order(K_MOVE, u->faction->locale, "%s", LOC(u->faction->locale, directions[target_dir]))); - /* Bewegung ausführen */ + /* Bewegung ausf�hren */ init_order(u->thisorder); move(u, true); } @@ -2607,7 +2607,7 @@ static int hunt(unit * u, order * ord) /* NACH ignorieren und Parsing initialisieren. */ init_tokens_str(command); getstrtoken(); - /* NACH ausführen */ + /* NACH ausf�hren */ move(u, false); return 1; /* true -> Einheitenliste von vorne durchgehen */ } @@ -2806,7 +2806,7 @@ void movement(void) if (repeat) continue; if (ships == 0) { - /* Abtreiben von beschädigten, unterbemannten, überladenen Schiffen */ + /* Abtreiben von besch�digten, unterbemannten, �berladenen Schiffen */ drifting_ships(r); } r = r->next; From b5ed7c562d20b892e77f29af6e41ae6c67ed0123 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 2 Aug 2015 22:08:35 +0200 Subject: [PATCH 09/17] wait until curse->magician has been resolve()'s before calling effskill() to find f->max_spelllevel. --- src/kernel/save.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/kernel/save.c b/src/kernel/save.c index 3751bea91..114126b0c 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1600,7 +1600,6 @@ int readgame(const char *filename, int backup) while (--p >= 0) { unit *u = read_unit(&gdata); - sc_mage *mage; if (gdata.version < JSON_REPORT_VERSION) { if (u->_name && fval(u->faction, FFL_NPC)) { @@ -1615,21 +1614,6 @@ int readgame(const char *filename, int backup) up = &u->next; update_interval(u->faction, u->region); - mage = get_mage(u); - if (mage) { - faction *f = u->faction; - int skl = effskill(u, SK_MAGIC); - if (!fval(f, FFL_NPC) && f->magiegebiet == M_GRAY) { - log_error("faction %s had magic=gray, fixing (%s)\n", factionname(f), magic_school[mage->magietyp]); - f->magiegebiet = mage->magietyp; - } - if (f->max_spelllevel < skl) { - f->max_spelllevel = skl; - } - if (mage->spellcount < 0) { - mage->spellcount = 0; - } - } } } log_printf(stdout, "\n"); @@ -1653,6 +1637,7 @@ int readgame(const char *filename, int backup) for (f = factions; f; f = f->next) { if (f->flags & FFL_NPC) { f->alive = 1; + f->magiegebiet = M_GRAY; if (f->no == 0) { int no = 666; while (findfaction(no)) @@ -1663,8 +1648,23 @@ int readgame(const char *filename, int backup) } else { for (u = f->units; u; u = u->nextF) { + sc_mage *mage = get_mage(u); + if (mage) { + faction *f = u->faction; + int skl = effskill(u, SK_MAGIC); + if (f->magiegebiet == M_GRAY) { + log_error("faction %s had magic=gray, fixing (%s)\n", factionname(f), magic_school[mage->magietyp]); + f->magiegebiet = mage->magietyp; + } + if (f->max_spelllevel < skl) { + f->max_spelllevel = skl; + } + if (mage->spellcount < 0) { + mage->spellcount = 0; + } + } if (u->number > 0) { - f->alive = 1; + f->alive = true; break; } } From d99ffaf1ed3e011104e8bc88e7178d7e965c703f Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 2 Aug 2015 22:45:59 +0200 Subject: [PATCH 10/17] filter by curse-type before trying to call update_gbdreams. --- src/kernel/unit.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 7a992563f..c5c60d08d 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -1274,18 +1274,16 @@ static int item_modification(const unit * u, skill_t sk, int val) return val; } -static int update_gbdream(const unit * u, int bonus, curse *c, const curse_type *gbdream_ct, int sign){ - if (curse_active(c) && c->type == gbdream_ct) { - double effect = curse_geteffect(c); - unit *mage = c->magician; - /* wir suchen jeweils den groessten Bonus und den groessten Malus */ - if (sign * effect > sign * bonus) { - bool allied; - assert(mage && mage->number > 0); - allied = alliedunit(mage, u->faction, HELP_GUARD); - if ((sign>0)?allied:!allied) { - bonus = (int)effect; - } +static int update_gbdream(const unit * u, int bonus, curse *c, int sign) { + double effect = curse_geteffect(c); + unit *mage = c->magician; + /* wir suchen jeweils den groessten Bonus und den groessten Malus */ + if (sign * effect > sign * bonus) { + bool allied; + assert(mage && mage->number > 0); + allied = alliedunit(mage, u->faction, HELP_GUARD); + if ((sign>0)?allied:!allied) { + bonus = (int)effect; } } return bonus; @@ -1294,7 +1292,7 @@ static int update_gbdream(const unit * u, int bonus, curse *c, const curse_type int att_modification(const unit * u, skill_t sk) { double result = 0; - static bool init = false; + static bool init = false; // TODO: static variables are bad global state static const curse_type *skillmod_ct, *gbdream_ct, *worse_ct; curse *c; @@ -1329,9 +1327,11 @@ int att_modification(const unit * u, skill_t sk) while (a && a->type == &at_curse) { curse *c = (curse *)a->data.v; - assert(c->magician); // update_gbdream makes no sense if there is no caster (calls alliedunit) - bonus = update_gbdream(u, bonus, c, gbdream_ct, 1); - malus = update_gbdream(u, malus, c, gbdream_ct, -1); + if (curse_active(c) && c->type == gbdream_ct) { + assert(c->magician); // update_gbdream makes no sense if there is no caster (calls alliedunit) + bonus = update_gbdream(u, bonus, c, 1); + malus = update_gbdream(u, malus, c, -1); + } a = a->next; } result = result + bonus + malus; From 9938b3fb66d59d854ac69dce6325c840c85ab65d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 2 Aug 2015 23:15:13 +0200 Subject: [PATCH 11/17] eliminate update_gbdream completely, make code smaller and simpler. simplify tests (no need to use create_spell if we don't use it) increase build no for hotfix. --- src/buildno.h | 2 +- src/kernel/unit.c | 29 +++++++++-------------------- src/spells.test.c | 15 ++++++--------- 3 files changed, 16 insertions(+), 30 deletions(-) diff --git a/src/buildno.h b/src/buildno.h index 813baf03b..a8118b327 100644 --- a/src/buildno.h +++ b/src/buildno.h @@ -1,3 +1,3 @@ #define VERSION_MAJOR 3 #define VERSION_MINOR 5 -#define VERSION_BUILD 3 +#define VERSION_BUILD 4 diff --git a/src/kernel/unit.c b/src/kernel/unit.c index c5c60d08d..3a07344af 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -1274,22 +1274,7 @@ static int item_modification(const unit * u, skill_t sk, int val) return val; } -static int update_gbdream(const unit * u, int bonus, curse *c, int sign) { - double effect = curse_geteffect(c); - unit *mage = c->magician; - /* wir suchen jeweils den groessten Bonus und den groessten Malus */ - if (sign * effect > sign * bonus) { - bool allied; - assert(mage && mage->number > 0); - allied = alliedunit(mage, u->faction, HELP_GUARD); - if ((sign>0)?allied:!allied) { - bonus = (int)effect; - } - } - return bonus; -} - -int att_modification(const unit * u, skill_t sk) +static int att_modification(const unit * u, skill_t sk) { double result = 0; static bool init = false; // TODO: static variables are bad global state @@ -1321,16 +1306,20 @@ int att_modification(const unit * u, skill_t sk) /* TODO hier kann nicht mit get/iscursed gearbeitet werden, da nur der * jeweils erste vom Typ C_GBDREAM zurueckgegen wird, wir aber alle * durchsuchen und aufaddieren muessen */ - if (u->region) { + if (gbdream_ct && u->region) { int bonus = 0, malus = 0; attrib *a = a_find(u->region->attribs, &at_curse); while (a && a->type == &at_curse) { curse *c = (curse *)a->data.v; if (curse_active(c) && c->type == gbdream_ct) { - assert(c->magician); // update_gbdream makes no sense if there is no caster (calls alliedunit) - bonus = update_gbdream(u, bonus, c, 1); - malus = update_gbdream(u, malus, c, -1); + int effect = curse_geteffect_int(c); + bool allied = alliedunit(c->magician, u->faction, HELP_GUARD); + if (allied) { + if (effect > bonus) bonus = effect; + } else { + if (effect < malus) malus = effect; + } } a = a->next; } diff --git a/src/spells.test.c b/src/spells.test.c index ff67dd58d..5ecb8bd88 100644 --- a/src/spells.test.c +++ b/src/spells.test.c @@ -20,13 +20,10 @@ #include -static struct castorder *test_create_castorder(castorder *order, unit *u, const char *name, int level, float force, int range) { +static void test_create_castorder(castorder *order, unit *u, int level, float force, int range) { struct locale * lang; - spell *sp; - lang = get_or_create_locale("en"); - sp = create_spell(name, 0); - return order = create_castorder(order, u, NULL, sp, u->region, level, force, range, create_order(K_CAST, lang, ""), NULL); + create_castorder(order, u, NULL, NULL, u->region, level, force, range, create_order(K_CAST, lang, ""), NULL); } static void test_dreams(CuTest *tc) { @@ -39,12 +36,12 @@ static void test_dreams(CuTest *tc) { test_cleanup(); test_create_world(); r=findregion(0, 0); - f1 = test_create_faction(test_create_race("human")); - f2 = test_create_faction(test_create_race("human")); + f1 = test_create_faction(0); + f2 = test_create_faction(0); u1 = test_create_unit(f1, r); u2 = test_create_unit(f2, r); - test_create_castorder(&order, u1, "goodreams", 10, 10., 0); + test_create_castorder(&order, u1, 10, 10., 0); level = sp_gooddreams(&order); CuAssertIntEquals(tc, 10, level); @@ -57,7 +54,7 @@ static void test_dreams(CuTest *tc) { CuAssertIntEquals(tc, 1, get_modifier(u1, SK_MELEE, 11, r, false)); CuAssertIntEquals(tc, 0, get_modifier(u2, SK_MELEE, 11, r, false)); - test_create_castorder(&order, u1, "baddreams", 10, 10., 0); + test_create_castorder(&order, u1, 10, 10., 0); level = sp_baddreams(&order); CuAssertIntEquals(tc, 10, level); From 57bb4a49f112f9f82bad75929f4e3d937b77db92 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 4 Aug 2015 10:25:57 +0200 Subject: [PATCH 12/17] fix git submodule urls (badgerman->ennorehling) and iniparser --- .gitmodules | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/.gitmodules b/.gitmodules index 2848986e4..7c4dc3765 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,28 +1,31 @@ [submodule "lunit"] path = lunit - url = git://github.com/badgerman/lunit.git + url = git://github.com/ennorehling/lunit.git [submodule "crypto"] path = crypto - url = git://github.com/badgerman/crypto.git + url = git://github.com/ennorehling/crypto.git [submodule "cmake"] path = cmake - url = git://github.com/badgerman/cmake.git + url = git://github.com/ennorehling/cmake.git [submodule "quicklist"] path = quicklist - url = git://github.com/badgerman/quicklist.git + url = git://github.com/ennorehling/quicklist.git [submodule "critbit"] path = critbit - url = git://github.com/badgerman/critbit.git + url = git://github.com/ennorehling/critbit.git [submodule "dlmalloc"] path = dlmalloc - url = git://github.com/badgerman/dlmalloc.git + url = git://github.com/ennorehling/dlmalloc.git [submodule "cutest"] path = cutest - url = git://github.com/badgerman/cutest.git + url = git://github.com/ennorehling/cutest.git [submodule "cJSON"] path = cJSON - url = git://github.com/badgerman/cJSON.git + url = git://github.com/ennorehling/cJSON.git +[submodule "iniparser"] + path = iniparser + url = git://github.com/ennorehling/iniparser.git [submodule "storage"] path = storage - url = git://github.com/badgerman/storage.git + url = git://github.com/ennorehling/storage.git branch = master From 4d061d8592295e75dcdaaf9074dcf82a847d9a69 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 4 Aug 2015 22:47:55 +0200 Subject: [PATCH 13/17] repair update_long_order and K_DESTROY handling according to discussion in https://bugs.eressea.de/view.php?id=2080 --- res/core/messages.xml | 11 --- scripts/eressea/jsreport.lua | 2 - src/battle.c | 2 +- src/creport.c | 3 +- src/economy.c | 31 ++----- src/kernel/build.c | 16 ++-- src/kernel/config.c | 5 -- src/kernel/config.h | 1 - src/kernel/order.c | 9 +- src/kernel/order.h | 4 +- src/kernel/save.c | 6 +- src/laws.c | 170 +++++++++++++++-------------------- src/report.c | 7 +- src/reports.c | 6 +- 14 files changed, 109 insertions(+), 164 deletions(-) diff --git a/res/core/messages.xml b/res/core/messages.xml index 4e78fc094..237ab8c7a 100644 --- a/res/core/messages.xml +++ b/res/core/messages.xml @@ -2830,17 +2830,6 @@ "$unit($unit) in $region($region) produziert $int($amount)$if($eq($wanted,$amount),""," von $int($wanted)") $resource($resource,$wanted)." "$unit($unit) in $region($region) produces $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") $resource($resource,$amount)." - - - - - - - - - "$unit($unit) in $region($region) produziert $int($amount)$if($eq($wanted,$amount),""," von $int($wanted)") $resource($resource,$wanted)." - "$unit($unit) in $region($region) produces $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") $resource($resource,$amount)." - diff --git a/scripts/eressea/jsreport.lua b/scripts/eressea/jsreport.lua index 442b27d5f..0351efd12 100644 --- a/scripts/eressea/jsreport.lua +++ b/scripts/eressea/jsreport.lua @@ -1,7 +1,5 @@ local pkg = {} -print("loading jsreport module") - function pkg.init() eressea.settings.set("feature.jsreport.enable", "1") end diff --git a/src/battle.c b/src/battle.c index 4719da5b7..d45cf02e7 100644 --- a/src/battle.c +++ b/src/battle.c @@ -3232,7 +3232,7 @@ fighter *make_fighter(battle * b, unit * u, side * s1, bool attack) } /* Illusionen und Zauber kaempfen nicht */ - if (fval(u_race(u), RCF_ILLUSIONARY) || idle(u->faction) || u->number == 0) { + if (fval(u_race(u), RCF_ILLUSIONARY) || u->number == 0) { return NULL; } if (s1 == NULL) { diff --git a/src/creport.c b/src/creport.c index 38e63e299..fefd7934e 100644 --- a/src/creport.c +++ b/src/creport.c @@ -929,7 +929,8 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f, } } for (ord = u->orders; ord; ord = ord->next) { - if (u->old_orders && is_repeated(ord)) + keyword_t kwd = getkeyword(ord); + if (u->old_orders && is_repeated(kwd)) continue; /* unit has defaults */ if (is_persistent(ord)) { fwriteorder(F, ord, f->locale, true); diff --git a/src/economy.c b/src/economy.c index 23ccb3fde..8cf46845b 100644 --- a/src/economy.c +++ b/src/economy.c @@ -563,7 +563,7 @@ static void recruit(unit * u, struct order *ord, request ** recruitorders) return; } } - if (!playerrace(rc) || idle(u->faction)) { + if (!playerrace(rc)) { cmistake(u, ord, 139, MSG_EVENT); return; } @@ -979,26 +979,13 @@ void economics(region * r) remove_empty_units_in_region(r); for (u = r->units; u; u = u->next) { - order *ord; - bool destroyed = false; - if (u->number > 0) { - for (ord = u->orders; ord; ord = ord->next) { - keyword_t kwd = getkeyword(ord); - if (kwd == K_DESTROY) { - if (!destroyed) { - if (destroy_cmd(u, ord) != 0) - ord = NULL; - destroyed = true; - } - } - if (u->orders == NULL) { - break; - } + order *ord = u->thisorder; + keyword_t kwd = getkeyword(ord); + if (kwd == K_DESTROY) { + if (destroy_cmd(u, ord) == 0) { + fset(u, UFL_LONGACTION | UFL_NOTMOVING); } } - if (destroyed) { - fset(u, UFL_LONGACTION | UFL_NOTMOVING); - } } } @@ -1051,7 +1038,7 @@ static void manufacture(unit * u, const item_type * itype, int want) i_change(&u->items, itype, n); if (want == INT_MAX) want = n; - ADDMSG(&u->faction->msgs, msg_message("manufacture", + ADDMSG(&u->faction->msgs, msg_message("produce", "unit region amount wanted resource", u, u->region, n, want, itype->rtype)); } @@ -1466,7 +1453,7 @@ static void create_potion(unit * u, const potion_type * ptype, int want) i_change(&u->items, ptype->itype, built); if (want == INT_MAX) want = built; - ADDMSG(&u->faction->msgs, msg_message("manufacture", + ADDMSG(&u->faction->msgs, msg_message("produce", "unit region amount wanted resource", u, u->region, built, want, ptype->itype->rtype)); break; @@ -3216,7 +3203,7 @@ void produce(struct region *r) continue; if (fval(u, UFL_LONGACTION) && u->thisorder == NULL) { - /* this message was already given in laws.setdefaults + /* this message was already given in laws.c:update_long_order cmistake(u, u->thisorder, 52, MSG_PRODUCE); */ continue; diff --git a/src/kernel/build.c b/src/kernel/build.c index fcb116741..37006e968 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -151,11 +151,11 @@ int destroy_cmd(unit * u, struct order *ord) int n = INT_MAX; if (u->number < 1) - return 0; + return 1; if (fval(u, UFL_LONGACTION)) { cmistake(u, ord, 52, MSG_PRODUCE); - return 0; + return 52; } init_order(ord); @@ -183,11 +183,11 @@ int destroy_cmd(unit * u, struct order *ord) if (u != building_owner(b)) { cmistake(u, ord, 138, MSG_PRODUCE); - return 0; + return 138; } if (fval(b->type, BTF_INDESTRUCTIBLE)) { cmistake(u, ord, 138, MSG_PRODUCE); - return 0; + return 138; } if (n >= b->size) { /* destroy completly */ @@ -213,11 +213,11 @@ int destroy_cmd(unit * u, struct order *ord) if (u != ship_owner(sh)) { cmistake(u, ord, 138, MSG_PRODUCE); - return 0; + return 138; } if (fval(r->terrain, SEA_REGION)) { cmistake(u, ord, 14, MSG_EVENT); - return 0; + return 14; } if (n >= (sh->size * 100) / sh->type->construction->maxsize) { @@ -242,11 +242,11 @@ int destroy_cmd(unit * u, struct order *ord) } else { cmistake(u, ord, 138, MSG_PRODUCE); - return 0; + return 138; } if (con) { - /* TODO: Nicht an ZERSTÖRE mit Punktangabe angepaßt! */ + /* TODO: Nicht an ZERSTÖRE mit Punktangabe angepasst! */ int c; for (c = 0; con->materials[c].number; ++c) { const requirement *rq = con->materials + c; diff --git a/src/kernel/config.c b/src/kernel/config.c index 699044520..ece8ca72f 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -906,11 +906,6 @@ int newcontainerid(void) return random_no; } -bool idle(faction * f) -{ - return (bool)(f ? false : true); -} - int maxworkingpeasants(const struct region *r) { int size = production(r); diff --git a/src/kernel/config.h b/src/kernel/config.h index 4ca76871c..62fa2d4d6 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -179,7 +179,6 @@ extern "C" { bool has_limited_skills(const struct unit *u); const struct race *findrace(const char *, const struct locale *); - bool idle(struct faction *f); bool unit_has_cursed_item(const struct unit *u); /* grammatik-flags: */ diff --git a/src/kernel/order.c b/src/kernel/order.c index 20cce5853..08d16088f 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -389,9 +389,8 @@ order *parse_order(const char *s, const struct locale * lang) * \return true if the order is long * \sa is_exclusive(), is_repeated(), is_persistent() */ -bool is_repeated(const order * ord) +bool is_repeated(keyword_t kwd) { - keyword_t kwd = ORD_KEYWORD(ord); switch (kwd) { case K_CAST: case K_BUY: @@ -468,10 +467,8 @@ bool is_exclusive(const order * ord) * \return true if the order is long * \sa is_exclusive(), is_repeated(), is_persistent() */ -bool is_long(const order * ord) +bool is_long(keyword_t kwd) { - keyword_t kwd = ORD_KEYWORD(ord); - switch (kwd) { case K_CAST: case K_BUY: @@ -522,7 +519,7 @@ bool is_persistent(const order * ord) case K_KOMMENTAR: return true; default: - return ord->_persistent || is_repeated(ord); + return ord->_persistent || is_repeated(kwd); } } diff --git a/src/kernel/order.h b/src/kernel/order.h index 27c61681c..75d741e42 100644 --- a/src/kernel/order.h +++ b/src/kernel/order.h @@ -55,8 +55,8 @@ extern "C" { char* get_command(const order *ord, char *buffer, size_t size); bool is_persistent(const order * ord); bool is_exclusive(const order * ord); - bool is_repeated(const order * ord); - bool is_long(const order * ord); + bool is_repeated(keyword_t kwd); + bool is_long(keyword_t kwd); char *write_order(const order * ord, char *buffer, size_t size); keyword_t init_order(const struct order *ord); diff --git a/src/kernel/save.c b/src/kernel/save.c index fba9b6083..1d610d013 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -139,7 +139,8 @@ static unit *unitorders(FILE * F, int enc, struct faction *f) ordp = &u->old_orders; while (*ordp) { order *ord = *ordp; - if (!is_repeated(ord)) { + keyword_t kwd = getkeyword(ord); + if (!is_repeated(kwd)) { *ordp = ord->next; ord->next = NULL; free_order(ord); @@ -777,7 +778,8 @@ void write_unit(struct gamedata *data, const unit * u) } } for (ord = u->orders; ord; ord = ord->next) { - if (u->old_orders && is_repeated(ord)) + keyword_t kwd = getkeyword(ord); + if (u->old_orders && is_repeated(kwd)) continue; /* has new defaults */ if (is_persistent(ord)) { if (++p < MAXPERSISTENT) { diff --git a/src/laws.c b/src/laws.c index 76658a2e3..40ffac896 100755 --- a/src/laws.c +++ b/src/laws.c @@ -3407,126 +3407,101 @@ void new_units(void) } } -/** Checks for two long orders and issues a warning if necessary. - */ -void check_long_orders(unit * u) -{ - order *ord; - keyword_t otherorder = MAXKEYWORDS; - - for (ord = u->orders; ord; ord = ord->next) { - if (getkeyword(ord) == NOKEYWORD) { - cmistake(u, ord, 22, MSG_EVENT); - } - else if (is_long(ord)) { - keyword_t longorder = getkeyword(ord); - if (otherorder != MAXKEYWORDS) { - switch (longorder) { - case K_CAST: - if (otherorder != longorder) { - cmistake(u, ord, 52, MSG_EVENT); - } - break; - case K_BUY: - if (otherorder == K_SELL) { - otherorder = K_BUY; - } - else { - cmistake(u, ord, 52, MSG_EVENT); - } - break; - case K_SELL: - if (otherorder != K_SELL && otherorder != K_BUY) { - cmistake(u, ord, 52, MSG_EVENT); - } - break; - default: - cmistake(u, ord, 52, MSG_EVENT); - } - } - else { - otherorder = longorder; - } - } - } -} - void update_long_order(unit * u) { order *ord; - bool trade = false; + bool exclusive = true; + keyword_t thiskwd = NOKEYWORD; bool hunger = LongHunger(u); freset(u, UFL_MOVED); freset(u, UFL_LONGACTION); - if (hunger) { - /* Hungernde Einheiten führen NUR den default-Befehl aus */ - set_order(&u->thisorder, default_order(u->faction->locale)); - } - else { - check_long_orders(u); - } + /* check all orders for a potential new long order this round: */ for (ord = u->orders; ord; ord = ord->next) { - if (getkeyword(ord) == NOKEYWORD) - continue; + keyword_t kwd = getkeyword(ord); + if (kwd == NOKEYWORD) continue; - if (u->old_orders && is_repeated(ord)) { + if (u->old_orders && is_repeated(kwd)) { /* this new order will replace the old defaults */ free_orders(&u->old_orders); - if (hunger) - break; } - if (hunger) - continue; - if (is_exclusive(ord)) { - /* Ãœber dieser Zeile nur Befehle, die auch eine idle Faction machen darf */ - if (idle(u->faction)) { - set_order(&u->thisorder, default_order(u->faction->locale)); - } - else { - set_order(&u->thisorder, copy_order(ord)); + // hungry units do not get long orders: + if (hunger) { + if (u->old_orders) { + // keep looking for repeated orders that might clear the old_orders + continue; } break; } - else { - keyword_t keyword = getkeyword(ord); - switch (keyword) { - /* Wenn gehandelt wird, darf kein langer Befehl ausgeführt - * werden. Da Handel erst nach anderen langen Befehlen kommt, - * muss das vorher abgefangen werden. Wir merken uns also - * hier, ob die Einheit handelt. */ - case K_BUY: - case K_SELL: - /* Wenn die Einheit handelt, muss der Default-Befehl gelöscht - * werden. - * Wird je diese Ausschliesslichkeit aufgehoben, muss man aufpassen - * mit der Reihenfolge von Kaufen, Verkaufen etc., damit es Spielern - * nicht moeglich ist, Schulden zu machen. */ - trade = true; - break; - case K_CAST: - /* dient dazu, das neben Zaubern kein weiterer Befehl - * ausgeführt werden kann, Zaubern ist ein kurzer Befehl */ - set_order(&u->thisorder, copy_order(ord)); - break; + if (is_long(kwd)) { + if (thiskwd == NOKEYWORD) { + // we have found the (first) long order + // some long orders can have multiple instances: + switch (kwd) { + /* Wenn gehandelt wird, darf kein langer Befehl ausgeführt + * werden. Da Handel erst nach anderen langen Befehlen kommt, + * muss das vorher abgefangen werden. Wir merken uns also + * hier, ob die Einheit handelt. */ + case K_BUY: + case K_SELL: + case K_CAST: + // non-exclusive orders can be used with others. BUY can be paired with SELL, + // CAST with other CAST orders. compatibility is checked once the second + // long order is analyzed (below). + exclusive = false; + break; - default: - break; + default: + set_order(&u->thisorder, copy_order(ord)); + break; + } + thiskwd = kwd; + } + else { + // we have found a second long order. this is okay for some, but not all commands. + // u->thisorder is already set, and should not have to be updated. + switch (kwd) { + case K_CAST: + if (thiskwd != K_CAST) { + cmistake(u, ord, 52, MSG_EVENT); + } + break; + case K_SELL: + if (thiskwd != K_SELL && thiskwd != K_BUY) { + cmistake(u, ord, 52, MSG_EVENT); + } + break; + case K_BUY: + if (thiskwd != K_SELL) { + cmistake(u, ord, 52, MSG_EVENT); + } + else { + thiskwd = K_BUY; + } + break; + default: +#ifdef TODO // TODO: decide https://bugs.eressea.de/view.php?id=2080#c6011 + if (kwd < thiskwd) { + /* swap thisorder for the new one */ + order *tmp = ord; + ord = u->thisorder; + u->thisorder = tmp; + } +#endif + cmistake(u, ord, 52, MSG_EVENT); + break; + } } } } - if (hunger) { - return; - } - /* Wenn die Einheit handelt, muss der Default-Befehl gelöscht - * werden. */ - - if (trade) { - /* fset(u, UFL_LONGACTION|UFL_NOTMOVING); */ + // Hungernde Einheiten führen NUR den default-Befehl aus + set_order(&u->thisorder, default_order(u->faction->locale)); + } else if (!exclusive) { + // Wenn die Einheit handelt oder zaubert, muss der Default-Befehl gelöscht werden. set_order(&u->thisorder, NULL); } } @@ -3696,6 +3671,7 @@ void defaultorders(void) free_order(ord); if (!neworders) { /* lange Befehle aus orders und old_orders löschen zu gunsten des neuen */ + // TODO: why only is_exclusive, not is_long? what about CAST, BUY, SELL? remove_exclusive(&u->orders); remove_exclusive(&u->old_orders); neworders = true; diff --git a/src/report.c b/src/report.c index 0b591b5ed..3d57ee4c2 100644 --- a/src/report.c +++ b/src/report.c @@ -1471,14 +1471,12 @@ report_template(const char *filename, report_context * ctx, const char *charset) newline(out); newline(out); - sprintf(buf, "%s %s \"%s\"", LOC(f->locale, "ERESSEA"), factionid(f), - LOC(f->locale, "enterpasswd")); + sprintf(buf, "%s %s \"%s\"", LOC(f->locale, "ERESSEA"), factionid(f), f->passw); rps_nowrap(out, buf); newline(out); newline(out); sprintf(buf, "; ECHECK -l -w4 -r%d -v%s", f->race->recruitcost, ECHECK_VERSION); - /* -v3.4: ECheck Version 3.4.x */ rps_nowrap(out, buf); newline(out); @@ -1575,7 +1573,8 @@ report_template(const char *filename, report_context * ctx, const char *charset) newline(out); } for (ord = u->orders; ord; ord = ord->next) { - if (u->old_orders && is_repeated(ord)) + keyword_t kwd = getkeyword(ord); + if (u->old_orders && is_repeated(kwd)) continue; /* unit has defaults */ if (is_persistent(ord)) { strcpy(buf, " "); diff --git a/src/reports.c b/src/reports.c index 128815f71..88b11e31d 100644 --- a/src/reports.c +++ b/src/reports.c @@ -793,7 +793,8 @@ size_t size) bool printed = 0; order *ord;; for (ord = u->old_orders; ord; ord = ord->next) { - if (is_repeated(ord)) { + keyword_t kwd = getkeyword(ord); + if (is_repeated(kwd)) { if (printed < ORDERS_IN_NR) { bytes = buforder(bufp, size, ord, printed++); if (wrptr(&bufp, &size, bytes) != 0) @@ -805,7 +806,8 @@ size_t size) } if (printed < ORDERS_IN_NR) for (ord = u->orders; ord; ord = ord->next) { - if (is_repeated(ord)) { + keyword_t kwd = getkeyword(ord); + if (is_repeated(kwd)) { if (printed < ORDERS_IN_NR) { bytes = buforder(bufp, size, ord, printed++); if (wrptr(&bufp, &size, bytes) != 0) From 928b9966d00af9cc9182e2b42f6b105c20957b14 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 4 Aug 2015 23:04:00 +0200 Subject: [PATCH 14/17] fix broken test (select DESTROY over MOVE), start writing unit tests for update_long_order --- src/laws.c | 16 ++++++++-------- src/laws.test.c | 13 +++++++++++++ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/laws.c b/src/laws.c index 40ffac896..b9df102cd 100755 --- a/src/laws.c +++ b/src/laws.c @@ -3483,15 +3483,15 @@ void update_long_order(unit * u) } break; default: -#ifdef TODO // TODO: decide https://bugs.eressea.de/view.php?id=2080#c6011 - if (kwd < thiskwd) { - /* swap thisorder for the new one */ - order *tmp = ord; - ord = u->thisorder; - u->thisorder = tmp; + // TODO: decide https://bugs.eressea.de/view.php?id=2080#c6011 + if (kwd > thiskwd) { + // swap out thisorder for the new one + cmistake(u, u->thisorder, 52, MSG_EVENT); + set_order(&u->thisorder, copy_order(ord)); + } + else { + cmistake(u, ord, 52, MSG_EVENT); } -#endif - cmistake(u, ord, 52, MSG_EVENT); break; } } diff --git a/src/laws.test.c b/src/laws.test.c index b5429e1aa..b6b13d37c 100644 --- a/src/laws.test.c +++ b/src/laws.test.c @@ -768,9 +768,22 @@ static void test_luck_message(CuTest *tc) { test_cleanup(); } +static void test_update_long_order(CuTest *tc) { + // TODO: write more tests + unit *u; + test_cleanup(); + u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + update_long_order(u); + CuAssertPtrEquals(tc, 0, u->thisorder); + CuAssertPtrEquals(tc, 0, u->orders); + CuAssertPtrEquals(tc, 0, u->old_orders); + test_cleanup(); +} + CuSuite *get_laws_suite(void) { CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_update_long_order); SUITE_ADD_TEST(suite, test_new_building_can_be_renamed); SUITE_ADD_TEST(suite, test_rename_building); SUITE_ADD_TEST(suite, test_rename_building_twice); From c22636ca13f1c7c10089b2f31dffbbdd55eda39d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 5 Aug 2015 00:03:30 +0200 Subject: [PATCH 15/17] unit tests for update_long_order. e3 tests are still broken. --- src/kernel/config.c | 10 ++++ src/kernel/config.h | 3 + src/kernel/order.c | 22 +++++++- src/laws.test.c | 130 +++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 160 insertions(+), 5 deletions(-) diff --git a/src/kernel/config.c b/src/kernel/config.c index ece8ca72f..8698fde51 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -1681,6 +1681,11 @@ void kernel_init(void) } static order * defaults[MAXLOCALES]; +keyword_t default_keyword = NOKEYWORD; + +void set_default_order(int kwd) { + default_keyword = (keyword_t)kwd; +} order *default_order(const struct locale *lang) { @@ -1688,6 +1693,11 @@ order *default_order(const struct locale *lang) int i = locale_index(lang); order *result = 0; assert(i < MAXLOCALES); + + if (default_keyword!=NOKEYWORD) { + return create_order(default_keyword, lang, 0); + } + result = defaults[i]; if (!result && usedefault) { const char * str = LOC(lang, "defaultorder"); diff --git a/src/kernel/config.h b/src/kernel/config.h index 62fa2d4d6..5e7e77899 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -286,7 +286,10 @@ extern "C" { int AllianceAuto(void); /* flags that allied factions get automatically */ int AllianceRestricted(void); /* flags restricted to allied factions */ int HelpMask(void); /* flags restricted to allied factions */ + struct order *default_order(const struct locale *lang); + void set_default_order(int kwd); + int entertainmoney(const struct region *r); void free_gamedata(void); diff --git a/src/kernel/order.c b/src/kernel/order.c index 08d16088f..008bfe0fe 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -252,6 +252,19 @@ static order_data *create_data(keyword_t kwd, const char *sptr, int lindex) return data; } +static void free_localedata(int lindex) { + int i; + for (i = 0; i != MAXKEYWORDS; ++i) { + release_data(locale_array[lindex]->short_orders[i]); + locale_array[lindex]->short_orders[i] = 0; + } + for (i = 0; i != MAXSKILLS; ++i) { + release_data(locale_array[lindex]->study_orders[i]); + locale_array[lindex]->study_orders[i] = 0; + } + locale_array[lindex]->lang = 0; +} + static order *create_order_i(keyword_t kwd, const char *sptr, bool persistent, const struct locale *lang) { @@ -276,7 +289,12 @@ static order *create_order_i(keyword_t kwd, const char *sptr, bool persistent, lindex = locale_index(lang); assert(lindex < MAXLOCALES); - locale_array[lindex] = (locale_data *)calloc(1, sizeof(locale_data)); + if (!locale_array[lindex]) { + locale_array[lindex] = (locale_data *)calloc(1, sizeof(locale_data)); + } + else if (locale_array[lindex]->lang != lang) { + free_localedata(lindex); + } locale_array[lindex]->lang = lang; ord = (order *)malloc(sizeof(order)); @@ -292,13 +310,13 @@ order *create_order(keyword_t kwd, const struct locale * lang, const char *params, ...) { char zBuffer[DISPLAYSIZE]; - assert(lang); if (params) { char *bufp = zBuffer; int bytes; size_t size = sizeof(zBuffer) - 1; va_list marker; + assert(lang); va_start(marker, params); while (*params) { if (*params == '%') { diff --git a/src/laws.test.c b/src/laws.test.c index b6b13d37c..900336d5c 100644 --- a/src/laws.test.c +++ b/src/laws.test.c @@ -768,22 +768,146 @@ static void test_luck_message(CuTest *tc) { test_cleanup(); } -static void test_update_long_order(CuTest *tc) { +static void test_long_order_normal(CuTest *tc) { + // TODO: write more tests + unit *u; + order *ord; + test_cleanup(); + u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + fset(u, UFL_MOVED); + fset(u, UFL_LONGACTION); + u->faction->locale = get_or_create_locale("de"); + ord = create_order(K_MOVE, u->faction->locale, 0); + unit_addorder(u, ord); + update_long_order(u); + CuAssertPtrEquals(tc, ord->data, u->thisorder->data); + CuAssertIntEquals(tc, 0, fval(u, UFL_MOVED)); + CuAssertIntEquals(tc, 0, fval(u, UFL_LONGACTION)); + CuAssertPtrNotNull(tc, u->orders); + CuAssertPtrEquals(tc, 0, u->faction->msgs); + CuAssertPtrEquals(tc, 0, u->old_orders); + test_cleanup(); +} + +static void test_long_order_none(CuTest *tc) { // TODO: write more tests unit *u; test_cleanup(); u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u->faction->locale = get_or_create_locale("de"); update_long_order(u); CuAssertPtrEquals(tc, 0, u->thisorder); CuAssertPtrEquals(tc, 0, u->orders); - CuAssertPtrEquals(tc, 0, u->old_orders); + CuAssertPtrEquals(tc, 0, u->faction->msgs); + test_cleanup(); +} + +static void test_long_order_cast(CuTest *tc) { + // TODO: write more tests + unit *u; + test_cleanup(); + u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u->faction->locale = get_or_create_locale("de"); + unit_addorder(u, create_order(K_CAST, u->faction->locale, 0)); + unit_addorder(u, create_order(K_CAST, u->faction->locale, 0)); + update_long_order(u); + CuAssertPtrEquals(tc, 0, u->thisorder); + CuAssertPtrNotNull(tc, u->orders); + CuAssertPtrEquals(tc, 0, u->faction->msgs); + test_cleanup(); +} + +static void test_long_order_buy_sell(CuTest *tc) { + // TODO: write more tests + unit *u; + test_cleanup(); + u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u->faction->locale = get_or_create_locale("de"); + unit_addorder(u, create_order(K_BUY, u->faction->locale, 0)); + unit_addorder(u, create_order(K_SELL, u->faction->locale, 0)); + unit_addorder(u, create_order(K_SELL, u->faction->locale, 0)); + update_long_order(u); + CuAssertPtrEquals(tc, 0, u->thisorder); + CuAssertPtrNotNull(tc, u->orders); + CuAssertPtrEquals(tc, 0, u->faction->msgs); + test_cleanup(); +} + +static void test_long_order_multi_long(CuTest *tc) { + // TODO: write more tests + unit *u; + test_cleanup(); + u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u->faction->locale = get_or_create_locale("de"); + unit_addorder(u, create_order(K_MOVE, u->faction->locale, 0)); + unit_addorder(u, create_order(K_DESTROY, u->faction->locale, 0)); + update_long_order(u); + CuAssertPtrNotNull(tc, u->thisorder); + CuAssertPtrNotNull(tc, u->orders); + CuAssertStrEquals(tc, "error52", test_get_messagetype(u->faction->msgs->begin->msg)); + test_cleanup(); +} + +static void test_long_order_multi_buy(CuTest *tc) { + // TODO: write more tests + unit *u; + test_cleanup(); + u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u->faction->locale = get_or_create_locale("de"); + unit_addorder(u, create_order(K_BUY, u->faction->locale, 0)); + unit_addorder(u, create_order(K_BUY, u->faction->locale, 0)); + update_long_order(u); + CuAssertPtrEquals(tc, 0, u->thisorder); + CuAssertPtrNotNull(tc, u->orders); + CuAssertStrEquals(tc, "error52", test_get_messagetype(u->faction->msgs->begin->msg)); + test_cleanup(); +} + +static void test_long_order_buy_cast(CuTest *tc) { + // TODO: write more tests + unit *u; + test_cleanup(); + u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u->faction->locale = get_or_create_locale("de"); + unit_addorder(u, create_order(K_BUY, u->faction->locale, 0)); + unit_addorder(u, create_order(K_CAST, u->faction->locale, 0)); + update_long_order(u); + CuAssertPtrEquals(tc, 0, u->thisorder); + CuAssertPtrNotNull(tc, u->orders); + CuAssertStrEquals(tc, "error52", test_get_messagetype(u->faction->msgs->begin->msg)); + test_cleanup(); +} + +static void test_long_order_hungry(CuTest *tc) { + // TODO: write more tests + unit *u; + test_cleanup(); + set_param(&global.parameters, "hunger.long", "1"); + u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + fset(u, UFL_HUNGER); + u->faction->locale = get_or_create_locale("de"); + unit_addorder(u, create_order(K_MOVE, u->faction->locale, 0)); + unit_addorder(u, create_order(K_DESTROY, u->faction->locale, 0)); + set_default_order(K_WORK); + update_long_order(u); + CuAssertIntEquals(tc, K_WORK, getkeyword(u->thisorder)); + CuAssertPtrNotNull(tc, u->orders); + CuAssertPtrEquals(tc, 0, u->faction->msgs); + set_default_order(NOKEYWORD); test_cleanup(); } CuSuite *get_laws_suite(void) { CuSuite *suite = CuSuiteNew(); - SUITE_ADD_TEST(suite, test_update_long_order); + SUITE_ADD_TEST(suite, test_long_order_normal); + SUITE_ADD_TEST(suite, test_long_order_none); + SUITE_ADD_TEST(suite, test_long_order_cast); + SUITE_ADD_TEST(suite, test_long_order_buy_sell); + SUITE_ADD_TEST(suite, test_long_order_multi_long); + SUITE_ADD_TEST(suite, test_long_order_multi_buy); + SUITE_ADD_TEST(suite, test_long_order_buy_cast); + SUITE_ADD_TEST(suite, test_long_order_hungry); SUITE_ADD_TEST(suite, test_new_building_can_be_renamed); SUITE_ADD_TEST(suite, test_rename_building); SUITE_ADD_TEST(suite, test_rename_building_twice); From 420574c7e46346619b5eda02176ec43adaaf8a44 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 5 Aug 2015 10:25:25 +0200 Subject: [PATCH 16/17] add unit-test for casting spells, fix spell-casting (was looking for thisorder), all E3 tests pass again --- scripts/tests/e3/rules.lua | 1 - scripts/tests/e3/spells.lua | 1 - src/laws.test.c | 17 +++++++++++++++++ src/magic.c | 26 ++++++++++++-------------- src/magic.test.c | 37 +++++++++++++++++++++++++++++++++++++ src/util/strings.c | 1 + 6 files changed, 67 insertions(+), 16 deletions(-) diff --git a/scripts/tests/e3/rules.lua b/scripts/tests/e3/rules.lua index 0e9d52147..902a91741 100644 --- a/scripts/tests/e3/rules.lua +++ b/scripts/tests/e3/rules.lua @@ -460,7 +460,6 @@ function test_canoe_passes_through_land() u1:add_order("NACH O O O") process_orders() assert_equal(land, u2.region, "canoe did not stop at coast") - u1:add_order("NACH O O O") process_orders() assert_equal(dst, sh.region, "canoe could not leave coast") assert_equal(dst, u1.region, "canoe could not leave coast") diff --git a/scripts/tests/e3/spells.lua b/scripts/tests/e3/spells.lua index c4f0aadaf..f99e4687b 100644 --- a/scripts/tests/e3/spells.lua +++ b/scripts/tests/e3/spells.lua @@ -58,7 +58,6 @@ function test_magic() u:add_spell("protective_runes") u:add_spell("analyze_magic") u:clear_orders() - u:add_order("ZAUBERE \"Runen des Schutzes\" BURG " .. itoa36(b.id)); u.building = b u:add_order("ZAUBERE \"Magie analysieren\" BURG " .. itoa36(b.id)); process_orders() diff --git a/src/laws.test.c b/src/laws.test.c index 900336d5c..12c2e8ecd 100644 --- a/src/laws.test.c +++ b/src/laws.test.c @@ -863,6 +863,22 @@ static void test_long_order_multi_buy(CuTest *tc) { test_cleanup(); } +static void test_long_order_multi_sell(CuTest *tc) { + // TODO: write more tests + unit *u; + test_cleanup(); + u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u->faction->locale = get_or_create_locale("de"); + unit_addorder(u, create_order(K_SELL, u->faction->locale, 0)); + unit_addorder(u, create_order(K_BUY, u->faction->locale, 0)); + unit_addorder(u, create_order(K_SELL, u->faction->locale, 0)); + update_long_order(u); + CuAssertPtrEquals(tc, 0, u->thisorder); + CuAssertPtrNotNull(tc, u->orders); + CuAssertPtrEquals(tc, 0, u->faction->msgs); + test_cleanup(); +} + static void test_long_order_buy_cast(CuTest *tc) { // TODO: write more tests unit *u; @@ -906,6 +922,7 @@ CuSuite *get_laws_suite(void) SUITE_ADD_TEST(suite, test_long_order_buy_sell); SUITE_ADD_TEST(suite, test_long_order_multi_long); SUITE_ADD_TEST(suite, test_long_order_multi_buy); + SUITE_ADD_TEST(suite, test_long_order_multi_sell); SUITE_ADD_TEST(suite, test_long_order_buy_cast); SUITE_ADD_TEST(suite, test_long_order_hungry); SUITE_ADD_TEST(suite, test_new_building_can_be_renamed); diff --git a/src/magic.c b/src/magic.c index 943c59db2..075880020 100644 --- a/src/magic.c +++ b/src/magic.c @@ -777,7 +777,7 @@ int spellcost(unit * u, const spell * sp) int count = countspells(u, 0); const resource_type *r_aura = get_resourcetype(R_AURA); - for (k = 0; sp->components[k].type; k++) { + for (k = 0; sp->components && sp->components[k].type; k++) { if (sp->components[k].type == r_aura) { aura = sp->components[k].amount; } @@ -798,7 +798,7 @@ static int spl_costtyp(const spell * sp) int k; int costtyp = SPC_FIX; - for (k = 0; sp->components[k].type; k++) { + for (k = 0; sp->components && sp->components[k].type; k++) { if (costtyp == SPC_LINEAR) return SPC_LINEAR; @@ -827,7 +827,7 @@ int eff_spelllevel(unit * u, const spell * sp, int cast_level, int range) int k, maxlevel, needplevel; int costtyp = SPC_FIX; - for (k = 0; sp->components[k].type; k++) { + for (k = 0; sp->components && sp->components[k].type; k++) { if (cast_level == 0) return 0; @@ -894,7 +894,7 @@ void pay_spell(unit * u, const spell * sp, int cast_level, int range) int resuse; assert(cast_level > 0); - for (k = 0; sp->components[k].type; k++) { + for (k = 0; sp->components && sp->components[k].type; k++) { if (sp->components[k].type == r_aura) { resuse = spellcost(u, sp) * range; } @@ -954,7 +954,7 @@ cancast(unit * u, const spell * sp, int level, int range, struct order * ord) return false; } - for (k = 0; sp->components[k].type; ++k) { + for (k = 0; sp->components && sp->components[k].type; ++k) { if (sp->components[k].amount > 0) { const resource_type *rtype = sp->components[k].type; int itemhave; @@ -2768,15 +2768,13 @@ void magic(void) continue; } - if (u->thisorder != NULL) { - for (ord = u->orders; ord; ord = ord->next) { - if (getkeyword(ord) == K_CAST) { - castorder *co = cast_cmd(u, ord); - fset(u, UFL_LONGACTION | UFL_NOTMOVING); - if (co) { - const spell *sp = co->sp; - add_castorder(&spellranks[sp->rank], co); - } + for (ord = u->orders; ord; ord = ord->next) { + if (getkeyword(ord) == K_CAST) { + castorder *co = cast_cmd(u, ord); + fset(u, UFL_LONGACTION | UFL_NOTMOVING); + if (co) { + const spell *sp = co->sp; + add_castorder(&spellranks[sp->rank], co); } } } diff --git a/src/magic.test.c b/src/magic.test.c index 9a01d5d4e..600f724ca 100644 --- a/src/magic.test.c +++ b/src/magic.test.c @@ -3,6 +3,7 @@ #include "magic.h" #include +#include #include #include #include @@ -382,9 +383,45 @@ void test_hasspell(CuTest * tc) test_cleanup(); } +static quicklist * casts; + +static int cast_fireball(struct castorder * co) { + ql_push(&casts, co); + return 0; +} + +void test_multi_cast(CuTest *tc) { + unit *u; + spell *sp; + struct locale * lang; + + test_cleanup(); + sp = create_spell("fireball", 0); + sp->cast = cast_fireball; + CuAssertPtrEquals(tc, sp, find_spell("fireball")); + + u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u->faction->locale = lang = get_or_create_locale("de"); + locale_setstring(lang, mkname("spell", sp->sname), "Feuerball"); + CuAssertStrEquals(tc, "Feuerball", spell_name(sp, lang)); + set_level(u, SK_MAGIC, 10); + unit_add_spell(u, 0, sp, 1); + CuAssertPtrEquals(tc, sp, unit_getspell(u, "Feuerball", lang)); + + unit_addorder(u, create_order(K_CAST, u->faction->locale, "Feuerball")); + unit_addorder(u, create_order(K_CAST, u->faction->locale, "Feuerball")); + CuAssertPtrEquals(tc, casts, 0); + magic(); + CuAssertPtrNotNull(tc, casts); + CuAssertIntEquals(tc, 2, ql_length(casts)); + ql_free(casts); + test_cleanup(); +} + CuSuite *get_magic_suite(void) { CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_multi_cast); SUITE_ADD_TEST(suite, test_updatespells); SUITE_ADD_TEST(suite, test_spellbooks); SUITE_ADD_TEST(suite, test_pay_spell); diff --git a/src/util/strings.c b/src/util/strings.c index 3f3d7dc36..b3801d52f 100644 --- a/src/util/strings.c +++ b/src/util/strings.c @@ -43,6 +43,7 @@ char *set_string(char **s, const char *neu) unsigned int hashstring(const char *s) { unsigned int key = 0; + assert(s); while (*s) { key = key * 37 + *s++; } From 8efc8749525b3191ec8f1cfb05dadfb92ec0271e Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 5 Aug 2015 12:19:17 +0200 Subject: [PATCH 17/17] backfill missing tests for ally_cmd --- src/kernel/config.c | 6 ++++- src/kernel/config.h | 1 + src/kernel/messages.c | 5 ++-- src/laws.c | 6 +++-- src/laws.test.c | 63 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 76 insertions(+), 5 deletions(-) diff --git a/src/kernel/config.c b/src/kernel/config.c index 8698fde51..9c26ad85a 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -919,6 +919,10 @@ static const char * parameter_key(int i) return parameters[i]; } +void init_parameters(struct locale *lang) { + init_translations(lang, UT_PARAMS, parameter_key, MAXPARAMS); +} + void init_terrains_translation(const struct locale *lang) { void **tokens; @@ -1009,7 +1013,7 @@ void init_locale(struct locale *lang) if (name) addtoken(tokens, name, var); } - init_translations(lang, UT_PARAMS, parameter_key, MAXPARAMS); + init_parameters(lang); init_options_translation(lang); init_terrains_translation(lang); diff --git a/src/kernel/config.h b/src/kernel/config.h index 5e7e77899..056de8f84 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -291,6 +291,7 @@ extern "C" { void set_default_order(int kwd); int entertainmoney(const struct region *r); + void init_parameters(struct locale *lang); void free_gamedata(void); diff --git a/src/kernel/messages.c b/src/kernel/messages.c index e0efdd04b..28625ff85 100644 --- a/src/kernel/messages.c +++ b/src/kernel/messages.c @@ -285,8 +285,9 @@ extern unsigned int new_hashstring(const char *s); void free_messagelist(message_list * msgs) { - struct mlist **mlistptr = &msgs->begin; - while (*mlistptr) { + struct mlist **mlistptr; + assert(msgs && msgs->begin); + for (mlistptr = &msgs->begin; *mlistptr;) { struct mlist *ml = *mlistptr; *mlistptr = ml->next; msg_release(ml->msg); diff --git a/src/laws.c b/src/laws.c index b9df102cd..3f68294fb 100755 --- a/src/laws.c +++ b/src/laws.c @@ -1347,10 +1347,12 @@ int ally_cmd(unit * u, struct order *ord) s = gettoken(token, sizeof(token)); - if (s && !s[0]) + if (!s || !s[0]) { keyword = P_ANY; - else + } + else { keyword = findparam(s, u->faction->locale); + } sfp = &u->faction->allies; if (fval(u, UFL_GROUP)) { diff --git a/src/laws.test.c b/src/laws.test.c index 12c2e8ecd..0c4881c85 100644 --- a/src/laws.test.c +++ b/src/laws.test.c @@ -1,6 +1,7 @@ #include #include "laws.h" #include "battle.h" +#include "monster.h" #include #include @@ -913,9 +914,71 @@ static void test_long_order_hungry(CuTest *tc) { test_cleanup(); } +static void test_ally_cmd_errors(CuTest *tc) { + unit *u; + int fid; + order *ord; + + test_cleanup(); + u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + u->faction->locale = get_or_create_locale("de"); + fid = u->faction->no + 1; + CuAssertPtrEquals(tc, 0, findfaction(fid)); + + ord = create_order(K_ALLY, u->faction->locale, itoa36(fid)); + ally_cmd(u, ord); + CuAssertStrEquals(tc, "error66", test_get_messagetype(u->faction->msgs->begin->msg)); + free_order(ord); + + test_cleanup(); +} + +static void test_ally_cmd(CuTest *tc) { + unit *u; + faction * f; + order *ord; + struct locale *lang; + + test_cleanup(); + u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + f = test_create_faction(0); + u->faction->locale = lang = get_or_create_locale("de"); + locale_setstring(lang, parameters[P_NOT], "NICHT"); + locale_setstring(lang, parameters[P_GUARD], "BEWACHE"); + init_parameters(lang); + + ord = create_order(K_ALLY, lang, "%s", itoa36(f->no)); + ally_cmd(u, ord); + CuAssertPtrEquals(tc, 0, u->faction->msgs); + CuAssertIntEquals(tc, HELP_ALL, alliedfaction(0, u->faction, f, HELP_ALL)); + free_order(ord); + + ord = create_order(K_ALLY, lang, "%s NICHT", itoa36(f->no)); + ally_cmd(u, ord); + CuAssertPtrEquals(tc, 0, u->faction->msgs); + CuAssertIntEquals(tc, 0, alliedfaction(0, u->faction, f, HELP_ALL)); + free_order(ord); + + ord = create_order(K_ALLY, lang, "%s BEWACHE", itoa36(f->no)); + ally_cmd(u, ord); + CuAssertPtrEquals(tc, 0, u->faction->msgs); + CuAssertIntEquals(tc, HELP_GUARD, alliedfaction(0, u->faction, f, HELP_ALL)); + free_order(ord); + + ord = create_order(K_ALLY, lang, "%s BEWACHE NICHT", itoa36(f->no)); + ally_cmd(u, ord); + CuAssertPtrEquals(tc, 0, u->faction->msgs); + CuAssertIntEquals(tc, 0, alliedfaction(0, u->faction, f, HELP_ALL)); + free_order(ord); + + test_cleanup(); +} + CuSuite *get_laws_suite(void) { CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_ally_cmd); + SUITE_ADD_TEST(suite, test_ally_cmd_errors); SUITE_ADD_TEST(suite, test_long_order_normal); SUITE_ADD_TEST(suite, test_long_order_none); SUITE_ADD_TEST(suite, test_long_order_cast);