unit::lastorder entfernt. Das Konzept eines einzelnen langen Befehles hat ausgedient, spätestens seit @ existiert.

This commit is contained in:
Enno Rehling 2005-04-30 17:07:46 +00:00
parent 9b0daeced4
commit 092b249060
27 changed files with 695 additions and 622 deletions

View File

@ -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();
}

View File

@ -173,9 +173,6 @@
<Filter
Name="Header"
Filter="*.h">
<File
RelativePath=".\aggressive.h">
</File>
<File
RelativePath=".\attributes.h">
</File>
@ -246,9 +243,6 @@
RelativePath=".\viewrange.h">
</File>
</Filter>
<File
RelativePath=".\aggressive.c">
</File>
<File
RelativePath=".\at_movement.c">
</File>

View File

@ -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);
}

View File

@ -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);
}
/* ------------------------------------------------------------- */

View File

@ -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();

View File

@ -32,7 +32,6 @@
/* attributes includes */
#include <attributes/targetregion.h>
#include <attributes/hate.h>
#include <attributes/aggressive.h>
/* spezialmonster */
#include <spells/alp.h>
@ -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()%100<MOVECHANCE || check_overpopulated(u))) {
move_monster(r, u);
} else {
boolean done = false;
if((u->race->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()%100<MOVECHANCE || check_overpopulated(u)) {
long_order = monster_move(r, u);
}
}
}
if (long_order==NULL) {
/* Ab hier noch nicht generalisierte Spezialbehandlungen. */
switch (old_race(u->race)) {
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
}
}
}
}
}

View File

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

View File

@ -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");
}

View File

@ -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);
}
}
/* ------------------------------------------------------------- */

View File

@ -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);
}

View File

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

View File

@ -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: */

View File

@ -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**)&current_token);
return parse_token((const char**)&state->current_token);
}
const char *
getstrtoken(void)
{
return parse_token((const char**)&current_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);
}

View File

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

View File

@ -14,6 +14,7 @@
/* TODO: enum auf fst_ umstellen. Pointer auf Display-Routine */
#include <config.h>
#include "eressea.h"
#include "karma.h"
/* kernel includes */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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_version<NOLASTORDER_VERSION) {
order * ord;
freadstr(F, buf, sizeof(buf));
ord = parse_order(buf, u->faction->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_VERSION<NOLASTORDER_VERSION
/* the current default order */
fwriteorder(F, u->lastorder, u->faction->locale);
wnl(F);
#endif
assert(u->number >= 0);
assert(u->race);

View File

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

View File

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

View File

@ -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);
}

View File

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