diff --git a/src/common/attributes/attributes.c b/src/common/attributes/attributes.c index c53bab14e..08f71f91c 100644 --- a/src/common/attributes/attributes.c +++ b/src/common/attributes/attributes.c @@ -38,7 +38,6 @@ # include "option.h" #endif #include "moved.h" -#include "aggressive.h" #include "variable.h" /* util includes */ @@ -74,6 +73,5 @@ init_attributes(void) #ifdef USE_UGROUPS init_ugroup(); #endif - init_aggressive(); init_variable(); } diff --git a/src/common/attributes/attributes.vcproj b/src/common/attributes/attributes.vcproj index 4271a2097..da9a2afcd 100644 --- a/src/common/attributes/attributes.vcproj +++ b/src/common/attributes/attributes.vcproj @@ -173,9 +173,6 @@ - - @@ -246,9 +243,6 @@ RelativePath=".\viewrange.h"> - - diff --git a/src/common/gamecode/creport.c b/src/common/gamecode/creport.c index 755a527e6..e3845af6a 100644 --- a/src/common/gamecode/creport.c +++ b/src/common/gamecode/creport.c @@ -760,12 +760,17 @@ cr_output_unit(FILE * F, const region * r, } /* default commands */ fprintf(F, "COMMANDS\n"); +#ifdef LASTORDER if (u->lastorder) { fwriteorder(F, u->lastorder, f->locale); fputc('\n', F); } +#endif for (ord = u->orders; ord; ord = ord->next) { - if (is_persistent(ord) && ord!=u->lastorder) { +#ifdef LASTORDER + if (ord==u->lastorder) continue; +#endif + if (is_persistent(ord)) { fwriteorder(F, ord, f->locale); fputc('\n', F); } diff --git a/src/common/gamecode/economy.c b/src/common/gamecode/economy.c index b22090c30..a3e93d8f3 100644 --- a/src/common/gamecode/economy.c +++ b/src/common/gamecode/economy.c @@ -1534,21 +1534,21 @@ make_cmd(unit * u, struct order * ord) if (p == P_ROAD) { direction_t d; if(r->planep && fval(r->planep, PFL_NOBUILD)) { - cmistake(u, u->thisorder, 275, MSG_PRODUCE); + cmistake(u, ord, 275, MSG_PRODUCE); return; } d = finddirection(getstrtoken(), u->faction->locale); if (d!=NODIRECTION) { if(r->planep && fval(r->planep, PFL_NOBUILD)) { - cmistake(u, u->thisorder, 94, MSG_PRODUCE); + cmistake(u, ord, 94, MSG_PRODUCE); return; } build_road(r, u, m, d); - } else cmistake(u, u->thisorder, 71, MSG_PRODUCE); + } else cmistake(u, ord, 71, MSG_PRODUCE); return; } else if (p == P_SHIP) { if(r->planep && fval(r->planep, PFL_NOBUILD)) { - cmistake(u, u->thisorder, 276, MSG_PRODUCE); + cmistake(u, ord, 276, MSG_PRODUCE); return; } continue_ship(r, u, m); @@ -1592,19 +1592,19 @@ make_cmd(unit * u, struct order * ord) if (stype != NOSHIP) { if(r->planep && fval(r->planep, PFL_NOBUILD)) { - cmistake(u, u->thisorder, 276, MSG_PRODUCE); + cmistake(u, ord, 276, MSG_PRODUCE); return; } - create_ship(r, u, stype, m); + create_ship(r, u, stype, m, ord); return; } if (btype != NOBUILDING) { if(r->planep && fval(r->planep, PFL_NOBUILD)) { - cmistake(u, u->thisorder, 94, MSG_PRODUCE); + cmistake(u, ord, 94, MSG_PRODUCE); return; } - build_building(u, btype, m); + build_building(u, btype, m, ord); return; } @@ -1613,7 +1613,7 @@ make_cmd(unit * u, struct order * ord) return; } - cmistake(u, u->thisorder, 125, MSG_PRODUCE); + cmistake(u, ord, 125, MSG_PRODUCE); } /* ------------------------------------------------------------- */ diff --git a/src/common/gamecode/laws.c b/src/common/gamecode/laws.c index fee34a2d5..7bbd2aa38 100644 --- a/src/common/gamecode/laws.c +++ b/src/common/gamecode/laws.c @@ -139,7 +139,9 @@ restart_race(unit *u, const race * rc) *ordp = ord->next; ord->next = NULL; if (u->thisorder == ord) set_order(&u->thisorder, NULL); +#ifdef LASTORDER if (u->lastorder == ord) set_order(&u->lastorder, NULL); +#endif } else { ordp = &ord->next; } @@ -2662,6 +2664,7 @@ instant_orders(void) unit * u; for (u = r->units; u; u = u->next) { order * ord; + freset(u, UFL_MOVED); for (ord = u->orders; ord; ord = ord->next) { switch (get_keyword(ord)) { case K_URSPRUNG: @@ -3413,86 +3416,48 @@ setdefaults (void) set_order(&u->thisorder, default_order(u->faction->locale)); continue; } - +#ifdef LASTORDER /* by default the default long order becomes the new long order. */ - u->thisorder = copy_order(u->lastorder); - + u->thisorder = duplicate_order(u->lastorder); +#endif /* check all orders for a potential new long order this round: */ for (ord = u->orders; ord; ord = ord->next) { - keyword_t keyword = get_keyword(ord); - - switch (keyword) { - /* 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 - * hier, ob die Einheit handelt. */ - case K_BUY: - case K_SELL: - /* Wenn die Einheit handelt, muß der Default-Befehl gelöscht - * werden. */ - 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, NULL); - break; - - case K_MAKE: - /* Falls wir MACHE TEMP haben, ignorieren wir es. Alle anderen - * Arten von MACHE zaehlen aber als neue defaults und werden - * behandelt wie die anderen (deswegen kein break nach case - * K_MAKE) - und in thisorder (der aktuelle 30-Tage Befehl) - * abgespeichert). */ - init_tokens(ord); /* initialize token-parser */ - skip_token(); - if (getparam(u->faction->locale) == P_TEMP) break; - /* else fall through */ - -#if GROWING_TREES - case K_PFLANZE: -#endif - case K_BESIEGE: - case K_ENTERTAIN: - case K_TAX: - case K_RESEARCH: - case K_SPY: - case K_STEAL: - case K_SABOTAGE: - case K_STUDY: - case K_TEACH: - case K_ZUECHTE: - case K_BIETE: - case K_PIRACY: - /* Ü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, ord); - } - break; - - case K_FOLLOW: - /* FOLLOW is only a long order if we are following a ship. */ - init_tokens(ord); - skip_token(); - if (getparam(u->faction->locale) == P_SHIP) { - set_order(&u->thisorder, ord); - } - break; - - case K_ROUTE: - case K_WORK: - case K_DRIVE: - case K_MOVE: - case K_WEREWOLF: + 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, ord); - break; + } + break; + } else { + keyword_t keyword = get_keyword(ord); + switch (keyword) { + /* 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 + * hier, ob die Einheit handelt. */ + case K_BUY: + case K_SELL: + /* Wenn die Einheit handelt, muß der Default-Befehl gelöscht + * werden. */ + trade = true; + break; - /* Wird je diese Ausschliesslichkeit aufgehoben, muss man aufpassen - * mit der Reihenfolge von Kaufen, Verkaufen etc., damit es Spielern - * nicht moeglich ist, Schulden zu machen. */ + case K_CAST: + /* dient dazu, das neben Zaubern kein weiterer Befehl + * ausgeführt werden kann, Zaubern ist ein kurzer Befehl */ + set_order(&u->thisorder, NULL); + break; + + case K_WEREWOLF: + set_order(&u->thisorder, ord); + break; + + /* Wird je diese Ausschliesslichkeit aufgehoben, muss man aufpassen + * mit der Reihenfolge von Kaufen, Verkaufen etc., damit es Spielern + * nicht moeglich ist, Schulden zu machen. */ + } } } @@ -3512,21 +3477,19 @@ setdefaults (void) * die Einheitsnummer ungueltig). Auch Attackiere sollte nie in * den Default übernommen werden */ +#ifdef LASTORDER switch (get_keyword(u->thisorder)) { case K_MOVE: - case K_BIETE: case K_ATTACK: case K_WEREWOLF: case NOKEYWORD: + /* these can never be default orders */ break; default: set_order(&u->lastorder, u->thisorder); - /* Attackiere sollte niemals Default werden */ - if (get_keyword(u->lastorder) == K_ATTACK) { - set_order(&u->lastorder, default_order(u->faction->locale)); - } } +#endif } } } @@ -3648,6 +3611,7 @@ monthly_healing(void) } } +#ifdef LASTORDER static void defaultorders (void) { @@ -3675,6 +3639,7 @@ defaultorders (void) } } } +#endif /* ************************************************************ */ /* GANZ WICHTIG! ALLE GEÄNDERTEN SPRÜCHE NEU ANZEIGEN */ @@ -3900,8 +3865,10 @@ processorders (void) monthly_healing(); regeneration_magiepunkte(); +#ifdef LASTORDER puts(" - Defaults setzen"); defaultorders(); +#endif puts(" - Unterhaltskosten, Nachfrage, Seuchen, Wachstum, Auswanderung"); demographics(); diff --git a/src/common/gamecode/monster.c b/src/common/gamecode/monster.c index 4170e6043..f007af749 100644 --- a/src/common/gamecode/monster.c +++ b/src/common/gamecode/monster.c @@ -32,7 +32,6 @@ /* attributes includes */ #include #include -#include /* spezialmonster */ #include @@ -74,87 +73,69 @@ static boolean is_waiting(const unit * u) { - if (fval(u, UFL_ISNEW)) return true; - if (get_keyword(u->lastorder)==K_WAIT) return true; - - return false; + if (fval(u, UFL_ISNEW|UFL_MOVED)) return true; + return false; } -static boolean +static order * monster_attack(unit * u, const unit * target) { char zText[20]; - if (u->region!=target->region) return false; - if (!cansee(u->faction, u->region, target, 0)) return false; - if (is_waiting(u)) return false; + if (u->region!=target->region) return NULL; + if (u->faction==target->faction) return NULL; + if (!cansee(u->faction, u->region, target, 0)) return NULL; + if (is_waiting(u)) return NULL; sprintf(zText, "%s %s", locale_string(u->faction->locale, keywords[K_ATTACK]), unitid(target)); - addlist(&u->orders, parse_order(zText, u->faction->locale)); - return true; + return parse_order(zText, u->faction->locale); } -void -taxed_by_monster(unit * u) -{ - const char * zText = locale_string(u->faction->locale, keywords[K_TAX]); - addlist(&u->orders, parse_order(zText, u->faction->locale)); -} -static boolean +static order * get_money_for_dragon(region * r, unit * u, int wanted) { unit *u2; int n; /* attackiere bewachende einheiten */ + for (u2 = r->units; u2; u2 = u2->next) { + if (u2 != u && getguard(u2)&GUARD_TAX) { + order * ord = monster_attack(u, u2); + if (ord) addlist(&u->orders, ord); + } + } - for (u2 = r->units; u2; u2 = u2->next) - if (u2 != u && getguard(u2)&GUARD_TAX) - monster_attack(u, u2); - - /* treibe steuern bei den bauern ein */ - - taxed_by_monster(u); - - /* falls das genug geld ist, bleibt das monster hier */ - - if (rmoney(r) >= wanted) - return true; - - /* attackiere so lange die fremden, alteingesessenen einheiten mit geld - * (einfach die reihenfolge der einheiten), bis das geld da ist. n - * zaehlt das so erhaltene geld. */ + /* falls genug geld in der region ist, treiben wir steuern ein. */ + if (rmoney(r) >= wanted) { + /* 5% chance, dass der drache aus einer laune raus attackiert */ + if (chance(0.95)) return parse_order(keywords[K_TAX], default_locale); + } + /* falls der drache launisch ist, oder das regionssilber knapp, greift er alle an */ n = 0; - for (u2 = r->units; u2; u2 = u2->next) - if (u2->faction != u->faction && get_money(u2)) { - if (monster_attack(u, u2)) { - n += get_money(u2); + for (u2 = r->units; u2; u2 = u2->next) { + if (u2->faction != u->faction && get_money(u2)) { + if (getguard(u2) & GUARD_TAX) continue; + else { + order * ord = monster_attack(u, u2); + if (ord) { + addlist(&u->orders, ord); + n += get_money(u2); + } + } + } + } - if (n > wanted) - break; - } - } - /* falls die einnahmen erreicht werden, bleibt das monster noch eine + /* falls die einnahmen erreicht werden, bleibt das monster noch eine * runde hier. */ + if (n + rmoney(r) >= wanted) { + return parse_order(keywords[K_TAX], default_locale); + } - if (n + rmoney(r) >= wanted) - return true; - - /* falls das geld, das wir haben, und das der angriffe zum leben - * reicht, koennen wir uns fortbewegen. deswegen duerfen wir - * steuereinnahmen nicht beruecksichtigen - wir bewegen uns ja fort. */ - - if (get_money(u) + n >= MAINTENANCE) - return false; - - /* falls wir auch mit angriffe nicht genug geld zum wandern haben, - * muessen wir wohl oder uebel hier bleiben. vielleicht wurden ja genug - * steuern eingetrieben */ - - return true; + /* wenn wir NULL zurückliefern, macht der drache was anderes, z.b. weggehen */ + return NULL; } static int @@ -314,8 +295,8 @@ treeman_neighbour(region * r) return NODIRECTION; } -static void -move_monster(region * r, unit * u) +static order * +monster_move(region * r, unit * u) { direction_t d = NODIRECTION; @@ -337,11 +318,11 @@ move_monster(region * r, unit * u) * den ozean */ if (d == NODIRECTION) - return; + return NULL; sprintf(buf, "%s %s", locale_string(u->faction->locale, keywords[K_MOVE]), locale_string(u->faction->locale, directions[d])); - addlist(&u->orders, parse_order(buf, u->faction->locale)); + return parse_order(buf, u->faction->locale); } /* Wir machen das mal autoconf-style: */ @@ -412,8 +393,8 @@ set_new_dragon_target(unit * u, region * r, int range) return NULL; } -static boolean -set_movement_order(unit * u, const region * target, int moves, boolean (*allowed)(const region *, const region *)) +static order * +make_movement_order(unit * u, const region * target, int moves, boolean (*allowed)(const region *, const region *)) { region * r = u->region; region ** plan = path_find(r, target, DRAGON_RANGE*5, allowed); @@ -421,7 +402,7 @@ set_movement_order(unit * u, const region * target, int moves, boolean (*allowed char * c; if (plan==NULL) { - return false; + return NULL; } strcpy(buf, locale_string(u->faction->locale, keywords[K_MOVE])); @@ -437,12 +418,10 @@ set_movement_order(unit * u, const region * target, int moves, boolean (*allowed c += strlen(c); } - set_order(&u->lastorder, parse_order(buf, u->faction->locale)); - free_order(u->lastorder); /* parse_order & set_order have both increased the refcount */ - return true; + return parse_order(buf, u->faction->locale); } -static void +static order * monster_seeks_target(region *r, unit *u) { direction_t d; @@ -465,7 +444,10 @@ monster_seeks_target(region *r, unit *u) } /* TODO: prüfen, ob target überhaupt noch existiert... */ - if(!target) return; /* this is a bug workaround! remove!! */ + if (!target) { + log_error(("Monster '%s' hat kein Ziel!\n", unitname(u))); + return NULL; /* this is a bug workaround! remove!! */ + } if(r == target->region ) { /* Wir haben ihn! */ if (u->race == new_race[RC_ALP]) { @@ -474,7 +456,7 @@ monster_seeks_target(region *r, unit *u) else { assert(!"Seeker-Monster hat keine Aktion fuer Ziel"); } - return; + return NULL; } /* Simpler Ansatz: Nachbarregion mit gerinster Distanz suchen. @@ -500,9 +482,9 @@ monster_seeks_target(region *r, unit *u) } if( d == NODIRECTION ) - return; + return NULL; sprintf(buf, "%s %s", locale_string(u->faction->locale, keywords[K_MOVE]), locale_string(u->faction->locale, directions[d])); - addlist(&u->orders, parse_order(buf, u->faction->locale)); + return parse_order(buf, u->faction->locale); } unit * @@ -535,61 +517,18 @@ random_unit(const region * r) return u; } -static boolean -random_attack_by_monster(const region * r, unit * u) +static void +monster_attacks(unit * u) { - boolean success = false; - unit *target; - int kill, max; - int tries = 0; - int attacked = 0; + region * r = u->region; + unit * u2; - switch (old_race(u->race)) { - case RC_FIREDRAGON: - kill = 25; - max = 50; - break; - case RC_DRAGON: - kill = 100; - max = 200; - break; - case RC_WYRM: - kill = 400; - max = 800; - break; - default: - kill = 1; - max = 1; - } - - kill *= u->number; - max *= u->number; - - do { - tries++; - target = random_unit(r); - if (target - && target != u - && humanoidrace(target->race) - && !illusionaryrace(target->race) - && target->number <= max) - { - if (monster_attack(u, target)) { - unit * u2; - success = true; - for (u2 = r->units; u2; u2 = u2->next) { - if (u2->faction->no == MONSTER_FACTION - && rand() % 100 < 75) - { - monster_attack(u2, target); - } - } - attacked += target->number; - } - } - } - while (attacked < kill && tries < 10); - return success; + for (u2=r->units;u2;u2=u2->next) { + if (chance(0.75)) { + order * ord = monster_attack(u, u2); + if (ord) addlist(&u->orders, ord); + } + } } static void @@ -741,12 +680,13 @@ random_growl(void) extern attrib_type at_direction; -static void -learn_monster(unit *u) +static order * +monster_learn(unit *u) { int c = 0; int n; skill * sv; + const struct locale * lang = u->faction->locale; /* Monster lernt ein zufälliges Talent aus allen, in denen es schon * Lerntage hat. */ @@ -755,7 +695,7 @@ learn_monster(unit *u) if (sv->level>0) ++c; } - if(c == 0) return; + if(c == 0) return NULL; n = rand()%c + 1; c = 0; @@ -763,14 +703,13 @@ learn_monster(unit *u) for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { if (sv->level>0) { if (++c == n) { - sprintf(buf, "%s %s", locale_string(u->faction->locale, keywords[K_STUDY]), - skillname(sv->id, u->faction->locale)); - set_order(&u->thisorder, parse_order(buf, u->faction->locale)); - free_order(u->thisorder); /* parse_order & set_order have both increased the refcount */ - break; + sprintf(buf, "%s %s", locale_string(lang, keywords[K_STUDY]), + skillname(sv->id, lang)); + return parse_order(buf, lang); } } } + return NULL; } void @@ -810,6 +749,47 @@ check_overpopulated(unit *u) } static void +recruit_dracoids(unit * dragon, int size) +{ + faction * f = dragon->faction; + region * r = dragon->region; + const struct item_type * weapon = NULL; + order * new_order; + unit *un = createunit(r, f, size, new_race[RC_DRACOID]); + + name_unit(un); + change_money(dragon, -un->number * 50); + + set_level(un, SK_SPEAR, (3 + rand() % 4)); + set_level(un, SK_SWORD, (3 + rand() % 4)); + set_level(un, SK_LONGBOW, (2 + rand() % 3)); + + switch (rand() % 3) { + case 0: + weapon = olditemtype[I_LONGBOW]; + break; + case 1: + weapon = olditemtype[I_SWORD]; + break; + default: + weapon = olditemtype[I_SPEAR]; + break; + } + i_change(&un->items, weapon, un->number); + if (weapon->rtype->wtype->flags & WTF_MISSILE) un->status = ST_BEHIND; + else un->status = ST_FIGHT; + + sprintf(buf, "%s \"%s\"", keywords[K_STUDY], skillname(weapon->rtype->wtype->skill, f->locale)); + new_order = parse_order(buf, default_locale); +#ifdef LASTORDER + set_order(&un->lastorder, new_order); + free_order(new_order); +#else + addlist(&un->orders, new_order); +#endif +} + +static order * plan_dragon(unit * u) { attrib * ta = a_find(u->attribs, &at_targetregion); @@ -819,6 +799,7 @@ plan_dragon(unit * u) int capacity = walkingcapacity(u); item ** itmp = &u->items; boolean move = false; + order * long_order = NULL; if (horses > 0) { change_resource(u, R_HORSE, - min(horses,(u->number*2))); @@ -853,15 +834,16 @@ plan_dragon(unit * u) } } if (tr!=NULL) { + assert(long_order==NULL); switch(old_race(u->race)) { case RC_FIREDRAGON: - set_movement_order(u, tr, 4, allowed_dragon); + long_order = make_movement_order(u, tr, 4, allowed_dragon); break; case RC_DRAGON: - set_movement_order(u, tr, 3, allowed_dragon); + long_order = make_movement_order(u, tr, 3, allowed_dragon); break; case RC_WYRM: - set_movement_order(u, tr, 1, allowed_dragon); + long_order = make_movement_order(u, tr, 1, allowed_dragon); break; } if (rand()%100 < 15) { @@ -875,49 +857,28 @@ plan_dragon(unit * u) } } } else { - if (!get_money_for_dragon(u->region, u, income(u))) { - /* money is gone */ + /* we have no target. do we like it here, then? */ + long_order = get_money_for_dragon(u->region, u, income(u)); + if (long_order==NULL) { + /* money is gone, need a new target */ set_new_dragon_target(u, u->region, DRAGON_RANGE); } - else if (u->race != new_race[RC_FIREDRAGON] && u->region->terrain!=T_OCEAN - && !(terrain[rterrain(u->region)].flags & FORBIDDEN_LAND)) { + else if (u->race != new_race[RC_FIREDRAGON]) { + /* neue dracoiden! */ + terrain_t t = rterrain(r); + if (r->land && !(terrain[t].flags & FORBIDDEN_LAND)) { int ra = 20 + rand() % 100; - if (get_money(u) > ra * 50 + 100 && rand() % 100 < 50) - { - const struct item_type * weapon = NULL; - unit *un; - un = createunit(u->region, findfaction(MONSTER_FACTION), ra, new_race[RC_DRACOID]); - name_unit(un); - change_money(u, -un->number * 50); - - set_level(un, SK_SPEAR, (3 + rand() % 4)); - set_level(un, SK_SWORD, (3 + rand() % 4)); - set_level(un, SK_LONGBOW, (2 + rand() % 3)); - - switch (rand() % 3) { - case 0: - weapon = olditemtype[I_LONGBOW]; - break; - case 1: - weapon = olditemtype[I_SWORD]; - break; - default: - weapon = olditemtype[I_SPEAR]; - break; - } - i_change(&un->items, weapon, un->number); - if (weapon->rtype->wtype->flags & WTF_MISSILE) un->status = ST_BEHIND; - else un->status = ST_FIGHT; - sprintf(buf, "%s \"%s\"", keywords[K_STUDY], skillname(weapon->rtype->wtype->skill, u->faction->locale)); - set_order(&un->lastorder, parse_order(buf, default_locale)); - } - if (is_waiting(u)) { - sprintf(buf, "%s \"%s\"", keywords[K_STUDY], skillname(SK_OBSERVATION, u->faction->locale)); - set_order(&u->thisorder, parse_order(buf, default_locale)); - set_order(&u->lastorder, u->thisorder); + if (get_money(u) > ra * 50 + 100 && rand() % 100 < 50) { + recruit_dracoids(u, ra); } } + } } + if (long_order==NULL) { + sprintf(buf, "%s \"%s\"", keywords[K_STUDY], skillname(SK_OBSERVATION, u->faction->locale)); + long_order = parse_order(buf, default_locale); + } + return long_order; } void @@ -931,30 +892,32 @@ plan_monsters(void) for (r = regions; r; r = r->next) { unit *u; + double attack_chance = MONSTERATTACK; + boolean attacking = false; + for (u = r->units; u; u = u->next) { - boolean is_moving = false; attrib * ta; + order * long_order = NULL; /* Ab hier nur noch Befehle für NPC-Einheiten. */ if (u->faction->no != MONSTER_FACTION) continue; + if (attack_chance>0.0) { + if (chance(attack_chance)) attacking = true; + attack_chance = 0.0; + } + if (u->status>ST_BEHIND) u->status = ST_FIGHT; /* all monsters fight */ /* Monster bekommen jede Runde ein paar Tage Wahrnehmung dazu */ produceexp(u, SK_OBSERVATION, u->number); - /* Haben Drachen ihr Ziel erreicht? */ - ta = a_find(u->attribs, &at_targetregion); - if (ta) { - if (u->region == (region*)ta->data.v) { - a_remove(&u->attribs, ta); - set_order(&u->lastorder, parse_order(keywords[K_WAIT], u->faction->locale)); - free_order(u->lastorder); /* parse_order & set_order have each increased the refcount */ - } - else { - is_moving = true; - } - } + /* Befehle müssen jede Runde neu gegeben werden: */ + free_orders(&u->orders); + if (attacking) { + monster_attacks(u); + } + /* units with a plan to kill get ATTACK orders: */ ta = a_find(u->attribs, &at_hate); if (ta && !is_waiting(u)) { unit * tu = (unit *)ta->data.v; @@ -963,62 +926,63 @@ plan_monsters(void) addlist(&u->orders, parse_order(buf, u->faction->locale)); } else if (tu) { tu = findunitg(ta->data.i, NULL); - if (tu) set_movement_order(u, tu->region, 2, allowed_walk); + if (tu!=NULL) { + long_order = make_movement_order(u, tu->region, 2, allowed_walk); + } } else a_remove(&u->attribs, ta); } - if (!(fval(u, UFL_ISNEW)) && r->terrain != T_OCEAN) { /* Monster bewachen immer */ + /* All monsters guard the region: */ + if (!is_waiting(u) && r->land) { const char * cmd = locale_string(u->faction->locale, keywords[K_GUARD]); addlist(&u->orders, parse_order(cmd, u->faction->locale)); } - /* Diese Verkettung ist krank und sollte durch eine 'vernünftige KI' - * ersetzt werden. */ - - if( (u->race->flags & RCF_MOVERANDOM) - && (rand()%100race->flags & RCF_ATTACKRANDOM) && is_moving == false) - { - double probability; - attrib *a = a_find(u->attribs, &at_aggressive); - - if (a) { - probability = a->data.flt; - } else { - probability = MONSTERATTACK; - } - - if(chance(probability)) { - done = random_attack_by_monster(r, u); - } + /* Einheiten mit Bewegungsplan kriegen ein NACH: */ + if (long_order==NULL) { + attrib * ta = a_find(u->attribs, &at_targetregion); + if (ta) { + if (u->region == (region*)ta->data.v) { + a_remove(&u->attribs, ta); } - if (!done) { - if(u->race == new_race[RC_SEASERPENT]) { - set_order(&u->thisorder, parse_order(keywords[K_PIRACY], default_locale)); - set_order(&u->lastorder, u->thisorder); - free_order(u->lastorder); /* parse_order & set_order have both increased the refcount */ - } else if(u->race->flags & RCF_LEARN) { - learn_monster(u); - } + } else if (u->race->flags & RCF_MOVERANDOM) { + if (rand()%100race)) { - case RC_ALP: - monster_seeks_target(r, u); - break; - case RC_FIREDRAGON: - case RC_DRAGON: - case RC_WYRM: - plan_dragon(u); - break; + case RC_SEASERPENT: + long_order = parse_order(keywords[K_PIRACY], default_locale); + break; + case RC_ALP: + long_order = monster_seeks_target(r, u); + break; + case RC_FIREDRAGON: + case RC_DRAGON: + case RC_WYRM: + long_order = plan_dragon(u); + break; + default: + if (u->race->flags & RCF_LEARN) { + long_order = monster_learn(u); + } + break; } + if (long_order) { + set_order(&u->thisorder, long_order); +#ifdef LASTORDER + set_order(&u->lastorder, long_order); + free_order(new_order); /* parse_order & set_order have both increased the refcount */ +#else + addlist(&u->orders, long_order); +#endif + } + } } } } diff --git a/src/common/gamecode/randenc.c b/src/common/gamecode/randenc.c index 664671b22..ba9baf725 100644 --- a/src/common/gamecode/randenc.c +++ b/src/common/gamecode/randenc.c @@ -308,9 +308,9 @@ get_unit(region * r, unit * u) addmessage(r, u->faction, buf, MSG_EVENT, ML_IMPORTANT); newunit = createunit(r, u->faction, rand() % 20 + 3, u->faction->race); + fset(newunit, UFL_ISNEW|UFL_MOVED); set_string(&newunit->name, "Dorfbewohner"); set_money(newunit, (rand() % 26 + 10) * newunit->number); - fset(newunit, UFL_ISNEW); if (fval(u, UFL_PARTEITARNUNG)) fset(newunit, UFL_PARTEITARNUNG); switch (rand() % 4) { case 0: @@ -576,7 +576,7 @@ chaos(region * r) break; } if (mfac) set_money(u, u->number * (rand() % mfac)); - guard(u, GUARD_ALL); + fset(u, UFL_ISNEW|UFL_MOVED); } case 2: /* Terrainveränderung */ if (!(terrain[rterrain(r)].flags & FORBIDDEN_LAND)) { @@ -1101,7 +1101,7 @@ godcurse(void) } } -static void +static unit * split_unit(region * r, unit *u) { unit *u2 = createunit(r, u->faction, 0, u->race); @@ -1109,11 +1109,8 @@ split_unit(region * r, unit *u) set_string(&u2->name, u->name); set_string(&u2->display, u->display); - set_order(&u2->thisorder, parse_order(keywords[K_WAIT], u->faction->locale)); - set_order(&u2->lastorder, u2->thisorder); - free_order(u2->lastorder); /* parse_order & set_order have each increased the refcount */ - transfermen(u, u2, newsize); + return u2; } static void @@ -1126,7 +1123,8 @@ check_split(void) for(u=r->units;u;u=u->next) { if(u->faction->no == MONSTER_FACTION) { if(u->number > u->race->splitsize) { - split_unit(r, u); + unit * u2 = split_unit(r, u); + fset(u2, UFL_ISNEW|UFL_MOVED); } } } @@ -1386,6 +1384,7 @@ randomevents(void) message * msg; if (rterrain(r) == T_OCEAN && rand()%10000 < 1) { u = createunit(r, findfaction(MONSTER_FACTION), 1, new_race[RC_SEASERPENT]); + fset(u, UFL_ISNEW|UFL_MOVED); set_level(u, SK_MAGIC, 4); set_level(u, SK_OBSERVATION, 3); set_level(u, SK_STEALTH, 2); @@ -1393,25 +1392,14 @@ randomevents(void) set_string(&u->name, "Seeschlange"); } - if ((rterrain(r) == T_GLACIER - || rterrain(r) == T_SWAMP || rterrain(r) == T_DESERT) - && rand() % 10000 < (5 + 100 * chaosfactor(r))) { - - switch (rand() % 10) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: + if ((rterrain(r) == T_GLACIER || rterrain(r) == T_SWAMP || rterrain(r) == T_DESERT) && rand() % 10000 < (5 + 100 * chaosfactor(r))) + { + if (chance(0.80)) { u = createunit(r, findfaction(MONSTER_FACTION), nrand(60, 20) + 1, new_race[RC_FIREDRAGON]); - break; - default: - u = createunit(r, findfaction(MONSTER_FACTION), nrand(30, 20) + 1, new_race[RC_DRAGON]); - break; - } + } else { + u = createunit(r, findfaction(MONSTER_FACTION), nrand(30, 20) + 1, new_race[RC_DRAGON]); + } + fset(u, UFL_ISNEW|UFL_MOVED); set_money(u, u->number * (rand() % 500 + 100)); set_level(u, SK_MAGIC, 4); @@ -1422,8 +1410,6 @@ randomevents(void) LOC(default_locale, rc_name(u->race, u->number!=1)), regionname(r, NULL)); name_unit(u); - set_order(&u->lastorder, parse_order(keywords[K_WAIT], u->faction->locale)); - free_order(u->lastorder); /* parse_order & set_order have each increased the refcount */ /* add message to the region */ ADDMSG(&r->msgs, @@ -1472,6 +1458,7 @@ randomevents(void) } u = createunit(r, findfaction(MONSTER_FACTION), undead, rc); + fset(u, UFL_ISNEW|UFL_MOVED); if ((rc == new_race[RC_SKELETON] || rc == new_race[RC_ZOMBIE]) && rand()%10 < 4) { set_item(u, I_RUSTY_SWORD, undead); if (rand()%10 < 3) { @@ -1490,14 +1477,12 @@ randomevents(void) u->hp = unit_max_hp(u) * u->number; deathcounts(r, -undead); - set_order(&u->lastorder, parse_order(keywords[K_WAIT], u->faction->locale)); - free_order(u->lastorder); /* parse_order & set_order have each increased the refcount */ - name_unit(u); + name_unit(u); - log_printf("%d %s in %s.\n", u->number, - LOC(default_locale, rc_name(u->race, u->number!=1)), regionname(r, NULL)); + log_printf("%d %s in %s.\n", u->number, + LOC(default_locale, rc_name(u->race, u->number!=1)), regionname(r, NULL)); - { + { message * msg = msg_message("undeadrise", "region", r); add_message(&r->msgs, msg); for (u=r->units;u;u=u->next) freset(u->faction, FL_DH); @@ -1566,9 +1551,7 @@ randomevents(void) rsettrees(r, trees); #endif u = createunit(r, findfaction(MONSTER_FACTION),treemen, new_race[RC_TREEMAN]); - set_order(&u->lastorder, parse_order(keywords[K_WAIT], u->faction->locale)); - free_order(u->lastorder); /* parse_order & set_order have each increased the refcount */ - /* guard(u, GUARD_ALL); kein auto-guard! erst in monster.c! */ + fset(u, UFL_ISNEW|UFL_MOVED); set_level(u, SK_OBSERVATION, 2); if (u->number == 1) diff --git a/src/common/gamecode/report.c b/src/common/gamecode/report.c index 37b7ecb0c..fcecb81b1 100644 --- a/src/common/gamecode/report.c +++ b/src/common/gamecode/report.c @@ -1676,12 +1676,14 @@ order_template(FILE * F, faction * f) /* If the lastorder begins with an @ it should have * been printed in the loop before. */ +#ifdef LASTORDER if (u->lastorder && !is_persistent(u->lastorder)) { strcpy(buf, " "); write_order(u->lastorder, u->faction->locale, buf+2, sizeof(buf)-2); rps_nowrap(F, buf); rnl(F); } +#endif } } rps_nowrap(F, ""); @@ -3776,7 +3778,7 @@ report_init(void) add_function("spell", &eval_spell); register_argtype("string", free, (void*(*)(void*))strdup); - register_argtype("order", (void(*)(void*))free_order, (void*(*)(void*))copy_order); + register_argtype("order", (void(*)(void*))free_order, (void*(*)(void*))duplicate_order); register_function((pf_generic)view_neighbours, "view_neighbours"); register_function((pf_generic)view_regatta, "view_regatta"); } diff --git a/src/common/gamecode/study.c b/src/common/gamecode/study.c index 1e4938079..6ffcba9c7 100644 --- a/src/common/gamecode/study.c +++ b/src/common/gamecode/study.c @@ -241,213 +241,215 @@ static void teach(unit * u, struct order * ord) { region * r = u->region; - static char order[BUFSIZE]; - int teaching, i, j, count, academy=0; - unit *u2; - const char *s; - skill_t sk; + int teaching, i, j, count, academy=0; + unit *u2; + const char *s; + skill_t sk = NOSKILL; - if ((u->race->flags & RCF_NOTEACH) || fval(u, UFL_WERE)) { - cmistake(u, u->thisorder, 274, MSG_EVENT); - return; - } + if ((u->race->flags & RCF_NOTEACH) || fval(u, UFL_WERE)) { + cmistake(u, ord, 274, MSG_EVENT); + return; + } - if (r->planep && fval(r->planep, PFL_NOTEACH)) { - cmistake(u, u->thisorder, 273, MSG_EVENT); - return; - } + if (r->planep && fval(r->planep, PFL_NOTEACH)) { + cmistake(u, ord, 273, MSG_EVENT); + return; + } - teaching = u->number * 30 * TEACHNUMBER; + teaching = u->number * 30 * TEACHNUMBER; - if ((i = get_effect(u, oldpotiontype[P_FOOL])) > 0) { /* Trank "Dumpfbackenbrot" */ - i = min(i, u->number * TEACHNUMBER); - /* Trank wirkt pro Schüler, nicht pro Lehrer */ - teaching -= i * 30; - change_effect(u, oldpotiontype[P_FOOL], -i); - j = teaching / 30; - add_message(&u->faction->msgs, msg_message("teachdumb", - "teacher amount", u, j)); - } - if (teaching == 0) return; + if ((i = get_effect(u, oldpotiontype[P_FOOL])) > 0) { /* Trank "Dumpfbackenbrot" */ + i = min(i, u->number * TEACHNUMBER); + /* Trank wirkt pro Schüler, nicht pro Lehrer */ + teaching -= i * 30; + change_effect(u, oldpotiontype[P_FOOL], -i); + j = teaching / 30; + add_message(&u->faction->msgs, msg_message("teachdumb", + "teacher amount", u, j)); + } + if (teaching == 0) return; - strcpy(order, locale_string(u->faction->locale, keywords[K_TEACH])); - u2 = 0; - count = 0; + u2 = 0; + count = 0; init_tokens(ord); skip_token(); #if TEACH_ALL - if (getparam(u->faction->locale)==P_ANY) { - unit * student = r->units; - skill_t teachskill[MAXSKILLS]; - int i = 0; - do { - sk = getskill(u->faction->locale); - teachskill[i++]=sk; - } while (sk!=NOSKILL); - while (teaching && student) { - if (student->faction == u->faction) { + if (getparam(u->faction->locale)==P_ANY) { + unit * student = r->units; + skill_t teachskill[MAXSKILLS]; + int i = 0; + do { + sk = getskill(u->faction->locale); + teachskill[i++]=sk; + } while (sk!=NOSKILL); + while (teaching && student) { + if (student->faction == u->faction) { #ifdef NEW_DAEMONHUNGER_RULE - if (LongHunger(student)) continue; -#else - if (fval(student, UFL_HUNGER)) continue; -#endif - if (get_keyword(student->thisorder) == K_STUDY) { - /* Input ist nun von student->thisorder !! */ - init_tokens(student->thisorder); - skip_token(); - sk = getskill(student->faction->locale); - if (sk!=NOSKILL && teachskill[0]!=NOSKILL) { - for (i=0;teachskill[i]!=NOSKILL;++i) if (sk==teachskill[i]) break; - sk = teachskill[i]; - } - if (sk != NOSKILL && eff_skill_study(u, sk, r)-TEACHDIFFERENCE > eff_skill_study(student, sk, r)) { - teaching -= teach_unit(u, student, teaching, sk, true, &academy); - } - } - } - student = student->next; - } -#ifdef TEACH_FRIENDS - while (teaching && student) { - if (student->faction != u->faction && alliedunit(u, student->faction, HELP_GUARD)) { -#ifdef NEW_DAEMONHUNGER_RULE - if (LongHunger(student)) continue; + if (LongHunger(student)) continue; #else if (fval(student, UFL_HUNGER)) continue; #endif - if (get_keyword(student->thisorder) == K_STUDY) { - /* Input ist nun von student->thisorder !! */ + if (get_keyword(student->thisorder) == K_STUDY) { + /* Input ist nun von student->thisorder !! */ init_tokens(student->thisorder); skip_token(); - sk = getskill(student->faction->locale); - if (sk != NOSKILL && eff_skill_study(u, sk, r)-TEACHDIFFERENCE >= eff_skill(student, sk, r)) { - teaching -= teach_unit(u, student, teaching, sk, true, &academy); - } - } - } - student = student->next; - } -#endif - } - else -#endif - for (;;) { - /* Da später tokens aus (u2->thisorder) verwendet werden, - * muß hier wieder von vorne gelesen werden. Also merken wir uns, an - * welcher Stelle wir hier waren... - * TODO: Optimierung wäre hier wirklich sinnvoll - * - * Beispiel count = 1: LEHRE 101 102 103 - * - * LEHRE und 101 wird gelesen (und ignoriert), und dann wird - * getunit die einheit 102 zurück liefern. */ - - init_tokens(u->thisorder); - skip_token(); - for (j = count; j; j--) getstrtoken(); - - u2 = getunit(r, u->faction); - - /* Falls keine Unit gefunden, abbrechen - außer es gibt überhaupt keine - * Unit, dann gibt es zusätzlich noch einen Fehler */ - - if (!u2) { - - /* Finde den string, der den Fehler verursacht hat */ - - init_tokens(u->thisorder); - skip_token(); - for (j = count; j; j--) getstrtoken(); - - s = getstrtoken(); - - /* Falls es keinen String gibt, ist die Liste der Einheiten zuende */ - - if (!s[0]) - return; - - /* Beginne die Fehlermeldung */ - - strcpy(buf, "Die Einheit '"); - - if (findparam(s, u->faction->locale) == P_TEMP) { - /* Für: "Die Einheit 'TEMP ZET' wurde nicht gefunden" oder "Die Einheit - * 'TEMP' wurde nicht gefunden" */ - - scat(s); - s = getstrtoken(); - if (s[0]) - scat(" "); - - /* Um nachher weiter einlesen zu koennen */ - count++; - } - scat(s); - scat("' wurde nicht gefunden"); - mistake(u, u->thisorder, buf, MSG_EVENT); - - count++; - continue; - } - /* Defaultorder zusammenbauen. TEMP-Einheiten werden automatisch in - * ihre neuen Nummern übersetzt. */ - strcat(order, " "); - strcat(order, unitid(u2)); - set_order(&u->lastorder, parse_order(order, u->faction->locale)); - free_order(u->lastorder); /* parse_order & set_order have each increased the refcount */ - - /* Wir müssen nun hochzählen, wieviele Einheiten wir schon abgearbeitet - * haben, damit mit getstrtoken() die richtige Einheit geholt werden kann. - * Falls u2 ein Alias hat, ist sie neu, und es wurde ein TEMP verwendet, um - * sie zu beschreiben. */ - - count++; - if (ualias(u2)) - count++; - - if (get_keyword(u2->thisorder) != K_STUDY) { - add_message(&u->faction->msgs, - msg_feedback(u, u->thisorder, "teach_nolearn", "student", u2)); - continue; - } - /* Input ist nun von u2->thisorder !! */ - init_tokens(u2->thisorder); - skip_token(); - sk = getskill(u2->faction->locale); - if (sk == NOSKILL) { - add_message(&u->faction->msgs, - msg_feedback(u, u->thisorder, "teach_nolearn", "student", u2)); - continue; - } - - /* u is teacher, u2 is student */ - if (eff_skill_study(u2, sk, r) > eff_skill_study(u, sk, r)-TEACHDIFFERENCE) { - add_message(&u->faction->msgs, - msg_feedback(u, u->thisorder, "teach_asgood", "student", u2)); - continue; - } - if (sk == SK_MAGIC) { - /* ist der Magier schon spezialisiert, so versteht er nur noch - * Lehrer seines Gebietes */ - if (find_magetype(u2) != 0 - && find_magetype(u) != find_magetype(u2)) - { - sprintf(buf, "%s versteht unsere Art von Magie nicht", unitname(u2)); - mistake(u, u->thisorder, buf, MSG_EVENT); - continue; - } - } - - teaching -= teach_unit(u, u2, teaching, sk, false, &academy); - + sk = getskill(student->faction->locale); + if (sk!=NOSKILL && teachskill[0]!=NOSKILL) { + for (i=0;teachskill[i]!=NOSKILL;++i) if (sk==teachskill[i]) break; + sk = teachskill[i]; } - if (academy) { - academy = academy/30; - learn_skill(u, sk, academy/30.0/TEACHNUMBER); - } + if (sk != NOSKILL && eff_skill_study(u, sk, r)-TEACHDIFFERENCE > eff_skill_study(student, sk, r)) { + teaching -= teach_unit(u, student, teaching, sk, true, &academy); + } + } + } + student = student->next; + } +#ifdef TEACH_FRIENDS + while (teaching && student) { + if (student->faction != u->faction && alliedunit(u, student->faction, HELP_GUARD)) { +#ifdef NEW_DAEMONHUNGER_RULE + if (LongHunger(student)) continue; +#else + if (fval(student, UFL_HUNGER)) continue; +#endif + if (get_keyword(student->thisorder) == K_STUDY) { + /* Input ist nun von student->thisorder !! */ + init_tokens(student->thisorder); + skip_token(); + sk = getskill(student->faction->locale); + if (sk != NOSKILL && eff_skill_study(u, sk, r)-TEACHDIFFERENCE >= eff_skill(student, sk, r)) { + teaching -= teach_unit(u, student, teaching, sk, true, &academy); + } + } + } + student = student->next; + } +#endif + } + else +#endif + { + static char zOrder[BUFSIZE]; + order * new_order; + + strcpy(zOrder, locale_string(u->faction->locale, keywords[K_TEACH])); + init_tokens(ord); + skip_token(); + for (;;) { + + u2 = getunit(r, u->faction); + + /* Falls keine Unit gefunden, abbrechen - außer es gibt überhaupt keine + * Unit, dann gibt es zusätzlich noch einen Fehler */ + + if (!u2) { + + /* Finde den string, der den Fehler verursacht hat */ + parser_pushstate(); + init_tokens(ord); + skip_token(); + for (j = count; j; j--) { + /* skip over the first 'count' units */ + getunit(r, u->faction); + } + + s = getstrtoken(); + + if (!s[0]) { + /* Falls es keinen String gibt, ist einfach nur die Liste der Einheiten + * zu ende. dann raus hier */ + parser_popstate(); + break; + } + + /* Beginne die Fehlermeldung */ + + strcpy(buf, "Die Einheit '"); + + if (findparam(s, u->faction->locale) == P_TEMP) { + /* Für: "Die Einheit 'TEMP ZET' wurde nicht gefunden" oder "Die Einheit + * 'TEMP' wurde nicht gefunden" */ + + scat(s); + s = getstrtoken(); + if (s[0]) + scat(" "); + + /* count++; -- unnötig/alt? Um nachher weiter einlesen zu koennen */ + + } + scat(s); + scat("' wurde nicht gefunden"); + mistake(u, ord, buf, MSG_EVENT); + + count++; + parser_popstate(); + continue; + } + /* Defaultorder zusammenbauen. TEMP-Einheiten werden automatisch in + * ihre neuen Nummern übersetzt. */ + strcat(zOrder, " "); + strcat(zOrder, unitid(u2)); + + /* Wir müssen nun hochzählen, wieviele Einheiten wir schon abgearbeitet + * haben, damit mit getstrtoken() die richtige Einheit geholt werden kann. + * Falls u2 ein Alias hat, ist sie neu, und es wurde ein TEMP verwendet, um + * sie zu beschreiben. */ + + count++; + + if (get_keyword(u2->thisorder) != K_STUDY) { + add_message(&u->faction->msgs, + msg_feedback(u, ord, "teach_nolearn", "student", u2)); + continue; + } + /* Input ist nun von u2->thisorder !! */ + init_tokens(u2->thisorder); + skip_token(); + sk = getskill(u2->faction->locale); + if (sk == NOSKILL) { + add_message(&u->faction->msgs, + msg_feedback(u, ord, "teach_nolearn", "student", u2)); + continue; + } + + /* u is teacher, u2 is student */ + if (eff_skill_study(u2, sk, r) > eff_skill_study(u, sk, r)-TEACHDIFFERENCE) { + add_message(&u->faction->msgs, + msg_feedback(u, ord, "teach_asgood", "student", u2)); + continue; + } + if (sk == SK_MAGIC) { + /* ist der Magier schon spezialisiert, so versteht er nur noch + * Lehrer seines Gebietes */ + if (find_magetype(u2) != 0 + && find_magetype(u) != find_magetype(u2)) + { + sprintf(buf, "%s versteht unsere Art von Magie nicht", unitname(u2)); + mistake(u, ord, buf, MSG_EVENT); + continue; + } + } + + teaching -= teach_unit(u, u2, teaching, sk, false, &academy); + + } + new_order = parse_order(zOrder, u->faction->locale); +#ifdef LASTORDER + set_order(&u->lastorder, new_order); +#else + copy_order(ord, new_order); +#endif + free_order(new_order); /* parse_order & set_order have each increased the refcount */ + } + if (academy && sk!=NOSKILL) { + academy = academy/30; /* anzahl gelehrter wochen, max. 10 */ + learn_skill(u, sk, academy/30.0/TEACHNUMBER); + } } /* ------------------------------------------------------------- */ diff --git a/src/common/kernel/build.c b/src/common/kernel/build.c index 30dceb7e4..375b29e4c 100644 --- a/src/common/kernel/build.c +++ b/src/common/kernel/build.c @@ -795,7 +795,7 @@ maxbuild(const unit * u, const construction * cons) /** old build routines */ void -build_building(unit * u, const building_type * btype, int want) +build_building(unit * u, const building_type * btype, int want, order * ord) { region * r = u->region; boolean newbuilding = false; @@ -804,9 +804,10 @@ build_building(unit * u, const building_type * btype, int want) /* einmalige Korrektur */ static char buffer[8 + IDSIZE + 1 + NAMESIZE + 1]; const char *string2; + order * new_order; if (eff_skill(u, SK_BUILDING, r) == 0) { - cmistake(u, u->thisorder, 101, MSG_PRODUCE); + cmistake(u, ord, 101, MSG_PRODUCE); return; } @@ -825,7 +826,7 @@ build_building(unit * u, const building_type * btype, int want) b = u->building; } else { /* keine neue Burg anfangen wenn eine Nummer angegeben war */ - cmistake(u, u->thisorder, 6, MSG_PRODUCE); + cmistake(u, ord, 6, MSG_PRODUCE); return; } } @@ -835,17 +836,17 @@ build_building(unit * u, const building_type * btype, int want) if (b && fval(btype, BTF_UNIQUE) && buildingtype_exists(r, btype)) { /* only one of these per region */ - cmistake(u, u->thisorder, 93, MSG_PRODUCE); + cmistake(u, ord, 93, MSG_PRODUCE); return; } if (besieged(u)) { /* units under siege can not build */ - cmistake(u, u->thisorder, 60, MSG_PRODUCE); + cmistake(u, ord, 60, MSG_PRODUCE); return; } if (btype->flags & BTF_NOBUILD) { /* special building, cannot be built */ - cmistake(u, u->thisorder, 221, MSG_PRODUCE); + cmistake(u, ord, 221, MSG_PRODUCE); return; } @@ -870,7 +871,7 @@ build_building(unit * u, const building_type * btype, int want) switch (built) { case ECOMPLETE: /* the building is already complete */ - cmistake(u, u->thisorder, 4, MSG_PRODUCE); + cmistake(u, ord, 4, MSG_PRODUCE); return; case ENOMATERIALS: { /* something missing from the list of materials */ @@ -887,14 +888,14 @@ build_building(unit * u, const building_type * btype, int want) ); ch = ch+strlen(ch); } - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "build_required", + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "build_required", "required", buf)); return; } case ELOWSKILL: case ENEEDSKILL: /* no skill, or not enough skill points to build */ - cmistake(u, u->thisorder, 50, MSG_PRODUCE); + cmistake(u, ord, 50, MSG_PRODUCE); return; } @@ -928,8 +929,14 @@ build_building(unit * u, const building_type * btype, int want) strcpy(buffer, locale_string(u->faction->locale, "defaultorder")); else sprintf(buffer, "%s %d %s %s", locale_string(u->faction->locale, keywords[K_MAKE]), want-built, string2, buildingid(b)); - set_order(&u->lastorder, parse_order(buffer, u->faction->locale)); - free_order(u->lastorder); + + new_order = parse_order(buffer, u->faction->locale); +#ifdef LASTORDER + set_order(&u->lastorder, new_order); +#else + copy_order(ord, new_order); +#endif + free_order(new_order); b->size += built; update_lighthouse(b); @@ -976,19 +983,20 @@ build_ship(unit * u, ship * sh, int want) } void -create_ship(region * r, unit * u, const struct ship_type * newtype, int want) +create_ship(region * r, unit * u, const struct ship_type * newtype, int want, order * ord) { static char buffer[IDSIZE + 2 * KEYWORDSIZE + 3]; ship *sh; int msize; const construction * cons = newtype->construction; + order * new_order; if (!eff_skill(u, SK_SHIPBUILDING, r)) { - cmistake(u, u->thisorder, 100, MSG_PRODUCE); + cmistake(u, ord, 100, MSG_PRODUCE); return; } if (besieged(u)) { - cmistake(u, u->thisorder, 60, MSG_PRODUCE); + cmistake(u, ord, 60, MSG_PRODUCE); return; } @@ -996,13 +1004,13 @@ create_ship(region * r, unit * u, const struct ship_type * newtype, int want) if (eff_skill(u, cons->skill, r) < cons->minskill) { sprintf(buf, "Um %s zu bauen, braucht man ein Talent von " "mindestens %d.", newtype->name[1], cons->minskill); - mistake(u, u->thisorder, buf, MSG_PRODUCE); + mistake(u, ord, buf, MSG_PRODUCE); return; } msize = maxbuild(u, cons); if (msize==0) { - cmistake(u, u->thisorder, 88, MSG_PRODUCE); + cmistake(u, ord, 88, MSG_PRODUCE); return; } if (want>0) want = min(want, msize); @@ -1015,8 +1023,14 @@ create_ship(region * r, unit * u, const struct ship_type * newtype, int want) fset(u, UFL_OWNER); sprintf(buffer, "%s %s %s", locale_string(u->faction->locale, keywords[K_MAKE]), locale_string(u->faction->locale, parameters[P_SHIP]), shipid(sh)); - set_order(&u->lastorder, parse_order(buffer, u->faction->locale)); - free_order(u->lastorder); + + new_order = parse_order(buffer, u->faction->locale); +#ifdef LASTORDER + set_order(&u->lastorder, new_order); +#else + copy_order(ord, new_order); +#endif + free_order(new_order); build_ship(u, sh, want); } diff --git a/src/common/kernel/build.h b/src/common/kernel/build.h index 7ed067268..1a0e44096 100644 --- a/src/common/kernel/build.h +++ b/src/common/kernel/build.h @@ -68,7 +68,7 @@ extern boolean can_contact(const struct region *r, const struct unit *u, const s void do_siege(void); void build_road(struct region * r, struct unit * u, int size, direction_t d); -void create_ship(struct region * r, struct unit * u, const struct ship_type * newtype, int size); +void create_ship(struct region * r, struct unit * u, const struct ship_type * newtype, int size, struct order * ord); void continue_ship(struct region * r, struct unit * u, int size); struct building * getbuilding(const struct region * r); diff --git a/src/common/kernel/building.h b/src/common/kernel/building.h index c690d5920..ec5852e2e 100644 --- a/src/common/kernel/building.h +++ b/src/common/kernel/building.h @@ -112,7 +112,7 @@ extern const char * buildingtype(const struct building * b, int bsize); extern const char * buildingname(const struct building * b); extern int buildingcapacity(const struct building * b); extern struct building *new_building(const struct building_type * typ, struct region * r, const struct locale * lang); -void build_building(struct unit * u, const struct building_type * typ, int size); +void build_building(struct unit * u, const struct building_type * typ, int size, struct order * ord); /* Alte Gebäudetypen: */ diff --git a/src/common/kernel/eressea.c b/src/common/kernel/eressea.c index 4c1e1b4ae..ce77f7701 100644 --- a/src/common/kernel/eressea.c +++ b/src/common/kernel/eressea.c @@ -344,7 +344,6 @@ const char *keywords[MAXKEYWORDS] = "BANNER", "ARBEITEN", "ATTACKIEREN", - "BIETEN", "BEKLAUEN", "BELAGERE", "BENENNEN", @@ -398,7 +397,6 @@ const char *keywords[MAXKEYWORDS] = "MAGIEGEBIET", "PIRATERIE", "NEUSTART", - "WARTEN", "GRUPPE", "OPFERE", "BETEN", @@ -1259,21 +1257,50 @@ count_maxmigrants(const faction * f) /* GET STR, I zur Eingabe von Daten liest diese aus dem Buffer, der beim ersten * Aufruf inititialisiert wird? */ -static const unsigned char *current_token; +typedef struct parser_state { + const unsigned char *current_token; + char * current_cmd; + struct parser_state * next; +} parser_state; + +static parser_state * state; void init_tokens_str(const char * initstr) { - current_token = (const unsigned char *)initstr; + if (state==NULL) { + state = malloc(sizeof(parser_state)); + state->current_cmd = NULL; + } + state->current_token = (const unsigned char *)initstr; } void init_tokens(const struct order * ord) { - static char * cmd = NULL; - if (cmd!=NULL) free(cmd); - cmd = getcommand(ord); - init_tokens_str(cmd); + if (state==NULL) state = malloc(sizeof(parser_state)); + else if (state->current_cmd!=NULL) free(state->current_cmd); + state->current_cmd = getcommand(ord); + init_tokens_str(state->current_cmd); +} + +void +parser_pushstate(void) +{ + parser_state * new_state = malloc(sizeof(parser_state)); + new_state->current_cmd = NULL; + new_state->current_token = NULL; + new_state->next = state; + state = new_state; +} + +void +parser_popstate(void) +{ + parser_state * new_state = state->next; + if (state->current_cmd!=NULL) free(state->current_cmd); + free(state); + state = new_state; } void @@ -1281,23 +1308,23 @@ skip_token(void) { char quotechar = 0; - while (isspace(*current_token)) ++current_token; - while (*current_token) { - if (isspace(*current_token) && quotechar==0) { + while (isspace(*state->current_token)) ++state->current_token; + while (*state->current_token) { + if (isspace(*state->current_token) && quotechar==0) { return; } else { - switch(*current_token) { + switch(*state->current_token) { case '"': case '\'': - if (*current_token==quotechar) return; - quotechar = *current_token; + if (*state->current_token==quotechar) return; + quotechar = *state->current_token; break; case ESCAPE_CHAR: - ++current_token; + ++state->current_token; break; } } - ++current_token; + ++state->current_token; } } @@ -1377,13 +1404,13 @@ igetstrtoken(const char * initstr) init_tokens_str(initstr); } - return parse_token((const char**)¤t_token); + return parse_token((const char**)&state->current_token); } const char * getstrtoken(void) { - return parse_token((const char**)¤t_token); + return parse_token((const char**)&state->current_token); } int @@ -1870,12 +1897,17 @@ unit * create_unit(region * r, faction * f, int number, const struct race *urace, int id, const char * dname, unit *creator) { unit * u = calloc(1, sizeof(unit)); + order * deford = default_order(f->locale); assert(urace); assert(f->alive); u_setfaction(u, f); set_order(&u->thisorder, NULL); - set_order(&u->lastorder, default_order(f->locale)); +#ifdef LASTORDER + set_order(&u->lastorder, deford); +#else + addlist(&u->orders, deford); +#endif u_seteffstealth(u, -1); u->race = urace; u->irace = urace; @@ -2600,7 +2632,10 @@ init_used_faction_ids(void) void make_undead_unit(unit * u) { +#ifdef LASTORDER set_order(&u->lastorder, NULL); +#endif + free_orders(&u->orders); name_unit(u); fset(u, UFL_ISNEW); } diff --git a/src/common/kernel/eressea.h b/src/common/kernel/eressea.h index 4740a52de..524b7c014 100644 --- a/src/common/kernel/eressea.h +++ b/src/common/kernel/eressea.h @@ -161,6 +161,7 @@ struct building_type; #define SAVEALLIANCE_VERSION 317 #define CLAIM_VERSION 318 #define BACTION_VERSION 319 /* building action gets a param string */ +#define NOLASTORDER_VERSION 320 /* do not use lastorder */ #define MIN_VERSION ALLIANCES_VERSION #define REGIONOWNERS_VERSION 400 @@ -168,8 +169,10 @@ struct building_type; #ifdef REGIONOWNERS # define RELEASE_VERSION REGIONOWNERS_VERSION -#else +#elif defined(LASTORDER) # define RELEASE_VERSION BACTION_VERSION +#else +# define RELEASE_VERSION NOLASTORDER_VERSION #endif #if RESOURCE_CONVERSION @@ -377,7 +380,6 @@ enum { K_BANNER, K_WORK, K_ATTACK, - K_BIETE, K_STEAL, K_BESIEGE, K_NAME, @@ -431,7 +433,6 @@ enum { K_MAGIEGEBIET, K_PIRACY, K_RESTART, - K_WAIT, K_GROUP, K_SACRIFICE, K_PRAY, @@ -944,6 +945,8 @@ extern void init_tokens_str(const char * initstr); /* initialize token parsing * extern void init_tokens(const struct order * ord); /* initialize token parsing */ extern void skip_token(void); extern const char * parse_token(const char ** str); +extern void parser_pushstate(void); +extern void parser_popstate(void); extern skill_t findskill(const char *s, const struct locale * lang); diff --git a/src/common/kernel/karma.c b/src/common/kernel/karma.c index baa1eaffb..ff7e4f8d1 100644 --- a/src/common/kernel/karma.c +++ b/src/common/kernel/karma.c @@ -14,6 +14,7 @@ /* TODO: enum auf fst_ umstellen. Pointer auf Display-Routine */ #include #include "eressea.h" + #include "karma.h" /* kernel includes */ diff --git a/src/common/kernel/magic.c b/src/common/kernel/magic.c index 95231cba0..5d5176cd9 100644 --- a/src/common/kernel/magic.c +++ b/src/common/kernel/magic.c @@ -2004,7 +2004,7 @@ new_castorder(void *u, unit *u2, spell *sp, region *r, int lev, corder->force = force; corder->rt = r; corder->distance = range; - corder->order = copy_order(ord); + corder->order = duplicate_order(ord); corder->par = p; return corder; diff --git a/src/common/kernel/message.c b/src/common/kernel/message.c index d77aadef7..58708c7f7 100644 --- a/src/common/kernel/message.c +++ b/src/common/kernel/message.c @@ -332,7 +332,7 @@ mistake(const unit * u, struct order * ord, const char *comment, int mtype) if (u->faction->no != MONSTER_FACTION) { char * cmt = strdup(comment); ADDMSG(&u->faction->msgs, msg_message("mistake", - "command error unit region", copy_order(ord), cmt, u, u->region)); + "command error unit region", duplicate_order(ord), cmt, u, u->region)); } } @@ -345,7 +345,7 @@ cmistake(const unit * u, struct order *ord, int mno, int mtype) if (u->faction->no == MONSTER_FACTION) return; sprintf(ebuf, "error%d", mno); ADDMSG(&u->faction->msgs, msg_message(ebuf, - "command unit region", copy_order(ord), u, u->region)); + "command unit region", duplicate_order(ord), u, u->region)); } extern unsigned int new_hashstring(const char* s); diff --git a/src/common/kernel/movement.c b/src/common/kernel/movement.c index d4042b710..9de0fc0f5 100644 --- a/src/common/kernel/movement.c +++ b/src/common/kernel/movement.c @@ -860,7 +860,7 @@ static const char *shortdirections[MAXDIRECTIONS] = }; static void -cycle_route(unit *u, int gereist) +cycle_route(order * ord, unit *u, int gereist) { int cm = 0; char tail[1024]; @@ -869,13 +869,14 @@ cycle_route(unit *u, int gereist) direction_t d = NODIRECTION; boolean paused = false; boolean pause; + order * norder; - if (get_keyword(u->thisorder) != K_ROUTE) return; + if (get_keyword(ord) != K_ROUTE) return; tail[0] = '\0'; strcpy(neworder, locale_string(u->faction->locale, keywords[K_ROUTE])); - init_tokens(u->thisorder); + init_tokens(ord); skip_token(); for (cm=0;;++cm) { @@ -909,8 +910,13 @@ cycle_route(unit *u, int gereist) } strcat(neworder, tail); - set_order(&u->lastorder, parse_order(neworder, u->faction->locale)); - free_order(u->lastorder); /* parse_order & set_order have each increased the refcount */ + norder = parse_order(neworder, u->faction->locale); +#ifdef LASTORDER + set_order(&u->lastorder, norder); +#else + copy_order(ord, norder); +#endif + free_order(norder); } static boolean @@ -1311,7 +1317,7 @@ travel_route(unit * u, region_list * route_begin, region_list * route_end, order region * next = r; setguard(u, GUARD_NONE); - cycle_route(u, steps); + cycle_route(ord, u, steps); if (mode==TRAVEL_RUNNING) { walkmode = 0; @@ -1659,7 +1665,7 @@ sail(unit * u, order * ord, boolean move_on_land, region_list **routep) unit * hafenmeister; /* nachdem alle Richtungen abgearbeitet wurden, und alle Einheiten * transferiert wurden, kann der aktuelle Befehl gelöscht werden. */ - cycle_route(u, step); + cycle_route(ord, u, step); set_order(&u->thisorder, NULL); set_coast(sh, last_point, current_point); diff --git a/src/common/kernel/order.c b/src/common/kernel/order.c index 93e636614..71ae03442 100644 --- a/src/common/kernel/order.c +++ b/src/common/kernel/order.c @@ -26,6 +26,16 @@ static int nlocales = 0; #undef SHORT_STRINGS +void +copy_order(order * dst, const order * src) +{ + if (dst->_str) free(dst->_str); + dst->_str = strdup(src->_str); + dst->_keyword = src->_keyword; + dst->_lindex = src->_lindex; + dst->_persistent = src->_persistent; +} + keyword_t get_keyword(const order * ord) { @@ -70,7 +80,7 @@ free_order(order * ord) } order * -copy_order(order * ord) +duplicate_order(order * ord) { if (ord!=NULL) ++ord->_refcount; return ord; @@ -81,7 +91,7 @@ set_order(struct order ** destp, struct order * src) { if (*destp==src) return; free_order(*destp); - *destp = copy_order(src); + *destp = duplicate_order(src); } void @@ -156,19 +166,82 @@ parse_order(const char * s, const struct locale * lang) } boolean -is_persistent(const order * cmd) +is_exclusive(const order * ord) { - switch (cmd->_keyword) { + const struct locale * lang = locale_array[ord->_lindex]; + param_t param; + + switch (ord->_keyword) { + case K_MOVE: + case K_WEREWOLF: + /* these should not become persistent */ + case K_ROUTE: + case K_DRIVE: + case K_WORK: + case K_BESIEGE: + case K_ENTERTAIN: + case K_TAX: + case K_RESEARCH: + case K_SPY: + case K_STEAL: + case K_SABOTAGE: + case K_STUDY: + case K_TEACH: + case K_ZUECHTE: + case K_PIRACY: + return true; + +#if GROWING_TREES + case K_PFLANZE: + return true; +#endif + + case K_FOLLOW: + /* FOLLOW is only a long order if we are following a ship. */ + parser_pushstate(); + init_tokens(ord); + skip_token(); + param = getparam(lang); + parser_popstate(); + + if (param == P_SHIP) return true; + break; + + case K_MAKE: + /* Falls wir MACHE TEMP haben, ignorieren wir es. Alle anderen + * Arten von MACHE zaehlen aber als neue defaults und werden + * behandelt wie die anderen (deswegen kein break nach case + * K_MAKE) - und in thisorder (der aktuelle 30-Tage Befehl) + * abgespeichert). */ + parser_pushstate(); + init_tokens(ord); /* initialize token-parser */ + skip_token(); + param = getparam(lang); + parser_popstate(); + + if (param != P_TEMP) return true; + break; + } + return false; +} + +boolean +is_persistent(const order * ord) +{ + boolean persist = ord->_persistent!=0; + switch (ord->_keyword) { + case K_MOVE: + case K_WEREWOLF: case NOKEYWORD: + /* lang, aber niemals persistent! */ return false; + case K_KOMMENTAR: case K_LIEFERE: return true; } -#ifdef AT_PERSISTENT - if (cmd->_persistent) return true; -#endif /* Nur kurze Befehle! */ - return false; + + return persist || is_exclusive(ord); } char * diff --git a/src/common/kernel/order.h b/src/common/kernel/order.h index 4f5194b4e..3e43ad27c 100644 --- a/src/common/kernel/order.h +++ b/src/common/kernel/order.h @@ -37,9 +37,10 @@ typedef struct order { /* constructor */ extern struct order * parse_order(const char * s, const struct locale * lang); +extern void copy_order(order * dst, const order * src); /* reference counted copies of orders: */ -extern struct order * copy_order(struct order * ord); +extern struct order * duplicate_order(struct order * ord); extern void free_order(struct order * ord); extern void free_orders(struct order ** olist); @@ -48,6 +49,7 @@ extern keyword_t get_keyword(const struct order * ord); extern void set_order(struct order ** destp, struct order * src); extern char * getcommand(const struct order * ord); extern boolean is_persistent(const struct order *ord); +extern boolean is_exclusive(const struct order *ord); extern char * write_order(const struct order * ord, const struct locale * lang, char * buffer, size_t size); #ifdef __cplusplus } diff --git a/src/common/kernel/pathfinder.c b/src/common/kernel/pathfinder.c index d73608871..bebb4af51 100644 --- a/src/common/kernel/pathfinder.c +++ b/src/common/kernel/pathfinder.c @@ -111,7 +111,7 @@ regions_in_range(struct region * start, int maxdist, boolean (*allowed)(const st region * rn = rconnect(r, d); if (rn==NULL) continue; if (fval(rn, FL_MARK)) continue; /* already been there */ - if (!allowed(r, rn)) continue; /* can't go there */ + if (allowed && !allowed(r, rn)) continue; /* can't go there */ /* add the region to the list of available ones. */ add_regionlist(&rlist, rn); diff --git a/src/common/kernel/reports.c b/src/common/kernel/reports.c index 711ab7ade..b5c2d72b5 100644 --- a/src/common/kernel/reports.c +++ b/src/common/kernel/reports.c @@ -414,6 +414,7 @@ bufunit(const faction * f, const unit * u, int indent, int mode) } } } +#ifdef LASTORDER if (!isbattle && u->lastorder) { char * cmd = getcommand(u->lastorder); scat(", \""); @@ -421,6 +422,7 @@ bufunit(const faction * f, const unit * u, int indent, int mode) scat("\""); free(cmd); } +#endif } i = 0; diff --git a/src/common/kernel/save.c b/src/common/kernel/save.c index adf274db8..d7414175f 100644 --- a/src/common/kernel/save.c +++ b/src/common/kernel/save.c @@ -1101,7 +1101,7 @@ readunit(FILE * F) } } else u->flags = ri(F) & ~UFL_DEBUG; - /* Kurze persistente Befehle einlesen */ + /* Persistente Befehle einlesen */ free_orders(&u->orders); freadstr(F, buf, sizeof(buf)); while (*buf != 0) { @@ -1109,8 +1109,19 @@ readunit(FILE * F) if (ord!=NULL) addlist(&u->orders, ord); freadstr(F, buf, sizeof(buf)); } - freadstr(F, buf, sizeof(buf)); - u->lastorder = parse_order(buf, u->faction->locale); + if (global.data_versionfaction->locale); + if (ord!=NULL) { +#ifdef LASTORDER + set_order(&u->lastorder, ord); + free_order(ord); +#else + addlist(&u->orders, ord); +#endif + } + } set_order(&u->thisorder, NULL); assert(u->number >= 0); @@ -1219,9 +1230,11 @@ writeunit(FILE * F, const unit * u) /* write an empty string to terminate the list */ fwriteorder(F, NULL, u->faction->locale); wnl(F); +#if RELEASE_VERSIONlastorder, u->faction->locale); wnl(F); +#endif assert(u->number >= 0); assert(u->race); diff --git a/src/common/kernel/unit.c b/src/common/kernel/unit.c index 4aa25a04c..f8046f072 100644 --- a/src/common/kernel/unit.c +++ b/src/common/kernel/unit.c @@ -814,7 +814,9 @@ u_setfaction(unit * u, faction * f) join_group(u, NULL); free_orders(&u->orders); set_order(&u->thisorder, NULL); +#ifdef LASTORDER set_order(&u->lastorder, NULL); +#endif } if (u->prevF) u->prevF->nextF = u->nextF; else if (u->faction) { diff --git a/src/common/kernel/unit.h b/src/common/kernel/unit.h index 6c15636d8..4a2f200d9 100644 --- a/src/common/kernel/unit.h +++ b/src/common/kernel/unit.h @@ -55,9 +55,9 @@ struct skill; /* Flags, die gespeichert werden sollen: */ #ifndef HEROES -# define UFL_SAVEMASK (UFL_NOAID | UFL_OWNER | UFL_PARTEITARNUNG | UFL_LOCKED | UFL_HUNGER | FFL_NOIDLEOUT | UFL_TAKEALL) +# define UFL_SAVEMASK (UFL_MOVED | UFL_NOAID | UFL_OWNER | UFL_PARTEITARNUNG | UFL_LOCKED | UFL_HUNGER | FFL_NOIDLEOUT | UFL_TAKEALL) #else -# define UFL_SAVEMASK (UFL_NOAID | UFL_OWNER | UFL_PARTEITARNUNG | UFL_LOCKED | UFL_HUNGER | FFL_NOIDLEOUT | UFL_TAKEALL | UFL_HERO) +# define UFL_SAVEMASK (UFL_MOVED | UFL_NOAID | UFL_OWNER | UFL_PARTEITARNUNG | UFL_LOCKED | UFL_HUNGER | FFL_NOIDLEOUT | UFL_TAKEALL | UFL_HERO) #endif #ifdef HEROES @@ -94,7 +94,9 @@ typedef struct unit { /* orders */ struct order *orders; struct order * thisorder; +#ifdef LASTORDER struct order * lastorder; +#endif /* race and illusionary race */ const struct race * race; diff --git a/src/common/modules/arena.c b/src/common/modules/arena.c index 95868304d..90a553117 100644 --- a/src/common/modules/arena.c +++ b/src/common/modules/arena.c @@ -376,8 +376,10 @@ guardian_faction(plane * pl, int id) u = createunit(r, f, 1, new_race[RC_GOBLIN]); set_string(&u->name, "Igjarjuks Auge"); set_item(u, I_RING_OF_INVISIBILITY, 1); - u->thisorder = calloc(1, sizeof(char)); - u->lastorder = calloc(1, sizeof(char)); + set_order(&u->thisorder, NULL); +#ifdef LASTORDER + set_order(&u->lastorder, NULL); +#endif fset(u, UFL_PARTEITARNUNG); set_money(u, 1000); } diff --git a/src/eressea/server.cpp b/src/eressea/server.cpp index e262c52dc..fe14d5511 100644 --- a/src/eressea/server.cpp +++ b/src/eressea/server.cpp @@ -114,6 +114,7 @@ extern "C" { extern char * g_resourcedir; extern boolean nonr; + extern boolean nosh; extern boolean nocr; extern boolean noreports; extern boolean nomer; @@ -471,6 +472,7 @@ usage(const char * prog, const char * arg) "--debug : schreibt Debug-Ausgaben in die Datei debug\n" "--nocr : keine CRs\n" "--nonr : keine Reports\n" + "--nosh : keine Mail-Skripte\n" "--crabsolute : absolute Koordinaten im CR\n" "--help : help\n", prog); return -1; @@ -509,6 +511,7 @@ read_args(int argc, char **argv, lua_State * luaState) else if (strcmp(argv[i]+2, "xml")==0) xmlfile = argv[++i]; else if (strcmp(argv[i]+2, "dirtyload")==0) dirtyload = true; else if (strcmp(argv[i]+2, "nonr")==0) nonr = true; + else if (strcmp(argv[i]+2, "nosh")==0) nosh = true; else if (strcmp(argv[i]+2, "lomem")==0) lomem = true; else if (strcmp(argv[i]+2, "nobattle")==0) nobattle = true; else if (strcmp(argv[i]+2, "nomonsters")==0) nomonsters = true;