diff --git a/src/common/gamecode/economy.c b/src/common/gamecode/economy.c index 8a48bce93..dcc65c68c 100644 --- a/src/common/gamecode/economy.c +++ b/src/common/gamecode/economy.c @@ -995,93 +995,86 @@ gebaeude_stuerzt_ein(region * r, building * b) } void -maintain_buildings(boolean crash) +maintain_buildings(region * r, boolean crash) { - region * r; - for (r = regions; r; r = r->next) { - building **bp = &r->buildings; - while (*bp) { - building * b = *bp; - boolean maintained = maintain(b, !crash); + building **bp = &r->buildings; + while (*bp) { + building * b = *bp; + boolean maintained = maintain(b, !crash); - /* the second time, send a message */ - if (crash) { - if (!maintained && (rng_int() % 100 < EINSTURZCHANCE)) { - gebaeude_stuerzt_ein(r, b); - continue; - } else if (!fval(b, BLD_WORKING)) { - unit * u = buildingowner(r, b); - const char * msgtype = maintained?"maintenance_nowork":"maintenance_none"; - struct message * msg = msg_message(msgtype, "building", b); + /* the second time, send a message */ + if (crash) { + if (!maintained && (rng_int() % 100 < EINSTURZCHANCE)) { + gebaeude_stuerzt_ein(r, b); + continue; + } else if (!fval(b, BLD_WORKING)) { + unit * u = buildingowner(r, b); + const char * msgtype = maintained?"maintenance_nowork":"maintenance_none"; + struct message * msg = msg_message(msgtype, "building", b); - if (u) { - add_message(&u->faction->msgs, msg); - r_addmessage(r, u->faction, msg); - } else { - add_message(&r->msgs, msg); - } - msg_release(msg); + if (u) { + add_message(&u->faction->msgs, msg); + r_addmessage(r, u->faction, msg); + } else { + add_message(&r->msgs, msg); } + msg_release(msg); } - bp=&b->next; - } + } + bp=&b->next; } } void -economics(void) +economics(region *r) { - region *r; unit *u; + request *recruitorders = NULL; /* Geben vor Selbstmord (doquit)! Hier alle unmittelbaren Befehle. - * Rekrutieren vor allen Einnahmequellen. Bewachen JA vor Steuern - * eintreiben. */ + * Rekrutieren vor allen Einnahmequellen. Bewachen JA vor Steuern + * eintreiben. */ - for (r = regions; r; r = r->next) if (r->units) { - request *recruitorders = NULL; - - for (u = r->units; u; u = u->next) { - order * ord; - boolean destroyed = false; - for (ord = u->orders; ord; ord = ord->next) { - switch (get_keyword(ord)) { - case K_DESTROY: - if (!destroyed) { - if (destroy_cmd(u, ord)!=0) ord = NULL; - destroyed = true; - } - break; - - case K_GIVE: - case K_LIEFERE: - give_cmd(u, ord); - break; - - case K_FORGET: - forget_cmd(u, ord); - break; - - } - if (u->orders==NULL) break; - } - } - /* RECRUIT orders */ - - for (u = r->units; u; u = u->next) { - order * ord; - for (ord = u->orders; ord; ord = ord->next) { - if (get_keyword(ord) == K_RECRUIT) { - recruit(u, ord, &recruitorders); + for (u = r->units; u; u = u->next) { + order * ord; + boolean destroyed = false; + for (ord = u->orders; ord; ord = ord->next) { + switch (get_keyword(ord)) { + case K_DESTROY: + if (!destroyed) { + if (destroy_cmd(u, ord)!=0) ord = NULL; + destroyed = true; + } break; - } + + case K_GIVE: + case K_LIEFERE: + give_cmd(u, ord); + break; + + case K_FORGET: + forget_cmd(u, ord); + break; + + } + if (u->orders==NULL) break; + } + } + /* RECRUIT orders */ + + for (u = r->units; u; u = u->next) { + order * ord; + for (ord = u->orders; ord; ord = ord->next) { + if (get_keyword(ord) == K_RECRUIT) { + recruit(u, ord, &recruitorders); + break; } } - - if (recruitorders) expandrecruit(r, recruitorders); - } + + if (recruitorders) expandrecruit(r, recruitorders); + remove_empty_units_in_region(r); } /* ------------------------------------------------------------- */ diff --git a/src/common/gamecode/economy.h b/src/common/gamecode/economy.h index 8570b500d..417e6b3c0 100644 --- a/src/common/gamecode/economy.h +++ b/src/common/gamecode/economy.h @@ -47,11 +47,11 @@ extern int income(const struct unit * u); /* Wieviel Fremde eine Partei pro Woche aufnehmen kann */ #define MAXNEWBIES 5 -void economics(void); +void economics(struct region *r); void produce(void); enum { IC_WORK, IC_ENTERTAIN, IC_TAX, IC_TRADE, IC_TRADETAX, IC_STEAL, IC_MAGIC }; -void maintain_buildings(boolean crash); +void maintain_buildings(struct region * r, boolean crash); extern void add_spende(struct faction * f1, struct faction * f2, int betrag, struct region * r); #ifdef __cplusplus diff --git a/src/common/gamecode/laws.c b/src/common/gamecode/laws.c index a12fbc85e..ba6e6f2cb 100644 --- a/src/common/gamecode/laws.c +++ b/src/common/gamecode/laws.c @@ -1196,12 +1196,7 @@ parse_restart(void) /* Clear away debris of destroyed factions */ puts(" - beseitige leere Einheiten und leere Parteien..."); - remove_empty_units(); - - /* Auskommentiert: Wenn factions gelöscht werden, zeigen - * Spendenpointer ins Leere. */ - /* remove_empty_factions(); */ } /* ------------------------------------------------------------- */ @@ -1798,71 +1793,6 @@ deliverMail(faction * f, region * r, unit * u, const char *s, unit * receiver) } } -static int -prepare_mail_cmd(unit * u, struct order * ord) -{ - const char *s; - int n; - - init_tokens(ord); - skip_token(); /* skip the keyword */ - s = getstrtoken(); - - /* Falls kein Parameter, ist das eine Einheitsnummer; - * das Füllwort "AN" muß wegfallen, da gültige Nummer! */ - - if (strcasecmp(s, "to") == 0) s = getstrtoken(); - else if (strcasecmp(s, "an") == 0) s = getstrtoken(); - - switch (findparam(s, u->faction->locale)) { - case P_REGION: - break; - case P_FACTION: - break; - case P_UNIT: - { - region *r = u->region; - unit *u2; - boolean see = false; - - n = getid(); - - for (u2=r->units; u2; u2=u2->next) { - if (u2->no == n && cansee(u->faction, r, u2, 0)) { - see = true; - break; - } - } - - if (see == false) { - break; - } - - s = getstrtoken(); - if (!s[0]) { - break; - } - u2 = findunitr(r,n); - if(u2 && cansee(u->faction, r, u2, 0)) { - event_arg args[3]; - args[0].data.v = (void*)s; - args[0].type = "string"; - args[1].data.v = (void*)u; - args[1].type = "unit"; - args[2].type = NULL; - handle_event(&u2->attribs, "message", args); - } - } - break; - case P_BUILDING: - case P_GEBAEUDE: - break; - case P_SHIP: - break; - } - return 0; -} - static void mailunit(region * r, unit * u, int n, struct order * ord, const char * s) { @@ -1971,8 +1901,20 @@ mail_cmd(unit * u, struct order * ord) if (!s[0]) { cmistake(u, ord, 30, MSG_MESSAGE); break; + } else { + attrib * a = a_find(u2->attribs, &at_eventhandler); + if (a!=NULL) { + event_arg args[3]; + args[0].data.v = (void*)s; + args[0].type = "string"; + args[1].data.v = (void*)u; + args[1].type = "unit"; + args[2].type = NULL; + handle_event(a, "message", args); + } + + mailunit(r, u, n, ord, s); } - mailunit(r, u, n, ord, s); } break; @@ -2167,43 +2109,6 @@ send_cmd(unit * u, struct order * ord) return 0; } -static void -set_passw(void) -{ - region *r; - puts(" - setze Passwörter, Adressen und Format, Abstimmungen"); - - for (r = regions; r; r = r->next) { - unit *u; - for (u = r->units; u; u = u->next) { - struct order * ord; - for (ord = u->orders; ord; ord = ord->next) { - switch (get_keyword(ord)) { - case NOKEYWORD: - cmistake(u, ord, 22, MSG_EVENT); - break; - - case K_BANNER: - if (banner_cmd(u, ord)!=0) ord = NULL; - break; - - case K_EMAIL: - if (email_cmd(u, ord)!=0) ord = NULL; - break; - - case K_PASSWORD: - if (password_cmd(u, ord)!=0) ord = NULL; - break; - - case K_SEND: - if (send_cmd(u, ord)!=0) ord = NULL; - break; - } - } - } - } -} - static boolean display_item(faction *f, unit *u, const item_type * itype) { @@ -2667,7 +2572,6 @@ instant_orders(void) } } - parse(K_GROUP, group_cmd, false); for (r = regions; r; r = r->next) { unit * u; for (u = r->units; u; u = u->next) { @@ -2774,27 +2678,22 @@ guard_on_cmd(unit * u, struct order * ord) } static void -sinkships(void) +sinkships(region * r) { - region *r; + ship *sh; - /* Unbemannte Schiffe können sinken */ - for (r = regions; r; r = r->next) { - ship *sh; - - list_foreach(ship, r->ships, sh) { - if (fval(r->terrain, SEA_REGION) && (!enoughsailors(sh, r) || get_captain(sh)==NULL)) { - /* Schiff nicht seetüchtig */ - damage_ship(sh, 0.30); - } - if (shipowner(sh)==NULL) { - damage_ship(sh, 0.05); - } - if (sh->damage >= sh->size * DAMAGE_SCALE) - destroy_ship(sh); + list_foreach(ship, r->ships, sh) { + if (fval(r->terrain, SEA_REGION) && (!enoughsailors(sh, r) || get_captain(sh)==NULL)) { + /* Schiff nicht seetüchtig */ + damage_ship(sh, 0.30); } - list_next(sh); + if (shipowner(sh)==NULL) { + damage_ship(sh, 0.05); + } + if (sh->damage >= sh->size * DAMAGE_SCALE) + destroy_ship(sh); } + list_next(sh); } /* The following functions do not really belong here: */ @@ -3064,128 +2963,119 @@ declare_war(void) } #endif -static void -renumber(void) +static int +renumber_cmd(unit * u, order * ord) { - region *r; - const char *s; - unit * u; + const char * s; int i; + faction * f = u->faction; - for (r=regions;r;r=r->next) { - for (u=r->units;u;u=u->next) { - faction * f = u->faction; - struct order * ord; - for (ord = u->orders; ord; ord = ord->next) if (get_keyword(ord)==K_NUMBER) { - init_tokens(ord); - skip_token(); - s = getstrtoken(); - switch(findparam(s, u->faction->locale)) { + init_tokens(ord); + skip_token(); + s = getstrtoken(); + switch(findparam(s, u->faction->locale)) { - case P_FACTION: - s = getstrtoken(); - if (s && *s) { - int id = atoi36(s); - attrib * a = a_find(f->attribs, &at_number); - if (!a) a = a_add(&f->attribs, a_new(&at_number)); - a->data.i = id; - } - break; + case P_FACTION: + s = getstrtoken(); + if (s && *s) { + int id = atoi36(s); + attrib * a = a_find(f->attribs, &at_number); + if (!a) a = a_add(&f->attribs, a_new(&at_number)); + a->data.i = id; + } + break; - case P_UNIT: - s = getstrtoken(); - if(s == NULL || *s == 0) { - i = newunitid(); - } else { - i = atoi36(s); - if (i<=0 || i>MAX_UNIT_NR) { - cmistake(u, ord, 114, MSG_EVENT); - continue; - } + case P_UNIT: + s = getstrtoken(); + if (s == NULL || *s == 0) { + i = newunitid(); + } else { + i = atoi36(s); + if (i<=0 || i>MAX_UNIT_NR) { + cmistake(u, ord, 114, MSG_EVENT); + break; + } - if(forbiddenid(i)) { - cmistake(u, ord, 116, MSG_EVENT); - continue; - } + if (forbiddenid(i)) { + cmistake(u, ord, 116, MSG_EVENT); + break; + } - if(findunitg(i, r)) { - cmistake(u, ord, 115, MSG_EVENT); - continue; - } - } - uunhash(u); - if (!ualias(u)) { - attrib *a = a_add(&u->attribs, a_new(&at_alias)); - a->data.i = -u->no; - } - u->no = i; - uhash(u); - break; -#ifdef ALLOW_SHIP_RENUM - case P_SHIP: - if(!u->ship) { - cmistake(u,ord,144,MSG_EVENT); - continue; - } - if(!fval(u, UFL_OWNER)) { - cmistake(u,ord,146,MSG_EVENT); - continue; - } - s = getstrtoken(); - if(s == NULL || *s == 0) { - i = newcontainerid(); - } else { - i = atoi36(s); - if (i<=0 || i>MAX_CONTAINER_NR) { - cmistake(u,ord,114,MSG_EVENT); - continue; - } - if (findship(i) || findbuilding(i)) { - cmistake(u,ord,115,MSG_EVENT); - continue; - } - } - sunhash(u->ship); - u->ship->no = i; - shash(u->ship); - break; -#endif - case P_BUILDING: - case P_GEBAEUDE: - if(!u->building) { - cmistake(u,ord,145,MSG_EVENT); - continue; - } - if(!fval(u, UFL_OWNER)) { - cmistake(u,ord,148,MSG_EVENT); - continue; - } - s = getstrtoken(); - if(*s == 0) { - i = newcontainerid(); - } else { - i = atoi36(s); - if (i<=0 || i>MAX_CONTAINER_NR) { - cmistake(u,ord,114,MSG_EVENT); - continue; - } - if(findship(i) || findbuilding(i)) { - cmistake(u,ord,115,MSG_EVENT); - continue; - } - } - bunhash(u->building); - u->building->no = i; - bhash(u->building); - break; - - default: - cmistake(u, ord, 239, MSG_EVENT); + if (findunitg(i, u->region)) { + cmistake(u, ord, 115, MSG_EVENT); + break; } } - } + uunhash(u); + if (!ualias(u)) { + attrib *a = a_add(&u->attribs, a_new(&at_alias)); + a->data.i = -u->no; + } + u->no = i; + uhash(u); + break; +#ifdef ALLOW_SHIP_RENUM + case P_SHIP: + if (!u->ship) { + cmistake(u,ord,144,MSG_EVENT); + break; + } + if (!fval(u, UFL_OWNER)) { + cmistake(u,ord,146,MSG_EVENT); + break; + } + s = getstrtoken(); + if(s == NULL || *s == 0) { + i = newcontainerid(); + } else { + i = atoi36(s); + if (i<=0 || i>MAX_CONTAINER_NR) { + cmistake(u,ord,114,MSG_EVENT); + break; + } + if (findship(i) || findbuilding(i)) { + cmistake(u,ord,115,MSG_EVENT); + break; + } + } + sunhash(u->ship); + u->ship->no = i; + shash(u->ship); + break; +#endif + case P_BUILDING: + case P_GEBAEUDE: + if (!u->building) { + cmistake(u,ord,145,MSG_EVENT); + break; + } + if(!fval(u, UFL_OWNER)) { + cmistake(u,ord,148,MSG_EVENT); + break; + } + s = getstrtoken(); + if(*s == 0) { + i = newcontainerid(); + } else { + i = atoi36(s); + if (i<=0 || i>MAX_CONTAINER_NR) { + cmistake(u,ord,114,MSG_EVENT); + break; + } + if(findship(i) || findbuilding(i)) { + cmistake(u,ord,115,MSG_EVENT); + break; + } + } + bunhash(u->building); + u->building->no = i; + bhash(u->building); + break; + + default: + cmistake(u, ord, 239, MSG_EVENT); } - renumber_factions(); + return 0; } static building * @@ -3260,7 +3150,7 @@ age_building(building * b) } a_age(&b->attribs); - handle_event(&b->attribs, "timer", b); + handle_event(b->attribs, "timer", b); return b; } @@ -3302,7 +3192,7 @@ ageing(void) /* Factions */ for (f=factions;f;f=f->next) { a_age(&f->attribs); - handle_event(&f->attribs, "timer", f); + handle_event(f->attribs, "timer", f); } /* Regionen */ @@ -3312,13 +3202,13 @@ ageing(void) ship ** sp; a_age(&r->attribs); - handle_event(&r->attribs, "timer", r); + handle_event(r->attribs, "timer", r); /* Einheiten */ for (up=&r->units;*up;) { unit * u = *up; a_age(&u->attribs); - if (u==*up) handle_event(&u->attribs, "timer", u); + if (u==*up) handle_event(u->attribs, "timer", u); if (u==*up) up = &(*up)->next; } @@ -3326,7 +3216,7 @@ ageing(void) for (sp=&r->ships;*sp;) { ship * s = *sp; a_age(&s->attribs); - if (s==*sp) handle_event(&s->attribs, "timer", s); + if (s==*sp) handle_event(s->attribs, "timer", s); if (s==*sp) sp = &(*sp)->next; } @@ -3467,112 +3357,104 @@ new_units (void) } static void -setdefaults (void) +setdefaults(unit *u) { - region *r; + order *ord; + boolean trade = false; + boolean hunger = LongHunger(u); - for (r = regions; r; r = r->next) { - unit *u; - - for (u = r->units; u; u = u->next) { - order *ord; - boolean trade = false; - boolean hunger = LongHunger(u); - - freset(u, UFL_LONGACTION); - if (hunger) { - /* Hungernde Einheiten führen NUR den default-Befehl aus */ - set_order(&u->thisorder, default_order(u->faction->locale)); - } + freset(u, UFL_LONGACTION); + if (hunger) { + /* Hungernde Einheiten führen NUR den default-Befehl aus */ + set_order(&u->thisorder, default_order(u->faction->locale)); + } #ifdef LASTORDER - else { - /* by default the default long order becomes the new long order. */ - u->thisorder = copy_order(u->lastorder); - } + else { + /* by default the default long order becomes the new long order. */ + u->thisorder = copy_order(u->lastorder); + } #endif - /* check all orders for a potential new long order this round: */ - for (ord = u->orders; ord; ord = ord->next) { + /* check all orders for a potential new long order this round: */ + for (ord = u->orders; ord; ord = ord->next) { #ifndef LASTORDER - if (u->old_orders && is_repeated(ord)) { - /* this new order will replace the old defaults */ - free_orders(&u->old_orders); - if (hunger) break; - } + if (u->old_orders && is_repeated(ord)) { + /* this new order will replace the old defaults */ + free_orders(&u->old_orders); + if (hunger) break; + } #endif - if (hunger) continue; + if (hunger) continue; - if (is_exclusive(ord)) { - /* Über dieser Zeile nur Befehle, die auch eine idle Faction machen darf */ - if (idle(u->faction)) { - set_order(&u->thisorder, default_order(u->faction->locale)); - } else { - set_order(&u->thisorder, copy_order(ord)); - } + if (is_exclusive(ord)) { + /* Über dieser Zeile nur Befehle, die auch eine idle Faction machen darf */ + if (idle(u->faction)) { + set_order(&u->thisorder, default_order(u->faction->locale)); + } else { + set_order(&u->thisorder, copy_order(ord)); + } + 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; - } 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; - 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_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, copy_order(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. */ - } - } - } - - if (hunger) continue; - - /* Wenn die Einheit handelt, muß der Default-Befehl gelöscht - * werden. */ - - if (trade == true) { - /* fset(u, UFL_LONGACTION); */ - set_order(&u->thisorder, NULL); - } - /* thisorder kopieren wir nun nach lastorder. in lastorder steht - * der DEFAULT befehl der einheit. da MOVE kein default werden - * darf, wird MOVE nicht in lastorder kopiert. MACHE TEMP wurde ja - * schon gar nicht erst in thisorder kopiert, so dass MACHE TEMP - * durch diesen code auch nicht zum default wird Ebenso soll BIETE - * nicht hierher, da i.A. die Einheit dann ja weg ist (und damit - * die Einheitsnummer ungueltig). Auch Attackiere sollte nie in - * den Default übernommen werden */ - -#ifdef LASTORDER - switch (get_keyword(u->thisorder)) { - case K_MOVE: - case K_ATTACK: case K_WEREWOLF: - case NOKEYWORD: - /* these can never be default orders */ + set_order(&u->thisorder, copy_order(ord)); break; - default: - set_order(&u->lastorder, copy_order(u->thisorder)); + /* Wird je diese Ausschliesslichkeit aufgehoben, muss man aufpassen + * mit der Reihenfolge von Kaufen, Verkaufen etc., damit es Spielern + * nicht moeglich ist, Schulden zu machen. */ } -#endif } } + + if (hunger) return; + + /* Wenn die Einheit handelt, muß der Default-Befehl gelöscht + * werden. */ + + if (trade == true) { + /* fset(u, UFL_LONGACTION); */ + set_order(&u->thisorder, NULL); + } + /* thisorder kopieren wir nun nach lastorder. in lastorder steht + * der DEFAULT befehl der einheit. da MOVE kein default werden + * darf, wird MOVE nicht in lastorder kopiert. MACHE TEMP wurde ja + * schon gar nicht erst in thisorder kopiert, so dass MACHE TEMP + * durch diesen code auch nicht zum default wird Ebenso soll BIETE + * nicht hierher, da i.A. die Einheit dann ja weg ist (und damit + * die Einheitsnummer ungueltig). Auch Attackiere sollte nie in + * den Default übernommen werden */ + +#ifdef LASTORDER + switch (get_keyword(u->thisorder)) { + case K_MOVE: + case K_ATTACK: + case K_WEREWOLF: + case NOKEYWORD: + /* these can never be default orders */ + break; + + default: + set_order(&u->lastorder, copy_order(u->thisorder)); + } +#endif } static int @@ -3861,166 +3743,354 @@ claim_cmd(unit * u, struct order * ord) return 0; } +typedef struct processor { + struct processor * next; + int priority; + enum { PR_GLOBAL, PR_REGION, PR_UNIT, PR_ORDER } type; + union { + struct { + keyword_t kword; + boolean thisorder; + int (*process)(struct unit *, struct order *); + } per_order; + struct { + void (*process)(struct unit *); + } per_unit; + struct { + void (*process)(struct region *); + } per_region; + struct { + void (*process)(void); + } global; + } data; + const char * name; +} processor; + +static processor * processors; + +void +add_proc_order(int priority, keyword_t kword, int (*parser)(struct unit *, struct order *), boolean thisorder, const char * name) +{ + processor **pproc = &processors; + processor *proc; + + while (*pproc) { + proc = *pproc; + if (proc->priority>priority) break; + else if (proc->priority==priority && proc->type>=PR_ORDER) break; + pproc = &proc->next; + } + + proc = malloc(sizeof(processor)); + proc->priority = priority; + proc->type = PR_ORDER; + proc->data.per_order.process = parser; + proc->data.per_order.kword = kword; + proc->data.per_order.thisorder = thisorder; + proc->name = name; + proc->next = *pproc; + *pproc = proc; +} + +void +add_proc_global(int priority, void (*process)(void), const char * name) +{ + processor **pproc = &processors; + processor *proc; + + while (*pproc) { + proc = *pproc; + if (proc->priority>priority) break; + else if (proc->priority==priority && proc->type>=PR_GLOBAL) break; + pproc = &proc->next; + } + + proc = malloc(sizeof(processor)); + proc->priority = priority; + proc->type = PR_GLOBAL; + proc->data.global.process = process; + proc->name = name; + proc->next = *pproc; + *pproc = proc; +} + +void +add_proc_region(int priority, void (*process)(region *), const char * name) +{ + processor **pproc = &processors; + processor *proc; + + while (*pproc) { + proc = *pproc; + if (proc->priority>priority) break; + else if (proc->priority==priority && proc->type>=PR_REGION) break; + pproc = &proc->next; + } + + proc = malloc(sizeof(processor)); + proc->priority = priority; + proc->type = PR_REGION; + proc->data.per_region.process = process; + proc->name = name; + proc->next = *pproc; + *pproc = proc; +} + +void +add_proc_unit(int priority, void (*process)(unit *), const char * name) +{ + processor **pproc = &processors; + processor *proc; + + while (*pproc) { + proc = *pproc; + if (proc->priority>priority) break; + else if (proc->priority==priority && proc->type>=PR_UNIT) break; + pproc = &proc->next; + } + + proc = malloc(sizeof(processor)); + proc->priority = priority; + proc->type = PR_UNIT; + proc->data.per_unit.process = process; + proc->name = name; + proc->next = *pproc; + *pproc = proc; +} + +void +process(void) +{ + processor *proc = processors; + while (proc) { + int prio = proc->priority; + region *r; + processor *pglobal = proc; + + printf("- Step %u\n", prio); + while (proc && proc->priority==prio) { + if (proc->name) printf(" - %s\n", proc->name); + proc = proc->next; + } + + while (pglobal && pglobal->priority==prio && pglobal->type==PR_GLOBAL) { + pglobal->data.global.process(); + pglobal = pglobal->next; + } + if (pglobal==NULL || pglobal->priority!=prio) continue; + + for (r = regions; r; r = r->next) { + unit **up; + processor *pregion = pglobal; + + while (pregion && pregion->priority==prio && pregion->type==PR_REGION) { + pregion->data.per_region.process(r); + pregion = pregion->next; + } + if (pregion==NULL || pregion->priority!=prio) continue; + + for (up=&r->units;*up;) { + unit * u = *up; + processor *porder, *punit = pregion; + + while (punit && punit->priority==prio && punit->type==PR_UNIT) { + punit->data.per_unit.process(u); + punit = punit->next; + } + if (punit==NULL || punit->priority!=prio) continue; + + porder = punit; + while (porder && porder->priority==prio && porder->type==PR_ORDER) { + order ** ordp = &u->orders; + if (porder->data.per_order.thisorder) ordp = &u->thisorder; + while (*ordp) { + order * ord = *ordp; + if (get_keyword(ord) == porder->data.per_order.kword) { + porder->data.per_order.process(u, ord); + } + if (*ordp==ord) ordp=&ord->next; + } + porder = porder->next; + } + assert(*up==u); + up=&u->next; + } + } + } +} + +static void enter_1(region * r) { do_misc(r, false); } +static void enter_2(region * r) { do_misc(r, true); } +static void maintain_buildings_1(region * r) { maintain_buildings(r, false); } +static void maintain_buildings_2(region * r) { maintain_buildings(r,true); } +static void reset_moved(unit * u) { freset(u, UFL_MOVED); } + +static void reset_rng(void) { + if (turn == 0) rng_init((int)time(0)); + else rng_init(turn); +} + void processorders (void) { region *r; + int p; - set_passw(); /* und pruefe auf illegale Befehle */ + p = 10; + add_proc_global(p, &new_units, "Neue Einheiten erschaffen"); - puts(" - neue Einheiten erschaffen..."); - new_units(); + p+=10; + add_proc_unit(p, &setdefaults, "Default-Befehle"); + add_proc_order(p, K_BANNER, &banner_cmd, false, NULL); + add_proc_order(p, K_EMAIL, &email_cmd, false, NULL); + add_proc_order(p, K_PASSWORD, &password_cmd, false, NULL); + add_proc_order(p, K_SEND, &send_cmd, false, NULL); + add_proc_order(p, K_GROUP, &group_cmd, false, NULL); - puts(" - Defaults und Instant-Befehle..."); - setdefaults(); - instant_orders(); - - if (alliances!=NULL) alliancekick(); - - parse(K_MAIL, prepare_mail_cmd, false); - parse(K_MAIL, mail_cmd, false); - puts(" - Parteien altern"); - age_factions(); - - puts(" - Benutzen"); - parse(K_CLAIM, claim_cmd, false); - parse(K_USE, use_cmd, false); - - puts(" - Kontaktieren, Betreten von Schiffen und Gebäuden (1.Versuch)"); - do_misc(false); + p+=10; + add_proc_unit(p, &reset_moved, "Instant-Befehle"); + add_proc_order(p, K_QUIT, &quit_cmd, false, NULL); + add_proc_order(p, K_URSPRUNG, &origin_cmd, false, NULL); + add_proc_order(p, K_ALLY, &ally_cmd, false, NULL); + add_proc_order(p, K_PREFIX, &prefix_cmd, false, NULL); + add_proc_order(p, K_SYNONYM, &synonym_cmd, false, NULL); + add_proc_order(p, K_SETSTEALTH, &setstealth_cmd, false, NULL); + add_proc_order(p, K_STATUS, &status_cmd, false, NULL); + add_proc_order(p, K_COMBAT, &combatspell_cmd, false, NULL); + add_proc_order(p, K_DISPLAY, &display_cmd, false, NULL); + add_proc_order(p, K_NAME, &name_cmd, false, NULL); + add_proc_order(p, K_GUARD, &guard_off_cmd, false, NULL); + add_proc_order(p, K_RESHOW, &reshow_cmd, false, NULL); +#ifdef KARMA_MODULE + add_proc_order(p, K_WEREWOLF, &setwere_cmd, false, NULL); +#endif /* KARMA_MODULE */ if (alliances!=NULL) { - puts(" - Testen der Allianzbedingungen"); - alliancevictory(); + p+=10; + add_proc_global(p, &alliancekick, NULL); + } + + p+=10; + add_proc_global(p, &age_factions, "Parteienalter++"); + add_proc_order(p, K_MAIL, &mail_cmd, false, "Botschaften"); + add_proc_order(p, K_CLAIM, &claim_cmd, false, NULL); + + p+=10; /* all claims must be done before we can USE */ + add_proc_region(p, &enter_1, "Kontaktieren & Betreten (1. Versuch)"); + add_proc_order(p, K_USE, &use_cmd, false, "Benutzen"); + + if (alliances!=NULL) { + p+=10; /* in case USE changes it */ + add_proc_global(p, &alliancevictory, "Testen der Allianzbedingungen"); } - puts(" - GM Kommandos"); #ifdef INFOCMD_MODULE - infocommands(); + add_proc_global(p, &infocommands, NULL); #endif - gmcommands(); + add_proc_global(p, &gmcommands, "GM Kommandos"); - puts(" - Verlassen"); - parse(K_LEAVE, leave_cmd, false); - - puts(" - Kontakte löschen"); - remove_contacts(); + p += 10; /* in case it has any effects on allincevictories */ + add_proc_order(p, K_LEAVE, &leave_cmd, false, "Verlassen"); + if (!nobattle) { #ifdef KARMA_MODULE - puts(" - Jihad-Angriffe"); - jihad_attacks(); + p+=10; + add_proc_global(p, &jihad_attacks, "Jihad-Angriffe"); #endif - - puts(" - Attackieren"); - if (nobattle == false) do_battle(); - if (turn == 0) rng_init((int)time(0)); - else rng_init(turn); - - puts(" - Belagern"); - do_siege(); - - puts(" - Initialisieren des Pools, Reservieren"); - init_pool(); - - puts(" - Kontaktieren, Betreten von Schiffen und Gebäuden (2.Versuch)"); - do_misc(false); - - puts(" - Folge auf Einheiten ersetzen"); - follow_unit(); - - if (turn == 0) rng_init((int)time(0)); - else rng_init(turn); - - puts(" - Zerstören, Geben, Rekrutieren, Vergessen"); - economics(); - remove_empty_units(); - - puts(" - Gebäudeunterhalt (1. Versuch)"); - maintain_buildings(false); - - puts(" - Sterben, Neustart"); - quit(); - parse_restart(); - - puts(" - Zaubern"); - magic(); - remove_empty_units(); - - if (!global.disabled[K_TEACH]) { - puts(" - Lehren"); - teaching(); + add_proc_region(p, &do_battle, "Attackieren"); } - puts(" - Lernen"); - learn(); + p+=10; /* after combat, reset rng */ + add_proc_global(p, &reset_rng, NULL); + add_proc_region(p, &do_siege, "Belagern"); - puts(" - Produzieren, Geldverdienen, Handeln, Anwerben"); - produce(); + p+=10; /* can't allow reserve before siege (weapons) */ + add_proc_region(p, &enter_2, "Kontaktieren & Betreten (2. Versuch)"); + add_proc_order(p, K_RESERVE, &reserve_cmd, false, "Reservieren"); + add_proc_unit(p, &follow_unit, "Folge auf Einheiten setzen"); - puts(" - Kontaktieren, Betreten von Schiffen und Gebäuden (3.Versuch)"); - do_misc(true); + p+=10; /* rest rng again before economics */ + add_proc_global(p, &reset_rng, NULL); + add_proc_region(p, &economics, "Zerstören, Geben, Rekrutieren, Vergessen"); - puts(" - Schiffe sinken"); - sinkships(); + p+=10; + add_proc_region(p, &maintain_buildings_1, "Gebäudeunterhalt (1. Versuch)"); - puts(" - Bewegungen"); - movement(); + p+=10; /* QUIT fuer sich alleine */ + add_proc_global(p, &quit, "Sterben"); + add_proc_global(p, &parse_restart, "Neustart"); - puts(" - Bewache (an)"); - parse(K_GUARD, guard_on_cmd, false); + p+=10; + add_proc_global(p, &magic, "Zaubern"); - puts(" - Zufallsbegegnungen"); - encounters(); + p+=10; + if (!global.disabled[K_TEACH]) { + add_proc_region(p, &teaching, "Lehren"); + } + add_proc_order(p, K_STUDY, &learn_cmd, true, "Lernen"); - if (turn == 0) rng_init((int)time(0)); - else rng_init(turn); + p+=10; + add_proc_global(p, &produce, "Produktion, Handel, Rekruten"); - puts(" - Monster fressen und vertreiben Bauern"); - monsters_kill_peasants(); + p+=10; + add_proc_region(p, &enter_2, "Kontaktieren & Betreten (3. Versuch)"); - puts(" - random events"); - randomevents(); + p+=10; + add_proc_region(p, &sinkships, "Schiffe sinken"); - puts(" - newspaper commands"); + p+=10; + add_proc_global(p, &movement, "Bewegungen"); + + p+=10; + add_proc_order(p, K_GUARD, &guard_on_cmd, false, "Bewache (an)"); #ifdef XECMD_MODULE - xecmd(); + /* can do together with guard */ + add_proc_order(p, K_LEAVE, &xecmd, false, "Zeitung"); #endif - puts(" - regeneration (healing & aura)"); - monthly_healing(); - regeneration_magiepunkte(); + p+=10; + add_proc_global(p, &encounters, "Zufallsbegegnungen"); + p+=10; + add_proc_global(p, &reset_rng, NULL); + add_proc_unit(p, &monsters_kill_peasants, "Monster fressen und vertreiben Bauern"); - puts(" - Defaults setzen"); - defaultorders(); + p+=10; + add_proc_global(p, &randomevents, "Zufallsereignisse"); - puts(" - Unterhaltskosten, Nachfrage, Seuchen, Wachstum, Auswanderung"); - demographics(); + p+=10; + add_proc_global(p, &monthly_healing, "Regeneration (HP)"); + add_proc_global(p, ®eneration_magiepunkte, "Regeneration (Aura)"); + add_proc_global(p, &defaultorders, "Defaults setzen"); + add_proc_global(p, &demographics, "Nahrung, Seuchen, Wachstum, Wanderung"); - puts(" - Gebäudeunterhalt (2. Versuch)"); - maintain_buildings(true); + p+=10; + add_proc_region(p, &maintain_buildings_2, "Gebäudeunterhalt (2. Versuch)"); + p+=10; + add_proc_global(p, &reorder, "Einheiten sortieren"); #ifdef KARMA_MODULE - puts(" - Jihads setzen"); - karma(); + p+=10; + add_proc_global(p, &karma, "Jihads setzen"); #endif - - puts(" - Einheiten Sortieren"); - reorder(); #ifdef ALLIANCEJOIN - alliancejoin(); + p+=10; + add_proc_global(p, &alliancejoin, "Allianzen"); #endif #ifdef ENEMIES - puts(" - Krieg & Frieden"); - declare_war(); + p+=10; + add_proc_global(p, &declare_war, "Krieg & Frieden"); #endif - #ifdef HEROES - puts(" - Heldenbeförderung"); - parse(K_PROMOTION, promotion_cmd, false); + add_proc_order(p, K_PROMOTION, &promotion_cmd, false, "Heldenbeförderung"); #endif - puts(" - Neue Nummern"); - renumber(); + p+=10; + add_proc_global(p, &renumber_factions, "Neue Nummern"); + add_proc_order(p, K_NUMBER, &renumber_cmd, false, "Neue Nummern (Einheiten)"); + + process(); + /*************************************************/ + for (r = regions;r;r=r->next) reorder_owners(r); puts(" - Attribute altern"); diff --git a/src/common/gamecode/monster.c b/src/common/gamecode/monster.c index 6ded2eb53..53b73c9bc 100644 --- a/src/common/gamecode/monster.c +++ b/src/common/gamecode/monster.c @@ -761,23 +761,16 @@ monster_learn(unit *u) } void -monsters_kill_peasants(void) +monsters_kill_peasants(unit * u) { - region *r; - unit *u; - - for (r = regions; r; r = r->next) { - for (u = r->units; u; u = u->next) if(!fval(u, UFL_MOVED)) { - if (u->race->flags & RCF_SCAREPEASANTS) { - scared_by_monster(u); - } - if (u->race->flags & RCF_KILLPEASANTS) { - eaten_by_monster(u); - } - if (u->race->flags & RCF_ABSORBPEASANTS) { - absorbed_by_monster(u); - } - } + if (u->race->flags & RCF_SCAREPEASANTS) { + scared_by_monster(u); + } + if (u->race->flags & RCF_KILLPEASANTS) { + eaten_by_monster(u); + } + if (u->race->flags & RCF_ABSORBPEASANTS) { + absorbed_by_monster(u); } } diff --git a/src/common/gamecode/monster.h b/src/common/gamecode/monster.h index ab9295a53..4c5189665 100644 --- a/src/common/gamecode/monster.h +++ b/src/common/gamecode/monster.h @@ -29,7 +29,7 @@ extern "C" { void age_illusion(struct unit *u); -void monsters_kill_peasants(void); +void monsters_kill_peasants(struct unit * u); void plan_monsters(void); struct unit *random_unit(const struct region * r); diff --git a/src/common/gamecode/spy.c b/src/common/gamecode/spy.c index 125fb1058..dfdedcd61 100644 --- a/src/common/gamecode/spy.c +++ b/src/common/gamecode/spy.c @@ -459,9 +459,8 @@ sink_ship(region * r, ship * sh, const char *name, char spy, unit * saboteur) sprintf(buf, (dead == 1) ? person_lost_msg : persons_lost_msg, dead, unitname(u), unit_dies_msg); } - if (dead == u->number) - /* the poor creature, she dies */ - { + if (dead == u->number) { + /* the poor creature, she dies */ *ui = u->next; destroy_unit(u); } diff --git a/src/common/gamecode/study.c b/src/common/gamecode/study.c index 6776bb526..de0059b2e 100644 --- a/src/common/gamecode/study.c +++ b/src/common/gamecode/study.c @@ -439,11 +439,10 @@ teach(unit * u, struct order * ord) } /* ------------------------------------------------------------- */ -void -learn(void) +int +learn_cmd(unit * u, order * ord) { - region *r; - unit *u; + region *r = u->region; int p; magic_t mtyp; int l; @@ -451,286 +450,281 @@ learn(void) /* lernen nach lehren */ - for (r = regions; r; r = r->next) { - for (u = r->units; u; u = u->next) { - int days; - if (fval(r->terrain, SEA_REGION)) { - /* sonderbehandlung aller die auf Ozeanen lernen können */ - if (u->race!=new_race[RC_AQUARIAN] && !(u->race->flags & RCF_SWIM)) { - continue; + int days; + double multi = 1.0; + attrib * a = NULL; + teaching_info * teach = NULL; + int money = 0; + skill_t sk; + int maxalchemy = 0; + + if (fval(r->terrain, SEA_REGION)) { + /* sonderbehandlung aller die auf Ozeanen lernen können */ + if (u->race!=new_race[RC_AQUARIAN] && !(u->race->flags & RCF_SWIM)) { + return 0; + } + } + if (fval(u, UFL_LONGACTION)) return 0; + + if (u->race == new_race[RC_INSECT] && r_insectstalled(r) + && !is_cursed(u->attribs, C_KAELTESCHUTZ,0)) { + return 0; + } + if (fval(u, UFL_LONGACTION)) { + cmistake(u, ord, 52, MSG_PRODUCE); + return 0; + } + if ((u->race->flags & RCF_NOLEARN) || fval(u, UFL_WERE)) { + sprintf(buf, "%s können nichts lernen", LOC(default_locale, rc_name(u->race, 1))); + mistake(u, ord, buf, MSG_EVENT); + return 0; + } + + init_tokens(ord); + skip_token(); + sk = getskill(u->faction->locale); + + if (sk < 0) { + cmistake(u, ord, 77, MSG_EVENT); + return 0; + } + if (SkillCap(sk) && SkillCap(sk) <= effskill(u, sk)) { + cmistake(u, ord, 77, MSG_EVENT); + return 0; + } + /* Hack: Talente mit Malus -99 können nicht gelernt werden */ + if (u->race->bonus[sk] == -99) { + cmistake(u, ord, 77, MSG_EVENT); + return 0; + } + /* snotlings können Talente nur bis T8 lernen */ + if (u->race == new_race[RC_SNOTLING]){ + if (get_level(u, sk) >= 8){ + cmistake(u, ord, 308, MSG_EVENT); + return 0; + } + } + + p = studycost = study_cost(u, sk); + a = a_find(u->attribs, &at_learning); + if (a!=NULL) { + teach = (teaching_info*)a->data.v; + } + + /* keine kostenpflichtigen Talente für Migranten. Vertraute sind + * keine Migranten, wird in is_migrant abgefangen. Vorsicht, + * studycost darf hier noch nicht durch Akademie erhöht sein */ + if (studycost > 0 && !ExpensiveMigrants() && is_migrant(u)) { + sprintf(buf, "Migranten können keine kostenpflichtigen Talente lernen"); + mistake(u, ord, buf, MSG_EVENT); + return 0; + } + /* Akademie: */ + { + struct building * b = inside_building(u); + const struct building_type * btype = b?b->type:NULL; + + if (btype == bt_find("academy")) { + studycost = max(50, studycost * 2); + } + } + + if (sk == SK_MAGIC) { + if (u->number > 1){ + cmistake(u, ord, 106, MSG_MAGIC); + return 0; + } + if (is_familiar(u)){ + /* Vertraute zählen nicht zu den Magiern einer Partei, + * können aber nur Graue Magie lernen */ + mtyp = M_GRAU; + if (!is_mage(u)) create_mage(u, mtyp); + } else if (!has_skill(u, SK_MAGIC)) { + /* Die Einheit ist noch kein Magier */ + if (count_skill(u->faction, SK_MAGIC) + u->number > + max_skill(u->faction, SK_MAGIC)) + { + sprintf(buf, "Es kann maximal %d Magier pro Partei geben", + max_skill(u->faction, SK_MAGIC)); + mistake(u, ord, buf, MSG_EVENT); + return 0; + } + mtyp = getmagicskill(); + if (mtyp == M_NONE || mtyp == M_GRAU) { + /* wurde kein Magiegebiet angegeben, wird davon + * ausgegangen, daß das normal gelernt werden soll */ + if(u->faction->magiegebiet != 0) { + mtyp = u->faction->magiegebiet; + } else { + /* Es wurde kein Magiegebiet angegeben und die Partei + * hat noch keins gewählt. */ + cmistake(u, ord, 178, MSG_MAGIC); + return 0; } } - if (fval(u, UFL_LONGACTION)) continue; - if (get_keyword(u->thisorder) == K_STUDY) { - double multi = 1.0; - attrib * a = NULL; - teaching_info * teach = NULL; - int money = 0; - skill_t sk; - int maxalchemy = 0; + if (mtyp != u->faction->magiegebiet){ + /* Es wurde versucht, ein anderes Magiegebiet zu lernen + * als das der Partei */ + if (u->faction->magiegebiet != 0){ + cmistake(u, ord, 179, MSG_MAGIC); + return 0; + } else { + /* Lernt zum ersten mal Magie und legt damit das + * Magiegebiet der Partei fest */ + u->faction->magiegebiet = mtyp; + } + } + if (!is_mage(u)) create_mage(u, mtyp); + } else { + /* ist schon ein Magier und kein Vertrauter */ + if(u->faction->magiegebiet == 0){ + /* die Partei hat noch kein Magiegebiet gewählt. */ + mtyp = getmagicskill(); + if (mtyp == M_NONE){ + cmistake(u, ord, 178, MSG_MAGIC); + return 0; + } else { + /* Legt damit das Magiegebiet der Partei fest */ + u->faction->magiegebiet = mtyp; + } + } + } + } + if (sk == SK_ALCHEMY) { + maxalchemy = eff_skill(u, SK_ALCHEMY, r); + if (has_skill(u, SK_ALCHEMY)==0 + && count_skill(u->faction, SK_ALCHEMY) + u->number > + max_skill(u->faction, SK_ALCHEMY)) { + sprintf(buf, "Es kann maximal %d Alchemisten pro Partei geben", + max_skill(u->faction, SK_ALCHEMY)); + mistake(u, ord, buf, MSG_EVENT); + return 0; + } + } + if (studycost) { + int cost = studycost * u->number; + money = get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, cost); + money = min(money, cost); + } + if (money < studycost * u->number) { + studycost = p; /* Ohne Univertreurung */ + money = min(money, studycost); + if (p>0 && money < studycost * u->number) { + #ifdef PARTIAL_STUDY + cmistake(u, ord, 65, MSG_EVENT); + multi = money / (double)(studycost * u->number); + #else + cmistake(u, ord, 65, MSG_EVENT); + return 0; /* nein, Silber reicht auch so nicht */ + #endif + } + } - if (u->race == new_race[RC_INSECT] && r_insectstalled(r) - && !is_cursed(u->attribs, C_KAELTESCHUTZ,0)) { - continue; - } - if (fval(u, UFL_LONGACTION)) { - cmistake(u, u->thisorder, 52, MSG_PRODUCE); - continue; - } - if ((u->race->flags & RCF_NOLEARN) || fval(u, UFL_WERE)) { - sprintf(buf, "%s können nichts lernen", LOC(default_locale, rc_name(u->race, 1))); - mistake(u, u->thisorder, buf, MSG_EVENT); - continue; - } + if (teach==NULL) { + a = a_add(&u->attribs, a_new(&at_learning)); + teach = (teaching_info*)a->data.v; + teach->teachers[0] = 0; + } + if (money>0) { + use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, money); + ADDMSG(&u->faction->msgs, msg_message("studycost", + "unit region cost skill", u, u->region, money, sk)); + } - init_tokens(u->thisorder); - skip_token(); - sk = getskill(u->faction->locale); + if (get_effect(u, oldpotiontype[P_WISE])) { + l = min(u->number, get_effect(u, oldpotiontype[P_WISE])); + teach->value += l * 10; + change_effect(u, oldpotiontype[P_WISE], -l); + } + if (get_effect(u, oldpotiontype[P_FOOL])) { + l = min(u->number, get_effect(u, oldpotiontype[P_FOOL])); + teach->value -= l * 30; + change_effect(u, oldpotiontype[P_FOOL], -l); + } - if (sk < 0) { - cmistake(u, u->thisorder, 77, MSG_EVENT); - continue; - } - if (SkillCap(sk) && SkillCap(sk) <= effskill(u, sk)) { - cmistake(u, u->thisorder, 77, MSG_EVENT); - continue; - } - /* Hack: Talente mit Malus -99 können nicht gelernt werden */ - if (u->race->bonus[sk] == -99) { - cmistake(u, u->thisorder, 77, MSG_EVENT); - continue; - } - /* snotlings können Talente nur bis T8 lernen */ - if (u->race == new_race[RC_SNOTLING]){ - if (get_level(u, sk) >= 8){ - cmistake(u, u->thisorder, 308, MSG_EVENT); - continue; - } - } + #ifdef KARMA_MODULE + l = fspecial(u->faction, FS_WARRIOR); + if (l > 0) { + if (sk == SK_CROSSBOW || sk == SK_LONGBOW + || sk == SK_CATAPULT || sk == SK_MELEE || sk == SK_SPEAR + || sk == SK_AUSDAUER || sk == SK_WEAPONLESS) + { + teach->value += u->number * 5 * (l+1); + } else { + teach->value -= u->number * 5 * (l+1); + teach->value = max(0, teach->value); + } + } + #endif /* KARMA_MODULE */ - p = studycost = study_cost(u, sk); - a = a_find(u->attribs, &at_learning); - if (a!=NULL) { - teach = (teaching_info*)a->data.v; - } + if (p != studycost) { + /* ist_in_gebaeude(r, u, BT_UNIVERSITAET) == 1) { */ + /* p ist Kosten ohne Uni, studycost mit; wenn + * p!=studycost, ist die Einheit zwangsweise + * in einer Uni */ + teach->value += u->number * 10; + } - /* keine kostenpflichtigen Talente für Migranten. Vertraute sind - * keine Migranten, wird in is_migrant abgefangen. Vorsicht, - * studycost darf hier noch nicht durch Akademie erhöht sein */ - if (studycost > 0 && !ExpensiveMigrants() && is_migrant(u)) { - sprintf(buf, "Migranten können keine kostenpflichtigen Talente lernen"); - mistake(u, u->thisorder, buf, MSG_EVENT); - continue; - } - /* Akademie: */ - { - struct building * b = inside_building(u); - const struct building_type * btype = b?b->type:NULL; + if (is_cursed(r->attribs, C_BADLEARN,0)) { + teach->value -= u->number * 10; + } - if (btype == bt_find("academy")) { - studycost = max(50, studycost * 2); - } - } + days = (int)((u->number * 30 + teach->value) * multi); - if (sk == SK_MAGIC) { - if (u->number > 1){ - cmistake(u, u->thisorder, 106, MSG_MAGIC); - continue; - } - if (is_familiar(u)){ - /* Vertraute zählen nicht zu den Magiern einer Partei, - * können aber nur Graue Magie lernen */ - mtyp = M_GRAU; - if (!is_mage(u)) create_mage(u, mtyp); - } else if (!has_skill(u, SK_MAGIC)) { - /* Die Einheit ist noch kein Magier */ - if (count_skill(u->faction, SK_MAGIC) + u->number > - max_skill(u->faction, SK_MAGIC)) - { - sprintf(buf, "Es kann maximal %d Magier pro Partei geben", - max_skill(u->faction, SK_MAGIC)); - mistake(u, u->thisorder, buf, MSG_EVENT); - continue; - } - mtyp = getmagicskill(); - if (mtyp == M_NONE || mtyp == M_GRAU) { - /* wurde kein Magiegebiet angegeben, wird davon - * ausgegangen, daß das normal gelernt werden soll */ - if(u->faction->magiegebiet != 0) { - mtyp = u->faction->magiegebiet; - } else { - /* Es wurde kein Magiegebiet angegeben und die Partei - * hat noch keins gewählt. */ - cmistake(u, u->thisorder, 178, MSG_MAGIC); - continue; - } - } - if (mtyp != u->faction->magiegebiet){ - /* Es wurde versucht, ein anderes Magiegebiet zu lernen - * als das der Partei */ - if (u->faction->magiegebiet != 0){ - cmistake(u, u->thisorder, 179, MSG_MAGIC); - continue; - } else { - /* Lernt zum ersten mal Magie und legt damit das - * Magiegebiet der Partei fest */ - u->faction->magiegebiet = mtyp; - } - } - if (!is_mage(u)) create_mage(u, mtyp); - } else { - /* ist schon ein Magier und kein Vertrauter */ - if(u->faction->magiegebiet == 0){ - /* die Partei hat noch kein Magiegebiet gewählt. */ - mtyp = getmagicskill(); - if (mtyp == M_NONE){ - cmistake(u, u->thisorder, 178, MSG_MAGIC); - continue; - } else { - /* Legt damit das Magiegebiet der Partei fest */ - u->faction->magiegebiet = mtyp; - } - } - } - } - if (sk == SK_ALCHEMY) { - maxalchemy = eff_skill(u, SK_ALCHEMY, r); - if (has_skill(u, SK_ALCHEMY)==0 - && count_skill(u->faction, SK_ALCHEMY) + u->number > - max_skill(u->faction, SK_ALCHEMY)) { - sprintf(buf, "Es kann maximal %d Alchemisten pro Partei geben", - max_skill(u->faction, SK_ALCHEMY)); - mistake(u, u->thisorder, buf, MSG_EVENT); - continue; - } - } - if (studycost) { - int cost = studycost * u->number; - money = get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, cost); - money = min(money, cost); - } - if (money < studycost * u->number) { - studycost = p; /* Ohne Univertreurung */ - money = min(money, studycost); - if (p>0 && money < studycost * u->number) { -#ifdef PARTIAL_STUDY - cmistake(u, u->thisorder, 65, MSG_EVENT); - multi = money / (double)(studycost * u->number); -#else - cmistake(u, u->thisorder, 65, MSG_EVENT); - continue; /* nein, Silber reicht auch so nicht */ -#endif - } - } + /* the artacademy currently improves the learning of entertainment + of all units in the region, to be able to make it cumulative with + with an academy */ - if (teach==NULL) { - a = a_add(&u->attribs, a_new(&at_learning)); - teach = (teaching_info*)a->data.v; - teach->teachers[0] = 0; - } - if (money>0) { - use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, money); - ADDMSG(&u->faction->msgs, msg_message("studycost", - "unit region cost skill", u, u->region, money, sk)); + if (sk == SK_ENTERTAINMENT && buildingtype_exists(r, bt_find("artacademy"))) { + days *= 2; + } + + if (fval(u, UFL_HUNGER)) days /= 2; + + while (days) { + if (days>=u->number*30) { + learn_skill(u, sk, 1.0); + days -= u->number*30; + } else { + double chance = (double)days/u->number/30; + learn_skill(u, sk, chance); + days = 0; + } + } + if (a!=NULL) { + if (teach!=NULL) { + int index = 0; + while (teach->teachers[index] && index!=MAXTEACHERS) { + unit * teacher = teach->teachers[index++]; + if (teacher->faction != u->faction) { + ADDMSG(&u->faction->msgs, msg_message("teach_student", + "teacher student skill", teacher, u, sk)); + ADDMSG(&teacher->faction->msgs, msg_message("teach_teacher", + "teacher student skill level", teacher, u, sk, + effskill(u, sk))); } + } + } + a_remove(&u->attribs, a); + a = NULL; + } + fset(u, UFL_LONGACTION); - if (get_effect(u, oldpotiontype[P_WISE])) { - l = min(u->number, get_effect(u, oldpotiontype[P_WISE])); - teach->value += l * 10; - change_effect(u, oldpotiontype[P_WISE], -l); - } - if (get_effect(u, oldpotiontype[P_FOOL])) { - l = min(u->number, get_effect(u, oldpotiontype[P_FOOL])); - teach->value -= l * 30; - change_effect(u, oldpotiontype[P_FOOL], -l); - } + /* Anzeigen neuer Tränke */ + /* Spruchlistenaktualiesierung ist in Regeneration */ -#ifdef KARMA_MODULE - l = fspecial(u->faction, FS_WARRIOR); - if (l > 0) { - if (sk == SK_CROSSBOW || sk == SK_LONGBOW - || sk == SK_CATAPULT || sk == SK_MELEE || sk == SK_SPEAR - || sk == SK_AUSDAUER || sk == SK_WEAPONLESS) - { - teach->value += u->number * 5 * (l+1); - } else { - teach->value -= u->number * 5 * (l+1); - teach->value = max(0, teach->value); - } - } -#endif /* KARMA_MODULE */ - - if (p != studycost) { - /* ist_in_gebaeude(r, u, BT_UNIVERSITAET) == 1) { */ - /* p ist Kosten ohne Uni, studycost mit; wenn - * p!=studycost, ist die Einheit zwangsweise - * in einer Uni */ - teach->value += u->number * 10; - } - - if (is_cursed(r->attribs, C_BADLEARN,0)) { - teach->value -= u->number * 10; - } - - days = (int)((u->number * 30 + teach->value) * multi); - - /* the artacademy currently improves the learning of entertainment - of all units in the region, to be able to make it cumulative with - with an academy */ - - if (sk == SK_ENTERTAINMENT && buildingtype_exists(r, bt_find("artacademy"))) { - days *= 2; - } - - if (fval(u, UFL_HUNGER)) days /= 2; - - while (days) { - if (days>=u->number*30) { - learn_skill(u, sk, 1.0); - days -= u->number*30; - } else { - double chance = (double)days/u->number/30; - learn_skill(u, sk, chance); - days = 0; - } - } - if (a!=NULL) { - if (teach!=NULL) { - int index = 0; - while (teach->teachers[index] && index!=MAXTEACHERS) { - unit * teacher = teach->teachers[index++]; - if (teacher->faction != u->faction) { - ADDMSG(&u->faction->msgs, msg_message("teach_student", - "teacher student skill", teacher, u, sk)); - ADDMSG(&teacher->faction->msgs, msg_message("teach_teacher", - "teacher student skill level", teacher, u, sk, - effskill(u, sk))); - } - } - } - a_remove(&u->attribs, a); - a = NULL; - } - fset(u, UFL_LONGACTION); - - /* Anzeigen neuer Tränke */ - /* Spruchlistenaktualiesierung ist in Regeneration */ - - if (sk == SK_ALCHEMY) { - const potion_type * ptype; - faction * f = u->faction; - int skill = eff_skill(u, SK_ALCHEMY, r); - if (skill>maxalchemy) { - for (ptype=potiontypes; ptype; ptype=ptype->next) { - if (skill == ptype->level * 2) { - attrib * a = a_find(f->attribs, &at_showitem); - while (a && a->type==&at_showitem && a->data.v != ptype) a=a->next; - if (a==NULL || a->type!=&at_showitem) { - a = a_add(&f->attribs, a_new(&at_showitem)); - a->data.v = (void*) ptype->itype; - } - } - } + if (sk == SK_ALCHEMY) { + const potion_type * ptype; + faction * f = u->faction; + int skill = eff_skill(u, SK_ALCHEMY, r); + if (skill>maxalchemy) { + for (ptype=potiontypes; ptype; ptype=ptype->next) { + if (skill == ptype->level * 2) { + attrib * a = a_find(f->attribs, &at_showitem); + while (a && a->type==&at_showitem && a->data.v != ptype) a=a->next; + if (a==NULL || a->type!=&at_showitem) { + a = a_add(&f->attribs, a_new(&at_showitem)); + a->data.v = (void*) ptype->itype; } } } @@ -738,54 +732,50 @@ learn(void) } } - void -teaching(void) +teaching(region *r) { - region *r; /* das sind alles befehle, die 30 tage brauchen, und die in thisorder * stehen! von allen 30-tage befehlen wird einfach der letzte verwendet * (dosetdefaults). * * lehren vor lernen. */ - for (r = regions; r; r = r->next) { - unit *u; + unit *u; - for (u = r->units; u; u = u->next) { + for (u = r->units; u; u = u->next) { - if (u->race == new_race[RC_SPELL] || fval(u, UFL_LONGACTION)) + if (u->race == new_race[RC_SPELL] || fval(u, UFL_LONGACTION)) + continue; + + if (fval(r->terrain, SEA_REGION) + && u->race != new_race[RC_AQUARIAN] + && !(u->race->flags & RCF_SWIM)) continue; - if (fval(r->terrain, SEA_REGION) - && u->race != new_race[RC_AQUARIAN] - && !(u->race->flags & RCF_SWIM)) - continue; + if (u->race == new_race[RC_INSECT] && r_insectstalled(r) + && !is_cursed(u->attribs, C_KAELTESCHUTZ,0)) { + continue; + } - if (u->race == new_race[RC_INSECT] && r_insectstalled(r) - && !is_cursed(u->attribs, C_KAELTESCHUTZ,0)) { + switch (get_keyword(u->thisorder)) { + case K_TEACH: + if (fval(u, UFL_LONGACTION)) { + cmistake(u, u->thisorder, 52, MSG_PRODUCE); continue; - } - - switch (get_keyword(u->thisorder)) { - case K_TEACH: - if (fval(u, UFL_LONGACTION)) { - cmistake(u, u->thisorder, 52, MSG_PRODUCE); - continue; - } else { - static const curse_type * gbdream_ct = NULL; - if (gbdream_ct==0) gbdream_ct = ct_find("gbdream"); - if (gbdream_ct) { - if (get_curse(u->region->attribs, gbdream_ct)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "gbdream_noteach", "")); - continue; - } + } else { + static const curse_type * gbdream_ct = NULL; + if (gbdream_ct==0) gbdream_ct = ct_find("gbdream"); + if (gbdream_ct) { + if (get_curse(u->region->attribs, gbdream_ct)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "gbdream_noteach", "")); + continue; } } - teach(u, u->thisorder); - break; - } + } + teach(u, u->thisorder); + break; } } } diff --git a/src/common/gamecode/study.h b/src/common/gamecode/study.h index b0da60fc3..177976d49 100644 --- a/src/common/gamecode/study.h +++ b/src/common/gamecode/study.h @@ -19,8 +19,8 @@ extern "C" { #endif -extern void teaching(void); -extern void learn(void); +extern void teaching(struct region * r); +extern int learn_cmd(struct unit * u, struct order * ord); extern magic_t getmagicskill(void); extern boolean is_migrant(struct unit *u); diff --git a/src/common/kernel/battle.c b/src/common/kernel/battle.c index 78aaf903f..68fc16ce2 100644 --- a/src/common/kernel/battle.c +++ b/src/common/kernel/battle.c @@ -3988,106 +3988,101 @@ battle_flee(battle * b) } void -do_battle(void) +do_battle(region * r) { - region *r; #ifdef SMALL_BATTLE_MESSAGES char smallbuf[512]; #endif + battle *b = NULL; + boolean fighting = false; + ship * sh; + building *bu; - for (r=regions;r!=NULL;r=r->next) { - battle *b = NULL; - boolean fighting = false; - ship * sh; - building *bu; - /* int *rows; */ + fighting = init_battle(r, &b); - fighting = init_battle(r, &b); + if (b==NULL) return; - if (b==NULL) continue; - - /* Bevor wir die alliierten hineinziehen, sollten wir schauen, * - * Ob jemand fliehen kann. Dann erübrigt sich das ganze ja - * vielleicht schon. */ - print_header(b); - if (!fighting) { - /* Niemand mehr da, Kampf kann nicht stattfinden. */ - message * m = msg_message("battle::aborted", ""); - message_all(b, m); - msg_release(m); - free_battle(b); - free(b); - continue; - } - join_allies(b); + /* Bevor wir die alliierten hineinziehen, sollten wir schauen, * + * Ob jemand fliehen kann. Dann erübrigt sich das ganze ja + * vielleicht schon. */ + print_header(b); + if (!fighting) { + /* Niemand mehr da, Kampf kann nicht stattfinden. */ + message * m = msg_message("battle::aborted", ""); + message_all(b, m); + msg_release(m); + free_battle(b); + free(b); + return; + } + join_allies(b); #ifdef HEROES - make_heroes(b); + make_heroes(b); #endif - /* Alle Mann raus aus der Burg! */ - for (bu=r->buildings; bu!=NULL; bu=bu->next) bu->sizeleft = bu->size; + /* Alle Mann raus aus der Burg! */ + for (bu=r->buildings; bu!=NULL; bu=bu->next) bu->sizeleft = bu->size; - /* make sure no ships are damaged initially */ - for (sh=r->ships; sh; sh=sh->next) freset(sh, SF_DAMAGED); + /* make sure no ships are damaged initially */ + for (sh=r->ships; sh; sh=sh->next) freset(sh, SF_DAMAGED); - /* Gibt es eine Taktikrunde ? */ - if (cv_size(&b->leaders)) { - b->turn = 0; - b->has_tactics_turn = true; - } else { - b->turn = 1; - b->has_tactics_turn = false; - } + /* Gibt es eine Taktikrunde ? */ + if (cv_size(&b->leaders)) { + b->turn = 0; + b->has_tactics_turn = true; + } else { + b->turn = 1; + b->has_tactics_turn = false; + } - if (b->region->flags & RF_COMBATDEBUG) battle_stats(bdebug, b); + if (b->region->flags & RF_COMBATDEBUG) battle_stats(bdebug, b); - /* PRECOMBATSPELLS */ - do_combatmagic(b, DO_PRECOMBATSPELL); + /* PRECOMBATSPELLS */ + do_combatmagic(b, DO_PRECOMBATSPELL); - print_stats(b); /* gibt die Kampfaufstellung aus */ - printf("%s (%d, %d) : ", rname(r, NULL), r->x, r->y); + print_stats(b); /* gibt die Kampfaufstellung aus */ + printf("%s (%d, %d) : ", rname(r, NULL), r->x, r->y); #ifdef SMALL_BATTLE_MESSAGES - if (b->nfighters <= 30) { - b->small = true; - } else { - b->small = false; - } + if (b->nfighters <= 30) { + b->small = true; + } else { + b->small = false; + } #endif - for (;battle_report(b) && b->turn<=COMBAT_TURNS;++b->turn) { - char lbuf[256]; + for (;battle_report(b) && b->turn<=COMBAT_TURNS;++b->turn) { + char lbuf[256]; - sprintf(lbuf, "*** Runde: %d", b->turn); - battledebug(lbuf); + sprintf(lbuf, "*** Runde: %d", b->turn); + battledebug(lbuf); - battle_flee(b); - battle_update(b); - battle_attacks(b); + battle_flee(b); + battle_update(b); + battle_attacks(b); #ifdef KARMA_MODULE - /* Regeneration */ - for (fi=0;fi!=b->nfighters;++fi) { - fighter *fig = b->fighters[fi]; + /* Regeneration */ + for (fi=0;fi!=b->nfighters;++fi) { + fighter *fig = b->fighters[fi]; - if (fspecial(fig->unit->faction, FS_REGENERATION)) { - fig->fighting = fig->alive - fig->removed; - if (fig->fighting == 0) continue; - do_regenerate(fig); - } + if (fspecial(fig->unit->faction, FS_REGENERATION)) { + fig->fighting = fig->alive - fig->removed; + if (fig->fighting == 0) continue; + do_regenerate(fig); } + } #endif /* KARMA_MODULE */ - } + } - printf("\n"); + printf("\n"); - /* Auswirkungen berechnen: */ - aftermath(b); - /* Hier ist das Gefecht beendet, und wir können die - * Hilfsstrukturen * wieder löschen: */ + /* Auswirkungen berechnen: */ + aftermath(b); + /* Hier ist das Gefecht beendet, und wir können die + * Hilfsstrukturen * wieder löschen: */ - if (b) { - free_battle(b); - free(b); - } + if (b) { + free_battle(b); + free(b); } } diff --git a/src/common/kernel/battle.h b/src/common/kernel/battle.h index 877011dc9..0197471a7 100644 --- a/src/common/kernel/battle.h +++ b/src/common/kernel/battle.h @@ -206,7 +206,7 @@ extern "C" { extern const troop no_troop; - extern void do_battle(void); + extern void do_battle(struct region * r); /* for combar spells and special attacks */ enum { SELECT_ADVANCE = 0x1, SELECT_DISTANCE = 0x2, SELECT_FIND = 0x4 }; diff --git a/src/common/kernel/build.c b/src/common/kernel/build.c index efca9eb6b..ef4d72251 100644 --- a/src/common/kernel/build.c +++ b/src/common/kernel/build.c @@ -281,18 +281,14 @@ siege_cmd(unit * u, order * ord) } void -do_siege(void) +do_siege(region *r) { - region *r; + if (fval(r->terrain, LAND_REGION)) { + unit *u; - for (r = regions; r; r = r->next) { - if (fval(r->terrain, LAND_REGION)) { - unit *u; - - for (u = r->units; u; u = u->next) { - if (get_keyword(u->thisorder) == K_BESIEGE) { - siege_cmd(u, u->thisorder); - } + for (u = r->units; u; u = u->next) { + if (get_keyword(u->thisorder) == K_BESIEGE) { + siege_cmd(u, u->thisorder); } } } @@ -1106,26 +1102,6 @@ mayboard(const unit * u, const ship * sh) } -void -remove_contacts(void) -{ - region *r; - - for (r = regions; r; r = r->next) { - unit *u; - - for (u = r->units; u; u = u->next) { - attrib * a = (attrib *)a_find(u->attribs, &at_contact); - - while (a!=NULL &&a->type==&at_contact) { - attrib * ar = a; - a = a->next; - a_remove(&u->attribs, ar); - } - } - } -} - int leave_cmd(unit * u, struct order * ord) { @@ -1255,93 +1231,87 @@ enter_building(unit * u, order * ord, int id, boolean report) } void -do_misc(boolean lasttry) +do_misc(region * r, boolean lasttry) { - region *r; + unit **uptr, *uc; - /* lasttry: Fehler nur im zweiten Versuch melden. Sonst konfus. */ + for (uc = r->units; uc; uc = uc->next) { + order * ord; + for (ord = uc->orders; ord; ord = ord->next) { + switch (get_keyword(ord)) { + case K_CONTACT: + contact_cmd(uc, ord, lasttry); + break; + } + } + } - for (r = regions; r; r = r->next) { - unit **uptr, *uc; + for (uptr = &r->units; *uptr;) { + unit * u = *uptr; + order ** ordp = &u->orders; - for (uc = r->units; uc; uc = uc->next) { - order * ord; - for (ord = uc->orders; ord; ord = ord->next) { - switch (get_keyword(ord)) { - case K_CONTACT: - contact_cmd(uc, ord, lasttry); + while (*ordp) { + order * ord = *ordp; + if (get_keyword(ord) == K_ENTER) { + param_t p; + int id; + unit * ulast = NULL; + + init_tokens(ord); + skip_token(); + p = getparam(u->faction->locale); + id = getid(); + + switch (p) { + case P_BUILDING: + case P_GEBAEUDE: + if (u->building && u->building->no==id) break; + if (enter_building(u, ord, id, lasttry)) { + unit *ub; + for (ub=u;ub;ub=ub->next) { + if (ub->building==u->building) { + ulast = ub; + } + } + } + break; + + case P_SHIP: + if (u->ship && u->ship->no==id) break; + if (enter_ship(u, ord, id, lasttry)) { + unit *ub; + ulast = u; + for (ub=u;ub;ub=ub->next) { + if (ub->ship==u->ship) { + ulast = ub; + } + } + } + break; + + default: + if (lasttry) cmistake(u, ord, 79, MSG_MOVE); + + } + if (ulast!=NULL) { + /* Wenn wir hier angekommen sind, war der Befehl + * erfolgreich und wir löschen ihn, damit er im + * zweiten Versuch nicht nochmal ausgeführt wird. */ + *ordp = ord->next; + ord->next = NULL; + free_order(ord); + + if (ulast!=u) { + /* put u behind ulast so it's the last unit in the building */ + *uptr = u->next; + u->next = ulast->next; + ulast->next = u; + } break; } } + if (*ordp==ord) ordp = &ord->next; } - - for (uptr = &r->units; *uptr;) { - unit * u = *uptr; - order ** ordp = &u->orders; - - while (*ordp) { - order * ord = *ordp; - if (get_keyword(ord) == K_ENTER) { - param_t p; - int id; - unit * ulast = NULL; - - init_tokens(ord); - skip_token(); - p = getparam(u->faction->locale); - id = getid(); - - switch (p) { - case P_BUILDING: - case P_GEBAEUDE: - if (u->building && u->building->no==id) break; - if (enter_building(u, ord, id, lasttry)) { - unit *ub; - for (ub=u;ub;ub=ub->next) { - if (ub->building==u->building) { - ulast = ub; - } - } - } - break; - - case P_SHIP: - if (u->ship && u->ship->no==id) break; - if (enter_ship(u, ord, id, lasttry)) { - unit *ub; - ulast = u; - for (ub=u;ub;ub=ub->next) { - if (ub->ship==u->ship) { - ulast = ub; - } - } - } - break; - - default: - if (lasttry) cmistake(u, ord, 79, MSG_MOVE); - - } - if (ulast!=NULL) { - /* Wenn wir hier angekommen sind, war der Befehl - * erfolgreich und wir löschen ihn, damit er im - * zweiten Versuch nicht nochmal ausgeführt wird. */ - *ordp = ord->next; - ord->next = NULL; - free_order(ord); - - if (ulast!=u) { - /* put u behind ulast so it's the last unit in the building */ - *uptr = u->next; - u->next = ulast->next; - ulast->next = u; - } - break; - } - } - if (*ordp==ord) ordp = &ord->next; - } - if (*uptr==u) uptr = &u->next; - } + if (*uptr==u) uptr = &u->next; } } diff --git a/src/common/kernel/build.h b/src/common/kernel/build.h index e00cff43d..04fb20842 100644 --- a/src/common/kernel/build.h +++ b/src/common/kernel/build.h @@ -62,7 +62,7 @@ extern int leave_cmd(struct unit * u, struct order * ord); extern boolean can_contact(const struct region *r, const struct unit *u, const struct unit *u2); -void do_siege(void); +void do_siege(struct region *r); 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, struct order * ord); void continue_ship(struct region * r, struct unit * u, int size); @@ -70,8 +70,7 @@ void continue_ship(struct region * r, struct unit * u, int size); struct building * getbuilding(const struct region * r); struct ship *getship(const struct region * r); -void remove_contacts(void); -void do_misc(boolean tries); +void do_misc(struct region *r, boolean tries); void reportevent(struct region * r, char *s); diff --git a/src/common/kernel/building.c b/src/common/kernel/building.c index c7a75d25e..87d56e9e7 100644 --- a/src/common/kernel/building.c +++ b/src/common/kernel/building.c @@ -496,7 +496,7 @@ destroy_building(building * b) /* Stattdessen nur aus Liste entfernen, aber im Speicher halten. */ choplist(&b->region->buildings, b); - handle_event(&b->attribs, "destroy", b); + handle_event(b->attribs, "destroy", b); } extern attrib_type at_icastle; diff --git a/src/common/kernel/eressea.c b/src/common/kernel/eressea.c index f31268d4d..862c0fa88 100644 --- a/src/common/kernel/eressea.c +++ b/src/common/kernel/eressea.c @@ -2539,9 +2539,9 @@ remove_empty_units_in_region(region *r) faction * f = u->faction; if (!fval(f, FFL_NOTIMEOUT) && f->age > MaxAge()) set_number(u, 0); } - if ((u->number == 0 && u->race != new_race[RC_SPELL]) - || (u->age <= 0 && u->race == new_race[RC_SPELL])) { + if ((u->number == 0 && u->race != new_race[RC_SPELL]) || (u->age <= 0 && u->race == new_race[RC_SPELL])) { destroy_unit(u); + if (u->number==0) remove_unit(u); } if (*up==u) up=&u->next; } diff --git a/src/common/kernel/faction.c b/src/common/kernel/faction.c index 67e9dccf3..6c097508c 100644 --- a/src/common/kernel/faction.c +++ b/src/common/kernel/faction.c @@ -253,7 +253,7 @@ destroyfaction(faction * f) } f->alive = 0; /* no way! f->units = NULL; */ - handle_event(&f->attribs, "destroy", f); + handle_event(f->attribs, "destroy", f); for (ff = factions; ff; ff = ff->next) { group *g; ally *sf, *sfn; diff --git a/src/common/kernel/give.c b/src/common/kernel/give.c index 26541349c..c6cc24857 100644 --- a/src/common/kernel/give.c +++ b/src/common/kernel/give.c @@ -124,8 +124,8 @@ give_item(int want, const item_type * itype, unit * src, unit * dest, struct ord } #endif #endif - handle_event(&src->attribs, "give", dest); - handle_event(&dest->attribs, "receive", src); + handle_event(src->attribs, "give", dest); + handle_event(dest->attribs, "receive", src); #if defined(MUSEUM_MODULE) && defined(TODO) /* TODO: Einen Trigger für den museums-warden benutzen! */ if (a_find(dest->attribs, &at_warden)) { diff --git a/src/common/kernel/magic.c b/src/common/kernel/magic.c index e98859839..e8af0c7a2 100644 --- a/src/common/kernel/magic.c +++ b/src/common/kernel/magic.c @@ -2807,6 +2807,7 @@ magic(void) for (spellrank = 0; spellrank < MAX_SPELLRANK; spellrank++) { free_castorders(cll[spellrank]); } + remove_empty_units(); } const char * diff --git a/src/common/kernel/movement.c b/src/common/kernel/movement.c index 25105b86b..efd9f8398 100644 --- a/src/common/kernel/movement.c +++ b/src/common/kernel/movement.c @@ -2524,83 +2524,81 @@ movement(void) * FOLLOW SHIP is a long order, and doesn't need to be treated in here. */ void -follow_unit(void) +follow_unit(unit * u) { - region * r; + region * r = u->region; + attrib * a = NULL; + order * ord; - for (r=regions;r;r=r->next) { - unit * u; + if (fval(u, UFL_LONGACTION) || LongHunger(u)) return; - for (u=r->units;u;u=u->next) { - attrib * a; - order * ord; + for (ord=u->orders;ord;ord=ord->next) { + const struct locale * lang = u->faction->locale; - if (fval(u, UFL_LONGACTION) || LongHunger(u)) continue; - a = a_find(u->attribs, &at_follow); - for (ord=u->orders;ord;ord=ord->next) { - const struct locale * lang = u->faction->locale; + if (get_keyword(ord) == K_FOLLOW) { + init_tokens(ord); + skip_token(); + if (getparam(lang) == P_UNIT) { + int id = read_unitid(u->faction, r); - if (get_keyword(ord) == K_FOLLOW) { - init_tokens(ord); - skip_token(); - if (getparam(lang) == P_UNIT) { - int id = read_unitid(u->faction, r); + if (a!=NULL) { + a = a_find(u->attribs, &at_follow); + } - if (id>0) { - unit * uf = findunit(id); - if (!a) { - a = a_add(&u->attribs, make_follow(uf)); - } else { - a->data.v = uf; - } - } else if (a) { - a_remove(&u->attribs, a); - a = NULL; - } + if (id>0) { + unit * uf = findunit(id); + if (!a) { + a = a_add(&u->attribs, make_follow(uf)); + } else { + a->data.v = uf; } - } - } - - if (a && !fval(u, UFL_MOVED|UFL_NOTMOVING)) { - unit * u2 = a->data.v; - boolean follow = false; - - if (!u2 || u2->region!=r || !cansee(u->faction, r, u2, 0)) - continue; - - switch (get_keyword(u2->thisorder)) { - case K_MOVE: - case K_ROUTE: - case K_DRIVE: - follow = true; - break; - default: - for (ord=u2->orders;ord;ord=ord->next) { - switch (get_keyword(ord)) { - case K_FOLLOW: - case K_PIRACY: - follow = true; - break; - default: - continue; - } - break; - } - break; - } - if (!follow) { - attrib * a2 = a_find(u2->attribs, &at_follow); - if (a2!=NULL) { - unit * u3 = a2->data.v; - follow = (u3 && u2->region == u2->region); - } - } - if (follow) { - fset(u, UFL_FOLLOWING); - fset(u2, UFL_FOLLOWED); - set_order(&u->thisorder, NULL); + } else if (a) { + a_remove(&u->attribs, a); + a = NULL; } } } } + + if (a && !fval(u, UFL_MOVED|UFL_NOTMOVING)) { + unit * u2 = a->data.v; + boolean follow = false; + + if (!u2 || u2->region!=r || !cansee(u->faction, r, u2, 0)) { + return; + } + + switch (get_keyword(u2->thisorder)) { + case K_MOVE: + case K_ROUTE: + case K_DRIVE: + follow = true; + break; + default: + for (ord=u2->orders;ord;ord=ord->next) { + switch (get_keyword(ord)) { + case K_FOLLOW: + case K_PIRACY: + follow = true; + break; + default: + continue; + } + break; + } + break; + } + if (!follow) { + attrib * a2 = a_find(u2->attribs, &at_follow); + if (a2!=NULL) { + unit * u3 = a2->data.v; + follow = (u3 && u2->region == u2->region); + } + } + if (follow) { + fset(u, UFL_FOLLOWING); + fset(u2, UFL_FOLLOWED); + set_order(&u->thisorder, NULL); + } + } } diff --git a/src/common/kernel/movement.h b/src/common/kernel/movement.h index 7ed65a916..2ec5b232c 100644 --- a/src/common/kernel/movement.h +++ b/src/common/kernel/movement.h @@ -61,7 +61,7 @@ extern void travelthru(const struct unit * u, struct region * r); extern struct ship * move_ship(struct ship * sh, struct region * from, struct region * to, struct region_list * route); extern int walkingcapacity(const struct unit * u); -extern void follow_unit(void); +extern void follow_unit(struct unit * u); struct building_type; boolean buildingtype_exists(const struct region * r, const struct building_type * bt); diff --git a/src/common/kernel/pool.c b/src/common/kernel/pool.c index 69210b311..c0bbd9da5 100644 --- a/src/common/kernel/pool.c +++ b/src/common/kernel/pool.c @@ -260,38 +260,27 @@ use_pooled(unit * u, const resource_type * rtype, unsigned int mode, int count) } -void -init_pool(void) +int +reserve_cmd(unit * u, struct order *ord) { - unit *u; - region *r; + if (u->number > 0 && (urace(u)->ec_flags & GETITEM)) { + int use, count = geti(); + const resource_type * rtype; - /* Falls jemand diese Listen erweitert hat, muß er auch den R_* enum - * erweitert haben. */ - for (r = regions; r; r = r->next) { - for (u = r->units; u; u = u->next) { - order * ord; - for (ord=u->orders; ord; ord=ord->next) { - if (u->number > 0 && (urace(u)->ec_flags & GETITEM) && get_keyword(ord) == K_RESERVE) { - int use, count = geti(); - const resource_type * rtype; + init_tokens(ord); + skip_token(); + count = geti(); - init_tokens(ord); - skip_token(); - count = geti(); + rtype = findresourcetype(getstrtoken(), u->faction->locale); + if (rtype == NULL) return 0; - rtype = findresourcetype(getstrtoken(), u->faction->locale); - if (rtype == NULL) continue; - - new_set_resvalue(u, rtype, 0); /* make sure the pool is empty */ - use = use_pooled(u, rtype, GET_DEFAULT, count); - if (use) { - new_set_resvalue(u, rtype, use); - change_resource(u, rtype, use); - } - } - } + new_set_resvalue(u, rtype, 0); /* make sure the pool is empty */ + use = use_pooled(u, rtype, GET_DEFAULT, count); + if (use) { + new_set_resvalue(u, rtype, use); + change_resource(u, rtype, use); } } + return 0; } diff --git a/src/common/kernel/pool.h b/src/common/kernel/pool.h index b9bbac38f..b5001e4d9 100644 --- a/src/common/kernel/pool.h +++ b/src/common/kernel/pool.h @@ -46,7 +46,7 @@ int change_resource(struct unit * u, const struct resource_type * res, int chang int get_reservation(const struct unit * u, const struct resource_type * res); int change_reservation(struct unit * u, const struct resource_type * res, int value); -void init_pool(void); +int reserve_cmd(struct unit *u, struct order *ord); /** init_pool * initialisiert den regionalen Pool. diff --git a/src/common/kernel/ship.c b/src/common/kernel/ship.c index 7432c6cb2..5c4835a40 100644 --- a/src/common/kernel/ship.c +++ b/src/common/kernel/ship.c @@ -199,7 +199,7 @@ destroy_ship(ship * sh) } sunhash(sh); choplist(&r->ships, sh); - handle_event(&sh->attribs, "destroy", sh); + handle_event(sh->attribs, "destroy", sh); } const char * diff --git a/src/common/kernel/unit.c b/src/common/kernel/unit.c index 1c9ecf2b5..fde2dc9bd 100644 --- a/src/common/kernel/unit.c +++ b/src/common/kernel/unit.c @@ -178,6 +178,17 @@ distribute_items(unit * u) } } +void +remove_unit(unit * u) +{ + region * r = u->region; + assert(u->number==0); + uunhash(u); + if (r) choplist(&r->units, u); + u->next = udestroy; + udestroy = u; +} + void destroy_unit(unit * u) { @@ -261,17 +272,13 @@ destroy_unit(unit * u) u->race = u->irace = new_race[RC_ZOMBIE]; } else { if (u->number) set_number(u, 0); - handle_event(&u->attribs, "destroy", u); + handle_event(u->attribs, "destroy", u); if (r && !fval(r->terrain, SEA_REGION)) { rsetmoney(r, rmoney(r) + get_money(u)); } dhash(u->no, u->faction); u_setfaction(u, NULL); if (r) leave(r, u); - uunhash(u); - if (r) choplist(&r->units, u); - u->next = udestroy; - udestroy = u; } } diff --git a/src/common/kernel/unit.h b/src/common/kernel/unit.h index 82b2d6cf8..b13fc13fb 100644 --- a/src/common/kernel/unit.h +++ b/src/common/kernel/unit.h @@ -189,6 +189,7 @@ extern int get_modifier(const struct unit * u, skill_t sk, int lvl, const struct /* Einheiten werden nicht wirklich zerstört. */ extern void destroy_unit(struct unit * u); +extern void remove_unit(struct unit * u); extern void distribute_items(struct unit * u); /* see resolve.h */ diff --git a/src/common/modules/xecmd.c b/src/common/modules/xecmd.c index 784ccba4b..d5bc3a695 100644 --- a/src/common/modules/xecmd.c +++ b/src/common/modules/xecmd.c @@ -88,36 +88,29 @@ xe_giveballon(unit *u, struct order *ord) fset(u2, UFL_OWNER); } -void -xecmd(void) +int +xecmd(unit * u, order * ord) { - faction *f; + faction *f = u->faction; - for(f=factions; f; f=f->next) { - if(a_find(f->attribs, &at_xontormiaexpress)) { - unit *u; - for(u=f->units; u; u=u->nextF) { - order * ord; - for (ord=u->orders; ord; ord=ord->next) { - if (get_keyword(ord) == K_XE) { - init_tokens(ord); - skip_token(); - switch(findparam(getstrtoken(),f->locale)) { - case P_XEPOTION: - xe_givepotion(u, ord); - break; - case P_XEBALLOON: - xe_giveballon(u, ord); - break; - case P_XELAEN: - xe_givelaen(u, ord); - break; - } - } - } + if (a_find(f->attribs, &at_xontormiaexpress)) { + if (get_keyword(ord) == K_XE) { + init_tokens(ord); + skip_token(); + switch(findparam(getstrtoken(),f->locale)) { + case P_XEPOTION: + xe_givepotion(u, ord); + break; + case P_XEBALLOON: + xe_giveballon(u, ord); + break; + case P_XELAEN: + xe_givelaen(u, ord); + break; } } } + return 0; } #endif diff --git a/src/common/modules/xecmd.h b/src/common/modules/xecmd.h index 64656138a..80835cf76 100644 --- a/src/common/modules/xecmd.h +++ b/src/common/modules/xecmd.h @@ -18,7 +18,7 @@ extern "C" { #ifdef XECMD_MODULE extern attrib_type at_xontormiaexpress; -void xecmd(void); +int xecmd(struct unit * u, struct order * ord); #endif #ifdef __cplusplus diff --git a/src/common/util/event.c b/src/common/util/event.c index 4a8be46e8..94f655091 100644 --- a/src/common/util/event.c +++ b/src/common/util/event.c @@ -200,20 +200,20 @@ add_trigger(struct attrib ** ap, const char * eventname, struct trigger * t) } void -handle_event(attrib ** attribs, const char * eventname, void * data) +handle_event(attrib * attribs, const char * eventname, void * data) { - while (*attribs) { - if ((*attribs)->type==&at_eventhandler) break; - attribs = &(*attribs)->next; + while (attribs) { + if (attribs->type==&at_eventhandler) break; + attribs = attribs->nexttype; } - while (*attribs && (*attribs)->type==&at_eventhandler) { - handler_info * tl = (handler_info*)(*attribs)->data.v; + while (attribs && attribs->type==&at_eventhandler) { + handler_info * tl = (handler_info*)attribs->data.v; if (!strcmp(tl->event, eventname)) { - handler_info * tl = (handler_info*)(*attribs)->data.v; + handler_info * tl = (handler_info*)attribs->data.v; handle_triggers(&tl->triggers, data); break; } - attribs = &(*attribs)->next; + attribs = attribs->next; } } diff --git a/src/common/util/event.h b/src/common/util/event.h index d3e73030e..7c8e31ca3 100644 --- a/src/common/util/event.h +++ b/src/common/util/event.h @@ -58,7 +58,7 @@ extern void add_trigger(struct attrib ** ap, const char * eventname, struct trig extern void remove_triggers(struct attrib ** ap, const char * eventname, const trigger_type * tt); extern struct trigger ** get_triggers(struct attrib * ap, const char * eventname); /* calls handle() for each of these. e.g. used in timeout */ -extern void handle_event(struct attrib ** attribs, const char * eventname, void * data); +extern void handle_event(struct attrib * attribs, const char * eventname, void * data); /* functions for making complex triggers: */ extern void free_triggers(trigger * triggers); /* release all these triggers */ diff --git a/src/eressea/lua/region.cpp b/src/eressea/lua/region.cpp index 9159f2668..c77e13a3e 100644 --- a/src/eressea/lua/region.cpp +++ b/src/eressea/lua/region.cpp @@ -232,7 +232,9 @@ region_remove(region& r) while (*rp) { if (*rp==&r) { while (r.units) { - destroy_unit(r.units); + unit * u = r.units; + destroy_unit(u); + remove_unit(u); } *rp = r.next; #ifdef FAST_CONNECT diff --git a/src/mapper/map_units.c b/src/mapper/map_units.c index 3e2ce9e7e..bfc004fe4 100644 --- a/src/mapper/map_units.c +++ b/src/mapper/map_units.c @@ -1465,6 +1465,7 @@ showunits(region * r) if (yes_no(0, lbuf, 'n')) { modified = 1; destroy_unit(clipunit); + if (clipunit->number==0) remove_unit(clipunit); clipunit = 0; clipregion = 0; for (pline = 0, tmp = eh; tmp != pointer; tmp = tmp->next)