server/src/common/gamecode/laws.c

3743 lines
87 KiB
C
Raw Normal View History

2001-01-25 10:37:55 +01:00
/* vi: set ts=2:
*
*
* Eressea PB(E)M host Copyright (C) 1998-2003
2001-01-25 10:37:55 +01:00
* Christian Schlittchen (corwin@amber.kn-bremen.de)
* Katja Zedel (katze@felidae.kn-bremen.de)
* Henning Peters (faroul@beyond.kn-bremen.de)
* Enno Rehling (enno@eressea-pbem.de)
* Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
*
* based on:
*
* Atlantis v1.0 13 September 1993 Copyright 1993 by Russell Wallace
* Atlantis v1.7 Copyright 1996 by Alex Schr<EFBFBD>der
*
* This program may not be used, modified or distributed without
* prior permission by the authors of Eressea.
* This program may not be sold or used commercially without prior written
* permission from the authors.
*/
#include <config.h>
2001-01-30 21:02:06 +01:00
#include <eressea.h>
2001-01-25 10:37:55 +01:00
#include "laws.h"
2001-02-10 23:02:10 +01:00
#include <modules/gmcmd.h>
2001-04-26 19:41:06 +02:00
#include <modules/infocmd.h>
2004-02-21 23:25:00 +01:00
#ifdef WORMHOLE_MODULE
#include <modules/wormhole.h>
#endif
2001-01-30 21:02:06 +01:00
/* gamecode includes */
#include "economy.h"
#include "monster.h"
#include "randenc.h"
#include "study.h"
2001-01-30 21:02:06 +01:00
/* kernel includes */
#include <alchemy.h>
2001-01-30 21:02:06 +01:00
#include <border.h>
#include <faction.h>
#include <item.h>
#include <magic.h>
2001-01-30 21:02:06 +01:00
#include <message.h>
#include <save.h>
#include <ship.h>
#include <skill.h>
#include <movement.h>
#include <spy.h>
#include <race.h>
#include <battle.h>
#include <region.h>
#include <unit.h>
#include <plane.h>
#include <karma.h>
#include <pool.h>
#include <building.h>
#include <group.h>
#include <race.h>
#include <resources.h>
#ifdef USE_UGROUPS
# include <ugroup.h>
#endif
/* attributes includes */
#include <attributes/racename.h>
#include <attributes/raceprefix.h>
#include <attributes/synonym.h>
2001-01-25 10:37:55 +01:00
/* util includes */
#include <event.h>
#include <base36.h>
2001-01-30 21:02:06 +01:00
#include <goodies.h>
2001-01-25 10:37:55 +01:00
#include <rand.h>
#include <sql.h>
#include <util/message.h>
2001-01-25 10:37:55 +01:00
#include <modules/xecmd.h>
2002-09-02 22:36:12 +02:00
#ifdef ALLIANCES
#include <modules/alliance.h>
#endif
#ifdef AT_OPTION
/* attributes includes */
#include <attributes/option.h>
#endif
2001-01-25 10:37:55 +01:00
/* libc includes */
#include <stdio.h>
#include <math.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>
2001-01-25 10:37:55 +01:00
#include <attributes/otherfaction.h>
2001-01-25 10:37:55 +01:00
/* - external symbols ------------------------------------------ */
extern int dropouts[2];
extern int * age;
/* - exported global symbols ----------------------------------- */
boolean nobattle = false;
boolean nomonsters = false;
2001-01-25 10:37:55 +01:00
/* ------------------------------------------------------------- */
static int
RemoveNMRNewbie(void) {
static int value = -1;
if (value<0) {
const char * str = get_param(global.parameters, "nmr.removenewbie");
value = str?atoi(str):0;
}
return value;
}
static void
restart(unit *u, const race * rc)
2001-01-25 10:37:55 +01:00
{
faction * oldf = u->faction;
faction *f = addfaction(oldf->email, oldf->passw, rc, oldf->locale, oldf->subscription);
2003-12-14 11:02:29 +01:00
unit * nu = addplayer(u->region, f);
strlist ** o=&u->orders;
f->subscription = u->faction->subscription;
fset(f, FFL_RESTART);
if (f->subscription) fprintf(sqlstream, "UPDATE subscriptions set faction='%s', race='%s' where id=%u;\n",
itoa36(f->no), dbrace(rc), f->subscription);
f->magiegebiet = u->faction->magiegebiet;
f->options = u->faction->options;
freestrlist(nu->orders);
nu->orders = u->orders;
u->orders = NULL;
while (*o) {
strlist * S = *o;
if (igetkeyword(S->s, u->faction->locale) == K_RESTART) {
*o = S->next;
S->next = NULL;
freestrlist(S);
} else {
o = &S->next;
}
}
destroyfaction(u->faction);
2001-01-25 10:37:55 +01:00
}
/* ------------------------------------------------------------- */
static void
checkorders(void)
{
faction *f;
puts(" - Warne sp<73>te Spieler...");
for (f = factions; f; f = f->next)
if (f->no!=MONSTER_FACTION && turn - f->lastorders == NMRTimeout() - 1)
2002-07-29 09:35:37 +02:00
ADDMSG(&f->msgs, msg_message("turnreminder", ""));
2001-01-25 10:37:55 +01:00
}
static boolean
help_money(const unit * u)
{
if (u->race->ec_flags & GIVEITEM) return true;
return false;
}
2001-01-25 10:37:55 +01:00
static void
get_food(region *r)
{
unit *u;
int peasantfood = rpeasants(r)*10;
2004-02-29 09:59:15 +01:00
unit * demon = r->units;
2001-01-25 10:37:55 +01:00
/* 1. Versorgung von eigenen Einheiten. Das vorhandene Silber
* wird zun<EFBFBD>chst so auf die Einheiten aufgeteilt, dass idealerweise
* jede Einheit genug Silber f<EFBFBD>r ihren Unterhalt hat. */
2001-01-25 10:37:55 +01:00
for (u = r->units; u; u = u->next) {
int need = lifestyle(u);
/* Erstmal zur<75>cksetzen */
freset(u, UFL_HUNGER);
2001-01-25 10:37:55 +01:00
need -= get_money(u);
if (need > 0) {
unit *v;
for (v = r->units; need && v; v = v->next) {
if (v->faction == u->faction && help_money(v)) {
int give = get_money(v) - lifestyle(v);
give = min(need, give);
if (give>0) {
change_money(v, -give);
change_money(u, give);
need -= give;
}
}
}
2001-01-25 10:37:55 +01:00
}
}
/* 2. Versorgung durch Fremde. Das Silber alliierter Einheiten wird
* entsprechend verteilt. */
2001-01-25 10:37:55 +01:00
for (u = r->units; u; u = u->next) {
int need = lifestyle(u);
faction * f = u->faction;
2001-01-25 10:37:55 +01:00
need -= max(0, get_money(u));
if (need > 0) {
unit *v;
for (v = r->units; need && v; v = v->next) {
if (v->faction != f && alliedunit(v, f, HELP_MONEY) && help_money(v)) {
int give = get_money(v) - lifestyle(v);
2001-01-25 10:37:55 +01:00
give = min(need, give);
if (give>0) {
2001-01-25 10:37:55 +01:00
change_money(v, -give);
change_money(u, give);
need -= give;
add_spende(v->faction, u->faction, give, r);
}
}
}
2001-01-25 10:37:55 +01:00
/* Die Einheit hat nicht genug Geld zusammengekratzt und
* nimmt Schaden: */
if (need) {
int lspp = lifestyle(u)/u->number;
if (lspp > 0) {
int number = (need+lspp-1)/lspp;
if (hunger(number, u)) fset(u, UFL_HUNGER);
}
}
}
}
2001-01-25 10:37:55 +01:00
2004-02-29 09:59:15 +01:00
/* 3. bestimmen, wie viele Bauern gefressen werden.
* bei fehlenden Bauern den D<EFBFBD>mon hungern lassen
*/
for (u = r->units; u; u = u->next) {
if (u->race == new_race[RC_DAEMON]) {
2004-02-29 09:59:15 +01:00
int hungry = u->number;
while (demon!=NULL && hungry>0) {
/* alwayy start with the first known uint that may have some blood */
static const struct potion_type * pt_blood;
unit * ud = demon;
if (pt_blood==NULL) pt_blood = pt_find("peasantblood");
demon = NULL; /* this will be re-set in the loop */
while (ud!=NULL) {
if (ud->race==new_race[RC_DAEMON]) {
if (get_effect(ud, pt_blood)) {
/* new best guess for first blood-donor: */
if (demon==NULL) demon = ud;
/* if he's in our faction, drain him: */
if (ud->faction==u->faction) break;
}
}
ud=ud->next;
}
if (ud!=NULL) {
int blut = get_effect(ud, pt_blood);
blut = min(blut, hungry);
change_effect(ud, pt_blood, -blut);
hungry -= blut;
2004-02-29 11:00:26 +01:00
} else {
break;
/* no more help for us */
}
2004-02-29 09:59:15 +01:00
}
if (r->planep == NULL || !fval(r->planep, PFL_NOFEED)) {
2004-02-29 09:59:15 +01:00
if (peasantfood>=hungry) {
peasantfood -= hungry;
hungry = 0;
} else {
2004-02-29 09:59:15 +01:00
hungry -= peasantfood;
peasantfood = 0;
}
2004-02-29 09:59:15 +01:00
if (hungry > 0) {
hunger(hungry, u); /* nicht gef<65>tterte d<>monen hungern */
}
}
2001-01-25 10:37:55 +01:00
}
}
rsetpeasants(r, peasantfood/10);
2001-01-25 10:37:55 +01:00
/* 3. Von den <20>berlebenden das Geld abziehen: */
for (u = r->units; u; u = u->next) {
int need = min(get_money(u), lifestyle(u));
change_money(u, -need);
}
}
static void
live(region * r)
{
2004-04-09 03:32:06 +02:00
unit **up = &r->units;
2001-01-25 10:37:55 +01:00
2004-04-09 03:32:06 +02:00
get_food(r);
2001-01-25 10:37:55 +01:00
2004-04-09 03:32:06 +02:00
while (*up) {
unit * u = *up;
2004-04-09 03:32:06 +02:00
/* IUW: age_unit() kann u l<>schen, u->next ist dann
* undefiniert, also m<EFBFBD>ssen wir hier schon das n<EFBFBD>chste
* Element bestimmen */
int effect = get_effect(u, oldpotiontype[P_FOOL]);
if (effect > 0) { /* Trank "Dumpfbackenbrot" */
skill * sv = u->skills, * sb = NULL;
while (sv!=u->skills+u->skill_size) {
if (sb==NULL || skill_compare(sv, sb)>0) {
sb = sv;
}
++sv;
}
/* bestes Talent raussuchen */
if (sb!=NULL) {
int weeks = min(effect, u->number);
reduce_skill(u, sb, weeks);
ADDMSG(&u->faction->msgs, msg_message("dumbeffect",
"unit weeks skill", u, weeks, (skill_t)sb->id));
} /* sonst Gl<47>ck gehabt: wer nix wei<65>, kann nix vergessen... */
change_effect(u, oldpotiontype[P_FOOL], -effect);
2004-04-09 03:32:06 +02:00
}
age_unit(r, u);
if (*up==u) up=&u->next;
2004-04-09 03:32:06 +02:00
}
2001-01-25 10:37:55 +01:00
}
/*
* This procedure calculates the number of emigrating peasants for the given
* region r. There are two incentives for peasants to emigrate:
* 1) They prefer the less crowded areas.
* Example: mountains, 700 peasants (max 1000), 70% inhabited
* plain, 5000 peasants (max 10000), 50% inhabited
* 700*(PEASANTSWANDER_WEIGHT/100)*((70-50)/100) peasants wander
* from mountains to plain.
* Effect : peasents will leave densely populated regions.
* 2) Peasants prefer richer neighbour regions.
* Example: region A, 700 peasants, wealth $10500, $15 per head
* region B, 2500 peasants, wealth $25000, $10 per head
* Some peasants will emigrate from B to A because $15 > $10
* exactly: 2500*(PEASANTSGREED_WEIGHT1/100)*((15-10)/100)
* Not taken in consideration:
* - movement because of monsters.
* - movement because of wars
* - movement because of low loyalty relating to present parties.
*/
#if NEW_MIGRATION == 1
/* Arbeitsversion */
static void
calculate_emigration(region *r)
{
direction_t i;
int overpopulation = rpeasants(r) - maxworkingpeasants(r);
int weight[MAXDIRECTIONS], weightall;
/* Bauern wandern nur bei <20>berbev<65>lkerung, sonst gar nicht */
if(overpopulation <= 0) return;
weightall = 0;
for (i = 0; i != MAXDIRECTIONS; i++) {
region *rc = rconnect(r,i);
int w;
if (rc == NULL || rterrain(rc) == T_OCEAN) {
w = 0;
} else {
w = rpeasants(rc) - maxworkingpeasants(rc);
w = max(0,w);
if(rterrain(rc) == T_VOLCANO || rterrain(rc) == T_VOLCANO_SMOKING) {
w = w/10;
}
}
weight[i] = w;
weightall += w;
}
if (weightall !=0 ) for (i = 0; i != MAXDIRECTIONS; i++) {
region *rc;
if((rc = rconnect(r,i)) != NULL) {
int wandering_peasants = (overpopulation * weight[i])/weightall;
if (wandering_peasants > 0) {
r->land->newpeasants -= wandering_peasants;
rc->land->newpeasants += wandering_peasants;
}
}
}
}
#else
2001-01-25 10:37:55 +01:00
void
calculate_emigration(region *r)
{
direction_t i, j;
2001-01-25 10:37:55 +01:00
int maxpeasants_here;
int maxpeasants[MAXDIRECTIONS];
double wfactor, gfactor;
/* Vermeidung von DivByZero */
maxpeasants_here = max(maxworkingpeasants(r),1);
for (i = 0; i != MAXDIRECTIONS; i++) {
region *c = rconnect(r, i);
if (c && rterrain(c) != T_OCEAN) {
maxpeasants[i] = maxworkingpeasants(c);
} else maxpeasants[i] = 0;
}
/* calculate emigration for all directions independently */
for (i = 0; i != MAXDIRECTIONS; i++) {
region * c = rconnect(r, i);
if (!c) continue;
if (fval(r, RF_ORCIFIED)==fval(c, RF_ORCIFIED)) {
if (landregion(rterrain(c)) && landregion(rterrain(r))) {
int wandering_peasants;
double vfactor;
2001-01-25 10:37:55 +01:00
/* First let's calculate the peasants who wander off to less inhabited
* regions. wfactor indicates the difference of population denity.
* Never let more than PEASANTSWANDER_WEIGHT per cent wander off in one
* direction. */
wfactor = ((double) rpeasants(r) / maxpeasants_here -
((double) rpeasants(c) / maxpeasants[i]));
wfactor = max(wfactor, 0);
wfactor = min(wfactor, 1);
/* Now let's handle the greedy peasants. gfactor indicates the
* difference of per-head-wealth. Never let more than
* PEASANTSGREED_WEIGHT per cent wander off in one direction. */
gfactor = (((double) rmoney(c) / max(rpeasants(c), 1)) -
((double) rmoney(r) / max(rpeasants(r), 1))) / 500;
gfactor = max(gfactor, 0);
gfactor = min(gfactor, 1);
/* This calculates the influence of volcanos on peasant
* migration. */
if(rterrain(c) == T_VOLCANO || rterrain(c) == T_VOLCANO_SMOKING) {
vfactor = 0.10;
} else {
vfactor = 1.00;
}
for(j=0; j != MAXDIRECTIONS; j++) {
region *rv = rconnect(c, j);
if(rv && (rterrain(rv) == T_VOLCANO || rterrain(rv) == T_VOLCANO_SMOKING)) {
vfactor *= 0.5;
break;
}
}
wandering_peasants = (int) (rpeasants(r) * (gfactor+wfactor)
* vfactor * PEASANTSWANDER_WEIGHT / 100.0);
2001-01-25 10:37:55 +01:00
r->land->newpeasants -= wandering_peasants;
c->land->newpeasants += wandering_peasants;
}
}
}
}
#endif
2001-01-25 10:37:55 +01:00
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static void
peasants(region * r)
{
int glueck;
2001-01-25 10:37:55 +01:00
/* Das Geld, da<64> die Bauern erwirtschaftet haben unter expandwork, gibt
* den Bauern genug f<EFBFBD>r 11 Bauern pro Ebene ohne Wald. Der Wald
* breitet sich nicht in Gebiete aus, die bebaut werden. */
int peasants, n, i, satiated, money;
#if PEASANTS_DO_NOT_STARVE == 0
int dead;
#endif
2001-01-25 10:37:55 +01:00
attrib * a;
/* Bauern vermehren sich */
/* Bis zu 1000 Bauern k<>nnen Zwillinge bekommen oder 1000 Bauern
* wollen nicht! */
a = a_find(r->attribs, &at_peasantluck);
if (!a) {
glueck = 0;
} else {
glueck = a->data.i * 1000;
}
peasants = rpeasants(r);
for (n = peasants; n; n--) {
if (glueck >= 0) { /* Sonst keine Vermehrung */
2002-02-03 13:56:15 +01:00
if (rand() % 10000 < PEASANTGROWTH) {
2001-01-25 10:37:55 +01:00
if ((float) peasants
/ ((float) production(r) * MAXPEASANTS_PER_AREA)
< 0.9 || rand() % 100 < PEASANTFORCE) {
peasants++;
}
}
} else
glueck++;
if (glueck > 0) { /* Doppelvermehrung */
for(i=0; i<PEASANTLUCK; i++) {
if (rand() % 10000 < PEASANTGROWTH)
peasants++;
}
2001-01-25 10:37:55 +01:00
glueck--;
}
}
/* Alle werden satt, oder halt soviele f<>r die es auch Geld gibt */
money = rmoney(r);
satiated = min(peasants, money / MAINTENANCE);
rsetmoney(r, money - satiated * MAINTENANCE);
/* Von denjenigen, die nicht satt geworden sind, verhungert der
* Gro<EFBFBD>teil. dead kann nie gr<EFBFBD><EFBFBD>er als rpeasants(r) - satiated werden,
* so dass rpeasants(r) >= 0 bleiben mu<EFBFBD>. */
/* Es verhungert maximal die unterern<72>hrten Bev<65>lkerung. */
#if PEASANTS_DO_NOT_STARVE == 0
2001-01-25 10:37:55 +01:00
dead = 0;
for (n = min((peasants - satiated), rpeasants(r)); n; n--)
if (rand() % 100 > STARVATION_SURVIVAL)
dead++;
if(dead > 0) {
message * msg = add_message(&r->msgs, msg_message("phunger", "dead", dead));
msg_release(msg);
2001-01-25 10:37:55 +01:00
peasants -= dead;
}
2002-02-24 20:32:48 +01:00
#endif
2001-01-25 10:37:55 +01:00
rsetpeasants(r, peasants);
}
/* ------------------------------------------------------------- */
typedef struct migration {
struct migration * next;
region * r;
int horses;
int trees;
} migration;
#define MSIZE 1023
migration * migrants[MSIZE];
migration * free_migrants;
static migration *
get_migrants(region * r)
{
int key = region_hashkey(r);
int index = key % MSIZE;
migration * m = migrants[index];
while (m && m->r != r)
m = m->next;
if (m == NULL) {
/* Es gibt noch keine Migration. Also eine erzeugen
*/
m = free_migrants;
if (!m) m = calloc(1, sizeof(migration));
else {
free_migrants = free_migrants->next;
m->horses = 0;
m->trees = 0;
}
m->r = r;
m->next = migrants[index];
migrants[index] = m;
}
return m;
}
static void
migrate(region * r)
{
int key = region_hashkey(r);
int index = key % MSIZE;
migration ** hp = &migrants[index];
fset(r, RF_MIGRATION);
while (*hp && (*hp)->r != r) hp = &(*hp)->next;
if (*hp) {
migration * m = *hp;
rsethorses(r, rhorses(r) + m->horses);
/* Was macht das denn hier?
* Baumwanderung wird in trees() gemacht.
* wer fragt das? Die Baumwanderung war abh<EFBFBD>ngig von der
* Auswertungsreihenfolge der regionen,
* das hatte ich ge<EFBFBD>ndert. jemand hat es wieder gel<EFBFBD>scht, toll.
* ich habe es wieder aktiviert, mu<EFBFBD> getestet werden.
*/
#if GROWING_TREES == 0
2001-01-25 10:37:55 +01:00
rsettrees(r, rtrees(r) + m->trees);
#endif
2001-01-25 10:37:55 +01:00
*hp = m->next;
m->next = free_migrants;
free_migrants = m;
}
}
static void
horses(region * r)
{
int horses, maxhorses;
2001-01-25 10:37:55 +01:00
direction_t n;
/* Logistisches Wachstum, Optimum bei halbem Maximalbesatz. */
maxhorses = maxworkingpeasants(r)/10;
maxhorses = max(0, maxhorses);
horses = rhorses(r);
if(is_cursed(r->attribs, C_CURSED_BY_THE_GODS, 0)) {
rsethorses(r, (int)(horses*0.9));
} else if (maxhorses > 0) {
int i;
int growth = (int)((RESOURCE_QUANTITY * HORSEGROWTH * 200 * (maxhorses-horses))/maxhorses);
if(a_find(r->attribs, &at_horseluck)) growth *= 2;
/* printf("Horses: <%d> %d -> ", growth, horses); */
for(i = 0; i < horses; i++) {
if(rand()%10000 < growth) horses++;
2001-01-25 10:37:55 +01:00
}
/* printf("%d\n", horses); */
rsethorses(r, horses);
2001-01-25 10:37:55 +01:00
}
/* Pferde wandern in Nachbarregionen.
* Falls die Nachbarregion noch berechnet
* werden mu<EFBFBD>, wird eine migration-Struktur gebildet,
* die dann erst in die Berechnung der Nachbarstruktur einflie<EFBFBD>t.
*/
for(n = 0; n != MAXDIRECTIONS; n++) {
region * r2 = rconnect(r, n);
if(r2 && (terrain[r2->terrain].flags & WALK_INTO)) {
int pt = (rhorses(r) * HORSEMOVE)/100;
pt = (int)normalvariate(pt, pt/4.0);
pt = max(0, pt);
if (fval(r2, RF_MIGRATION))
rsethorses(r2, rhorses(r2) + pt);
else {
migration * nb;
/* haben wir die Migration schonmal benutzt?
* wenn nicht, m<EFBFBD>ssen wir sie suchen.
* Wandernde Pferde vermehren sich nicht.
*/
nb = get_migrants(r2);
nb->horses += pt;
}
/* Wandernde Pferde sollten auch abgezogen werden */
rsethorses(r, rhorses(r) - pt);
}
}
assert(rhorses(r) >= 0);
}
#if GROWING_TREES
static int
count_race(const region *r, const race *rc)
{
unit *u;
int c = 0;
for(u = r->units; u; u=u->next)
if(u->race == rc) c += u->number;
return c;
}
extern attrib_type at_germs;
static void
trees(region * r, const int current_season, const int last_weeks_season)
{
int growth, grownup_trees, i, seeds, sprout, seedchance;
direction_t d;
attrib *a;
if(current_season == SEASON_SUMMER || current_season == SEASON_AUTUMN) {
int elves = count_race(r,new_race[RC_ELF]);
a = a_find(r->attribs, &at_germs);
if(a && last_weeks_season == SEASON_SPRING) {
/* ungekeimte Samen bleiben erhalten, Spr<70><72>linge wachsen */
sprout = min(a->data.sa[1], rtrees(r, 1));
/* aus dem gesamt Spr<70><72>lingepool abziehen */
rsettrees(r, 1, rtrees(r, 1) - sprout);
/* zu den B<>umen hinzuf<75>gen */
rsettrees(r, 2, rtrees(r, 2) + sprout);
a_removeall(&r->attribs, &at_germs);
}
if(is_cursed(r->attribs, C_CURSED_BY_THE_GODS, 0)) {
rsettrees(r, 1, (int)(rtrees(r, 1) * 0.9));
rsettrees(r, 2, (int)(rtrees(r, 2) * 0.9));
return;
}
if(production(r) <= 0) return;
2002-03-03 12:52:22 +01:00
/* Grundchance 1.0% */
seedchance = (int)(FORESTGROWTH * RESOURCE_QUANTITY);
2002-03-03 12:52:22 +01:00
/* Jeder Elf in der Region erh<72>ht die Chance um 0.0008%. */
seedchance += (min(elves, (production(r)*MAXPEASANTS_PER_AREA)/8)) * 8;
grownup_trees = rtrees(r, 2);
seeds = 0;
for(i=0;i<grownup_trees;i++) {
2002-03-03 12:52:22 +01:00
if(rand()%1000000 < seedchance) seeds++;
}
rsettrees(r, 0, rtrees(r, 0) + seeds);
/* B<>ume breiten sich in Nachbarregionen aus. */
/* Gesamtzahl der Samen:
* bis zu 6% (FORESTGROWTH*3) der B<EFBFBD>ume samen in die Nachbarregionen */
seeds = (rtrees(r, 2) * FORESTGROWTH * 3)/1000000;
for (d=0;d!=MAXDIRECTIONS;++d) {
region * r2 = rconnect(r, d);
if (r2 && (terrain[r2->terrain].flags & WALK_INTO)) {
/* Eine Landregion, wir versuchen Samen zu verteilen:
* Die Chance, das Samen ein St<EFBFBD>ck Boden finden, in dem sie
* keimen k<EFBFBD>nnen, h<EFBFBD>ngt von der Bewuchsdichte und der
* verf<EFBFBD>gbaren Fl<EFBFBD>che ab. In Gletschern gibt es weniger
* M<EFBFBD>glichkeiten als in Ebenen. */
sprout = 0;
seedchance = (100 * maxworkingpeasants(r2)) / terrain[r2->terrain].production_max;
for(i=0; i<seeds/MAXDIRECTIONS; i++) {
if(rand()%10000 < seedchance) sprout++;
}
rsettrees(r2, 0, rtrees(r2, 0) + sprout);
}
}
} else if(current_season == SEASON_SPRING) {
if(is_cursed(r->attribs, C_CURSED_BY_THE_GODS, 0)) return;
/* in at_germs merken uns die Zahl der Samen und Spr<70><72>linge, die
* dieses Jahr <EFBFBD>lter werden d<EFBFBD>rfen, damit nicht ein Same im selben
* Zyklus zum Baum werden kann */
a = a_find(r->attribs, &at_germs);
if(!a) {
a = a_add(&r->attribs, a_new(&at_germs));
a->data.sa[0] = (short)rtrees(r, 0);
a->data.sa[1] = (short)rtrees(r, 1);
}
/* wir haben 6 Wochen zum wachsen, jeder Same/Spro<72> hat 18% Chance
* zu wachsen, damit sollten nach 5-6 Wochen alle gewachsen sein */
growth = 1800;
/* Samenwachstum */
/* Raubbau abfangen, es d<>rfen nie mehr Samen wachsen, als aktuell
* in der Region sind */
seeds = min(a->data.sa[0], rtrees(r, 0));
sprout = 0;
for(i=0;i<seeds;i++) {
if(rand()%10000 < growth) sprout++;
}
/* aus dem Samenpool dieses Jahres abziehen */
a->data.sa[0] = (short)(seeds - sprout);
/* aus dem gesamt Samenpool abziehen */
rsettrees(r, 0, rtrees(r, 0) - sprout);
/* zu den Spr<70><72>linge hinzuf<75>gen */
rsettrees(r, 1, rtrees(r, 1) + sprout);
/* Baumwachstum */
/* hier gehen wir davon aus, das Jungb<67>ume nicht ohne weiteres aus
* der Region entfernt werden k<EFBFBD>nnen, da Jungb<EFBFBD>ume in der gleichen
* Runde nachwachsen, wir also nicht mehr zwischen diesj<EFBFBD>hrigen und
* 'alten' Jungb<EFBFBD>umen unterscheiden k<EFBFBD>nnten */
sprout = min(a->data.sa[1], rtrees(r, 1));
grownup_trees = 0;
for(i=0;i<sprout;i++) {
if(rand()%10000 < growth) grownup_trees++;
}
/* aus dem Spr<70><72>lingepool dieses Jahres abziehen */
a->data.sa[1] = (short)(sprout - grownup_trees);
/* aus dem gesamt Spr<70><72>lingepool abziehen */
rsettrees(r, 1, rtrees(r, 1) - grownup_trees);
/* zu den B<>umen hinzuf<75>gen */
rsettrees(r, 2, rtrees(r, 2) + grownup_trees);
}
/* Jetzt die Kr<4B>utervermehrung. Vermehrt wird logistisch:
*
* Jedes Kraut hat eine Wahrscheinlichkeit von (100-(vorhandene
* Kr<EFBFBD>uter))% sich zu vermehren. */
if(current_season == SEASON_SPRING || current_season == SEASON_SUMMER
|| current_season == SEASON_AUTUMN)
{
for(i = rherbs(r); i > 0; i--) {
if (rand()%100 < (100-rherbs(r))) rsetherbs(r, (short)(rherbs(r)+1));
}
}
}
#else
2001-01-25 10:37:55 +01:00
static void
trees(region * r)
{
int i, maxtrees;
2001-01-25 10:37:55 +01:00
int tree = rtrees(r);
direction_t d;
/* B<>ume vermehren sich. m ist die Anzahl B<>ume, f<>r die es Land
* gibt. Der Wald besiedelt keine bebauten Gebiete, wird den Pferden
* aber Land wegnehmen. Gibt es zuviele Bauern, werden sie den Wald
* nicht f<EFBFBD>llen, sondern verhungern. Der Wald kann nur von Spielern gef<EFBFBD>llt
* werden! Der Wald wandert nicht. Auch bei magischen Terrainver<EFBFBD>nderungen
* darf m nicht negativ werden! */
if(production(r) <= 0) return;
maxtrees = production(r) - rpeasants(r)/MAXPEASANTS_PER_AREA;
maxtrees = max(0, maxtrees);
2001-01-25 10:37:55 +01:00
/* Solange es noch freie Pl<50>tze gibt, darf jeder Baum versuchen, sich
* fortzupflanzen. Da B<EFBFBD>ume nicht sofort eingehen, wenn es keinen
* Platz gibt (wie zB. die Pferde), darf nicht einfach drauflos vermehrt
* werden und dann ein min () gemacht werden, sondern es mu<EFBFBD> auf diese
* Weise vermehrt werden. */
if(is_cursed(r->attribs, C_CURSED_BY_THE_GODS, 0)) {
tree = (int)(tree*0.9);
} else if(maxtrees > 0) {
int growth = (int)((FORESTGROWTH * 200 * ((maxtrees*1.2)-tree))/maxtrees);
growth = max(FORESTGROWTH*50, growth);
growth = min(FORESTGROWTH*400, growth);
/* printf("Trees: <%d> %d -> ", growth, tree); */
for(i=0;i<tree;i++) {
if(rand()%10000 < growth) tree++;
}
/* printf("%d (max: %d)\n", tree, maxtrees); */
2001-01-25 10:37:55 +01:00
}
/* B<>ume breiten sich in Nachbarregionen aus.
* warnung: fr<EFBFBD>her kamen b<EFBFBD>ume aus nachbarregionen, heute
* gehen sie von der aktuellen in die benachbarten.
* Die Chance, das ein Baum in eine Region r2 einwandert, ist
* (production-rtrees(r2))/10000.
* Die Richtung, in der sich ein Baum vermehrt, ist zuf<EFBFBD>llig.
* Es ibt also genausoviel Versuche, in einen Geltscher zu
* wandern, wie in eine ebene - nur halt weniger Erfolge.
* Die Summe der Versuche ist rtrees(r), jeder Baum
* versucht es also einmal pro Woche, mit maximal 10% chance
* (wenn ein voller wald von lauter leeren ebenen umgeben ist)
*/
for (d=0;d!=MAXDIRECTIONS;++d) {
region * r2 = rconnect(r, d);
if (r2
&& (terrain[r2->terrain].flags & WALK_INTO)
&& fval(r2, RF_MALLORN) == fval(r, RF_MALLORN)) {
/* Da hier rtrees(r2) abgefragt wird, macht es einen Unterschied,
* ob das wachstum in r2 schon stattgefunden hat, oder nicht.
* leider nicht einfach zu verhindern */
int pt = (production(r2)-rtrees(r2));
pt = tree*max(0, pt) /
(MAXDIRECTIONS*terrain[T_PLAIN].production_max*10);
if (fval(r2, RF_MIGRATION))
rsettrees(r2, rtrees(r2) + pt);
else {
migration * nb;
/* haben wir die Migration schonmal benutzt?
* wenn nicht, m<EFBFBD>ssen wir sie suchen.
* Wandernde Pferde vermehren sich nicht.
*/
nb = get_migrants(r2);
nb->trees += pt;
}
}
}
rsettrees(r, tree);
assert(tree >= 0);
/* Jetzt die Kr<4B>utervermehrung. Vermehrt wird logistisch:
*
* Jedes Kraut hat eine Wahrscheinlichkeit von (100-(vorhandene
* Kr<EFBFBD>uter))% sich zu vermehren. */
for(i = rherbs(r); i > 0; i--) {
2001-01-25 10:37:55 +01:00
if (rand()%100 < (100-rherbs(r))) rsetherbs(r, (short)(rherbs(r)+1));
}
}
#endif
2001-01-25 10:37:55 +01:00
#if NEW_RESOURCEGROWTH == 0
extern attrib_type at_laen;
2001-01-25 10:37:55 +01:00
static void
iron(region * r)
{
if(is_cursed(r->attribs, C_CURSED_BY_THE_GODS, 0)) return;
2001-01-25 10:37:55 +01:00
#ifndef NO_GROWTH
if (rterrain(r) == T_MOUNTAIN) {
rsetiron(r, riron(r) + IRONPERTURN);
if(a_find(r->attribs, &at_laen)) {
rsetlaen(r, rlaen(r) + rand() % MAXLAENPERTURN);
}
} else if (rterrain(r) == T_GLACIER || rterrain(r) == T_ICEBERG_SLEEP) {
2001-01-25 10:37:55 +01:00
rsetiron(r, min(MAXGLIRON, riron(r)+GLIRONPERTURN));
}
#endif
2001-01-25 10:37:55 +01:00
}
#endif /* NEW_RESOURCEGROWTH */
2001-01-25 10:37:55 +01:00
/* ------------------------------------------------------------- */
extern int season(int turn);
2001-01-25 10:37:55 +01:00
void
demographics(void)
{
region *r;
#if GROWING_TREES
int current_season = season(turn);
int last_weeks_season = season(turn-1);
#endif
2001-01-25 10:37:55 +01:00
for (r = regions; r; r = r->next) {
live(r);
/* check_split_dragons(); */
if (rterrain(r) != T_OCEAN) {
/* die Nachfrage nach Produkten steigt. */
#ifdef NEW_ITEMS
struct demand * dmd;
if (r->land) for (dmd=r->land->demands;dmd;dmd=dmd->next) {
if (dmd->value>0 && dmd->value < MAXDEMAND) {
int rise = DMRISE;
if (buildingtype_exists(r, bt_find("harbour"))) rise = DMRISEHAFEN;
2001-01-25 10:37:55 +01:00
if (rand() % 100 < rise) dmd->value++;
}
}
#else
item_t n;
for (n = 0; n != MAXLUXURIES; n++) {
int d = rdemand(r, n);
if (d > 0 && d < MAXDEMAND) {
if (buildingtype_exists(r, &bt_harbour)) {
2001-01-25 10:37:55 +01:00
if (rand() % 100 < DMRISEHAFEN) {
d++;
}
} else {
if (rand() % 100 < DMRISE) {
d++;
}
}
}
rsetdemand(r, n, (char)d);
}
#endif
/* Seuchen erst nachdem die Bauern sich vermehrt haben
* und gewandert sind */
calculate_emigration(r);
peasants(r);
plagues(r, false);
r->age++;
horses(r);
#if GROWING_TREES
if(current_season != SEASON_WINTER) {
trees(r, current_season, last_weeks_season);
}
#else
2001-01-25 10:37:55 +01:00
trees(r);
#endif
#if NEW_RESOURCEGROWTH
update_resources(r);
#else
iron(r);
#endif
2001-01-25 10:37:55 +01:00
migrate(r);
}
}
while (free_migrants) {
migration * m = free_migrants->next;
free(free_migrants);
free_migrants = m;
};
putchar('\n');
remove_empty_units();
puts(" - Einwanderung...");
for (r = regions; r; r = r->next) {
if (landregion(rterrain(r))) {
int rp = rpeasants(r) + r->land->newpeasants;
rsetpeasants(r, max(0, rp));
/* Wenn keine Bauer da ist, soll auch kein Geld da sein */
/* Martin */
if (rpeasants(r) == 0)
rsetmoney(r, 0);
}
}
checkorders();
}
/* ------------------------------------------------------------- */
static int
modify(int i)
{
int c;
c = i * 2 / 3;
if (c >= 1) {
return (c + rand() % c);
} else {
return (i);
}
}
static void
inactivefaction(faction * f)
{
FILE *inactiveFILE;
char zText[128];
2001-01-25 10:37:55 +01:00
sprintf(zText, "%s/%s", datapath(), "/inactive");
inactiveFILE = fopen(zText, "a");
2001-01-25 10:37:55 +01:00
fprintf(inactiveFILE, "%s:%s:%d:%d\n",
factionid(f),
LOC(default_locale, rc_name(f->race, 1)),
2001-01-25 10:37:55 +01:00
modify(count_all(f)),
turn - f->lastorders);
fclose(inactiveFILE);
}
2003-04-24 22:54:14 +02:00
#ifdef ENHANCED_QUIT
static void
transfer_faction(faction *f, faction *f2)
{
unit *u, *un;
for (u = f->units; u;) {
2003-04-27 09:44:05 +02:00
un = u->nextF;
2003-04-24 22:54:14 +02:00
if(!unit_has_cursed_item(u)
&& !has_skill(u, SK_MAGIC)
&& !has_skill(u, SK_ALCHEMY)) {
u_setfaction(u, f2);
}
u = un;
}
}
#endif
static void
2001-01-25 10:37:55 +01:00
quit(void)
{
region *r;
2002-05-12 09:29:28 +02:00
unit *u, *un;
strlist *S;
2001-01-25 10:37:55 +01:00
faction *f;
const race * frace;
2001-01-25 10:37:55 +01:00
/* Sterben erst nachdem man allen anderen gegeben hat - bzw. man kann
* alles machen, was nicht ein drei<EFBFBD>igt<EFBFBD>giger Befehl ist. */
2002-05-12 09:29:28 +02:00
for (r = regions; r; r = r->next) {
for (u = r->units; u;) {
un = u->next;
for (S = u->orders; S; S = S->next) {
if (igetkeyword(S->s, u->faction->locale) == K_QUIT) {
if (checkpasswd(u->faction, getstrtoken(), false)) {
2003-04-24 22:54:14 +02:00
#ifdef ENHANCED_QUIT
int f2_id = getid();
if(f2_id > 0) {
faction *f2 = findfaction(f2_id);
f = u->faction;
if(f2 == NULL) {
cmistake(u, S->s, 66, MSG_EVENT);
} else if(f == f2) {
cmistake(u, S->s, 8, MSG_EVENT);
#ifdef ALLIANCES
} else if(u->faction->alliance != f2->alliance) {
cmistake(u, S->s, 315, MSG_EVENT);
#else
magicskillboost -- implementiert. Kann nur einmal pro Partei verwendet werden, und nur von einem Magier. Müssen wir erklären. Amulett des wahren Sehens und Ring der Unsichtbarkeit geben lediglich einen Bonus auf Wahrnehmung (+2) und Tarnung (+4). -- das define war nicht aktiviert Halblinge haben Armbrustschiessen +0 (statt +1). -- spearates Rassenfile für WDW Es gibt spezielle Regeln für Allianzen, und der HELFE und KONTAKTIERE Befehl sind eingeschränkt. Konkret kann kein HELP_FIGHT HELP_GUARD HELP_FSTEALTH HELP_MONEY gegeben werden (die anderen sind erlaubt). -- mit #defeine ALLIES_ONLY definiert Jede Allianz kann bis zu 15 Magier und 15 Alchemisten haben. Jede einzelne Partei der Allianz kann dabei nicht mehr als 15/Anzahl_Parteien (aufgerundet) Magier bzw. Alchemisten haben, und die Gesamtsumme darf 15 nicht übersteigen. -- mit #define ALLIANCE_LIMITS gemacht. Die Startgeschenke (Personen, Silber, ...) werden pro Allianz, nicht pro Spieler verteilt. Größere Allianzen bekommen also weniger pro Spieler. -- Nochmal geändert: Die Allianzen kriegen jede 168 Personen zum Start, weil sich das gut aufteilen lässt. Das wird auf 28 Einheiten pro Partei gesplittet, jede Einheit hat eines der Talente, außer der Starteinheit, die hat den magicskillboost. Einige Skills kommen öfter vor als andere, das ist nicht einfach vermeidbar. Sollte aber auch wurscht sein, es geht primär darum, lehren zu können. Es gibt ein Einheitenlimit von 1000 Einheiten pro Allianz. -- die Regel sparen wir uns einfach mal.
2003-12-14 22:45:47 +01:00
#error ENHANCED_QUIT defined without ALLIANCES
2003-04-24 22:54:14 +02:00
#endif
2003-04-27 09:44:05 +02:00
} else if(!alliedfaction(NULL, f, f2, HELP_MONEY)) {
2003-04-24 22:54:14 +02:00
cmistake(u, S->s, 316, MSG_EVENT);
} else {
transfer_faction(f,f2);
destroyfaction(f);
}
} else {
destroyfaction(u->faction);
}
#else
2001-01-25 10:37:55 +01:00
destroyfaction(u->faction);
2003-04-24 22:54:14 +02:00
#endif
2002-05-12 09:29:28 +02:00
break;
2001-01-25 10:37:55 +01:00
} else {
cmistake(u, S->s, 86, MSG_EVENT);
log_warning(("STIRB mit falschem Passwort f<>r Partei %s: %s\n",
factionid(u->faction), S->s));
2001-01-25 10:37:55 +01:00
}
} else if(igetkeyword(S->s, u->faction->locale) == K_RESTART && u->number > 0) {
const char *s_race, *s_pass;
2001-01-25 10:37:55 +01:00
if (!landregion(rterrain(r))) {
cmistake(u, S->s, 242, MSG_EVENT);
continue;
}
s_race = getstrtoken();
frace = findrace(s_race, u->faction->locale);
if (!frace) {
frace = u->faction->race;
s_pass = s_race;
} else {
s_pass = getstrtoken();
}
if (frace != u->faction->race && u->faction->age < 81) {
cmistake(u, S->s, 241, MSG_EVENT);
continue;
}
2002-05-12 09:04:39 +02:00
if (u->faction->age > 3 && fval(u->faction, FFL_RESTART)) {
cmistake(u, S->s, 314, MSG_EVENT);
continue;
2001-01-25 10:37:55 +01:00
}
if (!playerrace(frace)) {
2001-01-25 10:37:55 +01:00
cmistake(u, S->s, 243, MSG_EVENT);
continue;
}
if (!checkpasswd(u->faction, s_pass, false)) {
2001-01-25 10:37:55 +01:00
cmistake(u, S->s, 86, MSG_EVENT);
log_warning(("NEUSTART mit falschem Passwort f<>r Partei %s: %s\n",
factionid(u->faction), S->s));
2001-01-25 10:37:55 +01:00
continue;
}
restart(u, frace);
2002-05-12 09:29:28 +02:00
break;
2001-01-25 10:37:55 +01:00
}
2002-05-12 09:29:28 +02:00
}
u = un;
}
}
2001-01-25 10:37:55 +01:00
puts(" - beseitige Spieler, die sich zu lange nicht mehr gemeldet haben...");
remove("inactive");
for (f = factions; f; f = f->next) {
if(fval(f, FFL_NOIDLEOUT)) f->lastorders = turn;
if (NMRTimeout()>0 && turn - f->lastorders >= NMRTimeout()) {
2001-01-25 10:37:55 +01:00
destroyfaction(f);
continue;
}
if (fval(f, FFL_OVERRIDE)) {
free(f->override);
f->override = strdup(itoa36(rand()));
}
if (turn!=f->lastorders) {
char info[256];
sprintf(info, "%d Einheiten, %d Personen, %d Silber",
2002-03-31 10:46:36 +02:00
f->no_units, f->number, f->money);
if (f->subscription) fprintf(sqlstream,
"UPDATE subscriptions SET lastturn=%d, password='%s', info='%s' "
"WHERE id=%u;\n",
f->lastorders, f->override, info, f->subscription);
} else {
if (f->subscription) fprintf(sqlstream,
"UPDATE subscriptions SET status='ACTIVE', lastturn=%d, password='%s' "
"WHERE id=%u;\n",
f->lastorders, f->override, f->subscription);
}
if (NMRTimeout()>0 && turn - f->lastorders >= (NMRTimeout() - 1)) {
2001-01-25 10:37:55 +01:00
inactivefaction(f);
continue;
}
}
puts(" - beseitige Spieler, die sich nach der Anmeldung nicht "
"gemeldet haben...");
2004-01-04 12:28:26 +01:00
age = calloc(max(4,turn+1), sizeof(int));
2002-09-02 22:36:12 +02:00
for (f = factions; f; f = f->next) if (f->no != MONSTER_FACTION) {
if (RemoveNMRNewbie() && !fval(f, FFL_NOIDLEOUT)) {
2002-09-02 22:36:12 +02:00
if (f->age>=0 && f->age <= turn) ++age[f->age];
if (f->age == 2 || f->age == 3) {
if (f->lastorders == turn - 2) {
destroyfaction(f);
++dropouts[f->age-2];
continue;
}
2001-01-25 10:37:55 +01:00
}
}
2002-09-02 22:36:12 +02:00
#if defined(ALLIANCES) && !defined(ALLIANCEJOIN)
if (f->alliance==NULL) {
2004-01-18 21:17:47 +01:00
/* destroyfaction(f); */
2002-09-02 22:36:12 +02:00
continue;
}
#endif
}
2001-01-25 10:37:55 +01:00
/* Clear away debris of destroyed factions */
puts(" - beseitige leere Einheiten und leere Parteien...");
remove_empty_units();
/* Auskommentiert: Wenn factions gel<65>scht werden, zeigen
* Spendenpointer ins Leere. */
/* remove_empty_factions(); */
}
/* ------------------------------------------------------------- */
/* HELFE partei [<ALLES | SILBER | GIB | KAEMPFE | WAHRNEHMUNG>] [NICHT] */
static void
set_ally(unit * u, strlist * S)
{
ally * sf, ** sfp;
faction *f;
int keyword, not_kw;
const char *s;
2001-01-25 10:37:55 +01:00
f = getfaction();
if (f == 0 || f->no == 0) {
cmistake(u, S->s, 66, MSG_EVENT);
return;
}
if (f == u->faction)
return;
s = getstrtoken();
if (!s[0])
keyword = P_ANY;
else
keyword = findparam(s, u->faction->locale);
2001-01-25 10:37:55 +01:00
sfp = &u->faction->allies;
{
attrib * a = a_find(u->attribs, &at_group);
if (a) sfp = &((group*)a->data.v)->allies;
}
for (sf=*sfp; sf; sf = sf->next)
if (sf->faction == f)
break; /* Gleich die passende raussuchen, wenn vorhanden */
not_kw = getparam(u->faction->locale); /* HELFE partei [modus] NICHT */
2001-01-25 10:37:55 +01:00
if (!sf) {
if (keyword == P_NOT || not_kw == P_NOT) {
/* Wir helfen der Partei gar nicht... */
return;
} else {
sf = calloc(1, sizeof(ally));
sf->faction = f;
sf->status = 0;
addlist(sfp, sf);
}
}
switch (keyword) {
case P_NOT:
sf->status = 0;
break;
case NOPARAM:
cmistake(u, S->s, 137, MSG_EVENT);
return;
case P_ANY:
if (not_kw == P_NOT)
sf->status = 0;
else
sf->status = HELP_ALL;
break;
case P_TRAVEL:
if (not_kw == P_NOT)
sf->status = sf->status & (HELP_ALL - HELP_TRAVEL);
else
sf->status = sf->status | HELP_TRAVEL;
break;
case P_GIB:
2001-01-25 10:37:55 +01:00
if (not_kw == P_NOT)
sf->status = sf->status & (HELP_ALL - HELP_GIVE);
else
sf->status = sf->status | HELP_GIVE;
break;
case P_SILVER:
if (not_kw == P_NOT)
sf->status = sf->status & (HELP_ALL - HELP_MONEY);
else
sf->status = sf->status | HELP_MONEY;
break;
case P_KAEMPFE:
if (not_kw == P_NOT)
sf->status = sf->status & (HELP_ALL - HELP_FIGHT);
else
sf->status = sf->status | HELP_FIGHT;
break;
case P_FACTIONSTEALTH:
if (not_kw == P_NOT)
sf->status = sf->status & (HELP_ALL - HELP_FSTEALTH);
else
sf->status = sf->status | HELP_FSTEALTH;
break;
2001-01-25 10:37:55 +01:00
case P_GUARD:
if (not_kw == P_NOT)
sf->status = sf->status & (HELP_ALL - HELP_GUARD);
else
sf->status = sf->status | HELP_GUARD;
break;
}
if (sf->status == 0) { /* Alle HELPs geloescht */
removelist(sfp, sf);
}
}
/* ------------------------------------------------------------- */
static void
2001-01-25 10:37:55 +01:00
set_display(region * r, unit * u, strlist * S)
{
char **s;
const char *s2;
2001-01-25 10:37:55 +01:00
s = 0;
switch (getparam(u->faction->locale)) {
2001-01-25 10:37:55 +01:00
case P_BUILDING:
case P_GEBAEUDE:
if (!u->building) {
cmistake(u, S->s, 145, MSG_PRODUCE);
break;
}
if (!fval(u, UFL_OWNER)) {
2001-01-25 10:37:55 +01:00
cmistake(u, S->s, 5, MSG_PRODUCE);
break;
}
if (u->building->type == bt_find("generic")) {
2001-01-25 10:37:55 +01:00
cmistake(u, S->s, 279, MSG_PRODUCE);
break;
}
if (u->building->type == bt_find("monument") && u->building->display[0] != 0) {
2001-01-25 10:37:55 +01:00
cmistake(u, S->s, 29, MSG_PRODUCE);
break;
}
2004-05-14 12:07:36 +02:00
if (u->building->type == bt_find("artsculpture") && u->building->display[0] != 0) {
cmistake(u, S->s, 29, MSG_PRODUCE);
break;
}
2001-01-25 10:37:55 +01:00
s = &u->building->display;
break;
case P_SHIP:
if (!u->ship) {
cmistake(u, S->s, 144, MSG_PRODUCE);
break;
}
if (!fval(u, UFL_OWNER)) {
2001-01-25 10:37:55 +01:00
cmistake(u, S->s, 12, MSG_PRODUCE);
break;
}
s = &u->ship->display;
break;
case P_UNIT:
s = &u->display;
break;
case P_PRIVAT:
2001-02-13 20:22:48 +01:00
{
const char *d = getstrtoken();
2001-02-13 20:22:48 +01:00
if(d == NULL || *d == 0) {
usetprivate(u, NULL);
} else {
usetprivate(u, d);
}
}
2001-01-25 10:37:55 +01:00
break;
case P_REGION:
if (!u->building) {
cmistake(u, S->s, 145, MSG_EVENT);
break;
}
if (!fval(u, UFL_OWNER)) {
2001-01-25 10:37:55 +01:00
cmistake(u, S->s, 148, MSG_EVENT);
break;
}
if (u->building != largestbuilding(r,false)) {
cmistake(u, S->s, 147, MSG_EVENT);
break;
}
s = &r->display;
break;
default:
cmistake(u, S->s, 110, MSG_EVENT);
break;
}
if (!s)
return;
s2 = getstrtoken();
set_string(&(*s), s2);
}
static void
set_prefix(unit * u, strlist *S)
{
attrib **ap;
attrib *a, *a2;
int i;
const char *s;
s = getstrtoken();
if(!*s) {
a = a_find(u->attribs, &at_group);
if (a) {
a_removeall(&((group*)a->data.v)->attribs, &at_raceprefix);
} else {
a_removeall(&u->faction->attribs, &at_raceprefix);
}
return;
}
for(i=0; race_prefixes[i] != NULL; i++) {
if(strncasecmp(s, LOC(u->faction->locale, race_prefixes[i]), strlen(s)) == 0) {
break;
}
}
if(race_prefixes[i] == NULL) {
cmistake(u, S->s, 299, MSG_EVENT);
return;
}
ap = &u->faction->attribs;
a = a_find(u->attribs, &at_group);
if (a) ap = &((group*)a->data.v)->attribs;
a2 = a_find(*ap, &at_raceprefix);
if(!a2)
a2 = a_add(ap, a_new(&at_raceprefix));
a2->data.v = strdup(race_prefixes[i]);
return;
}
static void
set_synonym(unit * u, strlist *S)
{
attrib *a;
int i;
const char *s;
a = a_find(u->faction->attribs, &at_synonym);
if(a) { /* Kann nur einmal gesetzt werden */
cmistake(u, S->s, 302, MSG_EVENT);
return;
}
s = getstrtoken();
if(!s) {
cmistake(u, S->s, 301, MSG_EVENT);
return;
}
for(i=0; race_synonyms[i].race != -1; i++) {
if (new_race[race_synonyms[i].race] == u->faction->race
&& strcasecmp(s, race_synonyms[i].synonyms[0]) == 0) {
break;
}
}
if(race_synonyms[i].race == -1) {
cmistake(u, S->s, 300, MSG_EVENT);
return;
}
a = a_add(&u->faction->attribs, a_new(&at_synonym));
((frace_synonyms *)(a->data.v))->synonyms[0] =
strdup(race_synonyms[i].synonyms[0]);
((frace_synonyms *)(a->data.v))->synonyms[1] =
strdup(race_synonyms[i].synonyms[1]);
((frace_synonyms *)(a->data.v))->synonyms[2] =
strdup(race_synonyms[i].synonyms[2]);
((frace_synonyms *)(a->data.v))->synonyms[3] =
strdup(race_synonyms[i].synonyms[3]);
return;
}
static void
2001-01-25 10:37:55 +01:00
set_group(unit * u)
{
const char * s = getstrtoken();
2001-01-25 10:37:55 +01:00
join_group(u, s);
}
static void
2001-01-25 10:37:55 +01:00
set_name(region * r, unit * u, strlist * S)
{
char **s;
const char *s2;
2001-01-25 10:37:55 +01:00
int i;
param_t p;
boolean foreign = false;
s = 0;
p = getparam(u->faction->locale);
2001-01-25 10:37:55 +01:00
if(p == P_FOREIGN) {
foreign = true;
p = getparam(u->faction->locale);
2001-01-25 10:37:55 +01:00
}
switch (p) {
case P_BUILDING:
case P_GEBAEUDE:
if (foreign == true) {
building *b = getbuilding(r);
unit *uo;
if (!b) {
cmistake(u, S->s, 6, MSG_EVENT);
break;
}
if (b->type == bt_find("generic")) {
2001-01-25 10:37:55 +01:00
cmistake(u, S->s, 278, MSG_EVENT);
break;
}
if(!fval(b,FL_UNNAMED)) {
cmistake(u, S->s, 246, MSG_EVENT);
break;
}
uo = buildingowner(r, b);
if (uo) {
if (cansee(uo->faction, r, u, 0)) {
add_message(&uo->faction->msgs, new_message(uo->faction,
"renamed_building_seen%b:building%u:renamer%r:region", b, u, r));
} else {
add_message(&uo->faction->msgs, new_message(uo->faction,
"renamed_building_notseen%b:building%r:region", b, r));
}
}
s = &b->name;
} else {
if (!u->building) {
cmistake(u, S->s, 145, MSG_PRODUCE);
break;
}
if (!fval(u, UFL_OWNER)) {
2001-01-25 10:37:55 +01:00
cmistake(u, S->s, 148, MSG_PRODUCE);
break;
}
if (u->building->type == bt_find("generic")) {
2001-01-25 10:37:55 +01:00
cmistake(u, S->s, 278, MSG_EVENT);
break;
}
sprintf(buf, "Monument %d", u->building->no);
if (u->building->type == bt_find("monument")
2001-01-28 10:47:10 +01:00
&& !strcmp(u->building->name, buf)) {
2001-01-25 10:37:55 +01:00
cmistake(u, S->s, 29, MSG_EVENT);
break;
}
2004-05-14 12:07:36 +02:00
if (u->building->type == bt_find("artsculpure")) {
cmistake(u, S->s, 29, MSG_EVENT);
break;
}
2001-01-25 10:37:55 +01:00
s = &u->building->name;
freset(u->building, FL_UNNAMED);
}
break;
case P_FACTION:
if (foreign == true) {
faction *f;
f = getfaction();
if (!f) {
cmistake(u, S->s, 66, MSG_EVENT);
break;
}
if (f->age < 10) {
cmistake(u, S->s, 248, MSG_EVENT);
break;
}
if (!fval(f,FL_UNNAMED)) {
cmistake(u, S->s, 247, MSG_EVENT);
break;
}
if (cansee(f, r, u, 0)) {
add_message(&f->msgs, new_message(f,
"renamed_faction_seen%u:renamer%r:region", u, r));
} else {
add_message(&f->msgs, new_message(f,
"renamed_faction_notseen%r:region", r));
}
s = &f->name;
} else {
s = &u->faction->name;
freset(u->faction, FL_UNNAMED);
}
break;
case P_SHIP:
if (foreign == true) {
ship *sh = getship(r);
unit *uo;
if (!sh) {
cmistake(u, S->s, 20, MSG_EVENT);
break;
}
if (!fval(sh,FL_UNNAMED)) {
cmistake(u, S->s, 245, MSG_EVENT);
break;
}
uo = shipowner(r,sh);
if (uo) {
if (cansee(uo->faction, r, u, 0)) {
add_message(&uo->faction->msgs, new_message(uo->faction,
"renamed_ship_seen%h:ship%u:renamer%r:region", sh, u, r));
} else {
add_message(&uo->faction->msgs, new_message(uo->faction,
"renamed_ship_notseen%h:ship%r:region", sh, r));
}
}
s = &sh->name;
} else {
if (!u->ship) {
cmistake(u, S->s, 144, MSG_PRODUCE);
break;
}
if (!fval(u, UFL_OWNER)) {
2001-01-25 10:37:55 +01:00
cmistake(u, S->s, 12, MSG_PRODUCE);
break;
}
s = &u->ship->name;
freset(u->ship, FL_UNNAMED);
}
break;
case P_UNIT:
if (foreign == true) {
2001-04-26 19:41:06 +02:00
unit *u2 = getunit(r, u->faction);
2001-01-25 10:37:55 +01:00
if (!u2 || !cansee(u->faction, r, u2, 0)) {
cmistake(u, S->s, 63, MSG_EVENT);
2001-01-25 10:37:55 +01:00
break;
}
if (!fval(u,FL_UNNAMED)) {
cmistake(u, S->s, 244, MSG_EVENT);
2001-01-25 10:37:55 +01:00
break;
}
if (cansee(u2->faction, r, u, 0)) {
add_message(&u2->faction->msgs, new_message(u2->faction,
"renamed_seen%u:renamer%u:renamed%r:region", u, u2, r));
} else {
add_message(&u2->faction->msgs, new_message(u2->faction,
"renamed_notseen%u:renamed%r:region", u2, r));
}
s = &u2->name;
} else {
s = &u->name;
freset(u, FL_UNNAMED);
}
break;
case P_REGION:
if (!u->building) {
cmistake(u, S->s, 145, MSG_EVENT);
break;
}
if (!fval(u, UFL_OWNER)) {
2001-01-25 10:37:55 +01:00
cmistake(u, S->s, 148, MSG_EVENT);
break;
}
if (u->building != largestbuilding(r,false)) {
cmistake(u, S->s, 147, MSG_EVENT);
break;
}
s = &r->land->name;
break;
case P_GROUP:
{
attrib * a = a_find(u->attribs, &at_group);
if (a){
group * g = (group*)a->data.v;
s= &g->name;
break;
} else {
cmistake(u, S->s, 109, MSG_EVENT);
break;
}
}
break;
2001-01-25 10:37:55 +01:00
default:
cmistake(u, S->s, 109, MSG_EVENT);
break;
}
if (!s)
return;
s2 = getstrtoken();
if (!s2[0]) {
cmistake(u, S->s, 84, MSG_EVENT);
return;
}
for (i = 0; s2[i]; i++)
if (s2[i] == '(')
break;
if (s2[i]) {
cmistake(u, S->s, 112, MSG_EVENT);
return;
}
set_string(&(*s), s2);
}
/* ------------------------------------------------------------- */
static void
deliverMail(faction * f, region * r, unit * u, const char *s, unit * receiver)
{
if (!receiver) { /* BOTSCHAFT an PARTEI */
char * message = (char*)gc_add(strdup(s));
add_message(&f->msgs,
msg_message("unitmessage", "region unit string", r, u, message));
2001-01-25 10:37:55 +01:00
}
else { /* BOTSCHAFT an EINHEIT */
unit *emp = receiver;
if (cansee(f, r, u, 0))
sprintf(buf, "Eine Botschaft von %s: '%s'", unitname(u), s);
2001-01-25 10:37:55 +01:00
else
sprintf(buf, "Eine anonyme Botschaft: '%s'", s);
addstrlist(&emp->botschaften, strdup(buf));
2001-01-25 10:37:55 +01:00
}
}
static void
mailunit(region * r, unit * u, int n, strlist * S, const char * s)
{
unit *u2; /* nur noch an eine Unit m<>glich */
u2=findunitr(r,n);
if (u2 && cansee(u->faction, r, u2, 0)) {
deliverMail(u2->faction, r, u, s, u2);
}
else
cmistake(u, S->s, 63, MSG_MESSAGE);
2001-01-25 10:37:55 +01:00
/* Immer eine Meldung - sonst k<>nnte man so getarnte EHs enttarnen:
* keine Meldung -> EH hier. */
}
static void
mailfaction(unit * u, int n, strlist * S, const char * s)
{
faction *f;
f = findfaction(n);
if (f && n>0)
deliverMail(f, u->region, u, s, NULL);
else
cmistake(u, S->s, 66, MSG_MESSAGE);
}
static void
2001-01-25 10:37:55 +01:00
distributeMail(region * r, unit * u, strlist * S)
{
unit *u2;
const char *s;
2001-01-25 10:37:55 +01:00
int n;
s = getstrtoken();
/* Falls kein Parameter, ist das eine Einheitsnummer;
* das F<EFBFBD>llwort "AN" mu<EFBFBD> wegfallen, da g<EFBFBD>ltige Nummer! */
if(strcasecmp(s, "an") == 0)
s = getstrtoken();
switch (findparam(s, u->faction->locale)) {
2001-01-25 10:37:55 +01:00
case P_REGION: /* k<>nnen alle Einheiten in der Region sehen */
s = getstrtoken();
if (!s[0]) {
cmistake(u, S->s, 30, MSG_MESSAGE);
return;
} else {
sprintf(buf, "von %s: '%s'", unitname(u), s);
addmessage(r, 0, buf, MSG_MESSAGE, ML_IMPORTANT);
return;
}
break;
case P_FACTION:
{
boolean see = false;
n = getfactionid();
for(u2=r->units; u2; u2=u2->next) {
if(u2->faction->no == n && seefaction(u->faction, r, u2, 0)) {
see = true;
break;
}
}
if(see == false) {
cmistake(u, S->s, 66, MSG_MESSAGE);
return;
}
s = getstrtoken();
if (!s[0]) {
cmistake(u, S->s, 30, MSG_MESSAGE);
return;
}
mailfaction(u, n, S, s);
}
break;
case P_UNIT:
{
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) {
cmistake(u, S->s, 63, MSG_MESSAGE);
2001-01-25 10:37:55 +01:00
return;
}
s = getstrtoken();
if (!s[0]) {
cmistake(u, S->s, 30, MSG_MESSAGE);
return;
}
mailunit(r, u, n, S, s);
}
break;
case P_BUILDING:
case P_GEBAEUDE:
{
building *b = getbuilding(r);
if(!b) {
cmistake(u, S->s, 6, MSG_MESSAGE);
return;
}
s = getstrtoken();
if (!s[0]) {
cmistake(u, S->s, 30, MSG_MESSAGE);
return;
}
for (u2 = r->units; u2; u2 = u2->next) freset(u2->faction, FL_DH);
for(u2=r->units; u2; u2=u2->next) {
if(u2->building == b && !fval(u2->faction, FL_DH)
&& cansee(u->faction, r, u2, 0)) {
mailunit(r, u, u2->no, S, s);
fset(u2->faction, FL_DH);
}
}
}
break;
case P_SHIP:
{
ship *sh = getship(r);
if(!sh) {
cmistake(u, S->s, 20, MSG_MESSAGE);
return;
}
s = getstrtoken();
if (!s[0]) {
cmistake(u, S->s, 30, MSG_MESSAGE);
return;
}
for (u2 = r->units; u2; u2 = u2->next) freset(u2->faction, FL_DH);
for(u2=r->units; u2; u2=u2->next) {
if(u2->ship == sh && !fval(u2->faction, FL_DH)
&& cansee(u->faction, r, u2, 0)) {
mailunit(r, u, u2->no, S, s);
fset(u2->faction, FL_DH);
}
}
}
break;
default:
cmistake(u, S->s, 149, MSG_MESSAGE);
return;
}
}
static void
2001-01-25 10:37:55 +01:00
mail(void)
{
region *r;
unit *u;
strlist *S;
puts(" - verschicke Botschaften...");
for (r = regions; r; r = r->next)
for (u = r->units; u; u = u->next)
for (S = u->orders; S; S = S->next)
if (igetkeyword(S->s, u->faction->locale) == K_MAIL)
2001-01-25 10:37:55 +01:00
distributeMail(r, u, S);
}
/* ------------------------------------------------------------- */
static void
2001-01-25 10:37:55 +01:00
report_option(unit * u, const char * sec, char *cmd)
{
const messageclass * mc;
const char *s;
mc = mc_find(sec);
if (mc == NULL) {
cmistake(u, findorder(u, cmd), 135, MSG_EVENT);
return;
}
s = getstrtoken();
#ifdef MSG_LEVELS
if (s[0])
2001-01-25 10:37:55 +01:00
set_msglevel(&u->faction->warnings, mc->name, atoi(s));
else
set_msglevel(&u->faction->warnings, mc->name, -1);
#endif
2001-01-25 10:37:55 +01:00
}
static void
2001-01-25 10:37:55 +01:00
set_passw(void)
{
region *r;
unit *u;
strlist *S;
const char *s;
2001-01-25 10:37:55 +01:00
int o, i;
magic_t mtyp;
puts(" - setze Passw<73>rter, Adressen und Format, Abstimmungen");
for (r = regions; r; r = r->next)
for (u = r->units; u; u = u->next)
for (S = u->orders; S; S = S->next) {
switch (igetkeyword(S->s, u->faction->locale)) {
2001-01-25 10:37:55 +01:00
case NOKEYWORD:
cmistake(u, S->s, 22, MSG_EVENT);
break;
case K_BANNER:
s = getstrtoken();
set_string(&u->faction->banner, s);
add_message(&u->faction->msgs, new_message(u->faction,
"changebanner%s:value", gc_add(strdup(u->faction->banner))));
break;
case K_EMAIL:
s = getstrtoken();
if (!s[0]) {
cmistake(u, S->s, 85, MSG_EVENT);
break;
}
if (strstr(s, "internet:") || strchr(s, ' ')) {
cmistake(u, S->s, 117, MSG_EVENT);
break;
}
set_string(&u->faction->email, s);
add_message(&u->faction->msgs, new_message(u->faction,
"changemail%s:value", gc_add(strdup(u->faction->email))));
break;
case K_PASSWORD:
{
char pbuf[32];
int i;
2001-01-25 10:37:55 +01:00
s = getstrtoken();
if (!s || !*s) {
for(i=0; i<6; i++) pbuf[i] = (char)(97 + rand() % 26);
pbuf[6] = 0;
} else {
boolean pwok = true;
char *c;
strncpy(pbuf, s, 31);
pbuf[31] = 0;
c = pbuf;
while(*c) {
if(!isalnum(*c)) pwok = false;
c++;
}
if (pwok == false) {
cmistake(u, S->s, 283, MSG_EVENT);
for(i=0; i<6; i++) pbuf[i] = (char)(97 + rand() % 26);
pbuf[6] = 0;
}
}
set_string(&u->faction->passw, pbuf);
2002-03-31 16:08:33 +02:00
fset(u->faction, FFL_OVERRIDE);
2002-04-20 14:41:49 +02:00
ADDMSG(&u->faction->msgs, msg_message("changepasswd",
"value", gc_add(strdup(u->faction->passw))));
2001-01-25 10:37:55 +01:00
}
break;
case K_REPORT:
s = getstrtoken();
i = atoi(s);
sprintf(buf, "%d", i);
if (!strcmp(buf, s)) {
/* int level;
level = geti();
not implemented yet. set individual levels for f->msglevels */
} else {
report_option(u, s, S->s);
}
break;
case K_SEND:
s = getstrtoken();
o = findoption(s, u->faction->locale);
#ifdef AT_OPTION
/* Sonderbehandlung Zeitungsoption */
if (o == O_NEWS) {
attrib *a = a_find(u->faction->attribs, &at_option_news);
if(a) a->data.i = 0;
while((s = getstrtoken())) {
if(findparam(s) == P_NOT) {
a_removeall(&u->faction->attribs, &at_option_news);
2001-02-28 19:31:49 +01:00
u->faction->options = u->faction->options & ~O_NEWS;
break;
} else {
int sec = atoi(s);
if(sec != 0) {
if(!a) a_add(&u->faction->attribs, a_new(&at_option_news));
a->data.i = a->data.i & (1<<(sec-1));
2001-02-28 19:31:49 +01:00
u->faction->options = u->faction->options | O_NEWS;
}
}
}
break;
}
#endif
2001-01-25 10:37:55 +01:00
if (o == -1) {
cmistake(u, S->s, 135, MSG_EVENT);
} else {
if (getparam(u->faction->locale) == P_NOT) {
2002-02-04 19:11:12 +01:00
if(o == O_COMPRESS || o == O_BZIP2) {
cmistake(u, S->s, 305, MSG_EVENT);
} else {
2002-02-04 19:11:12 +01:00
u->faction->options = u->faction->options & ~((int)pow(2, o));
}
2001-01-25 10:37:55 +01:00
} else {
2002-02-04 19:11:12 +01:00
u->faction->options = u->faction->options | ((int)pow(2,o));
if(o == O_COMPRESS) u->faction->options &= ~((int)pow(2,O_BZIP2));
if(o == O_BZIP2) u->faction->options &= ~((int)pow(2,O_COMPRESS));
2001-01-25 10:37:55 +01:00
}
}
break;
case K_MAGIEGEBIET:
if(u->faction->magiegebiet != 0) {
add_message(&u->faction->msgs,
msg_error(u, S->s, "one_circle_only", ""));
2001-01-25 10:37:55 +01:00
} else {
mtyp = getmagicskill();
if(mtyp == M_NONE) {
mistake(u, S->s, "Syntax: MAGIEGEBIET <Gebiet>", MSG_EVENT);
} else {
region *r2;
unit *u2;
sc_mage *m;
region *last = lastregion(u->faction);
u->faction->magiegebiet = mtyp;
2002-02-03 13:56:15 +01:00
for (r2 = firstregion(u->faction); r2 != last; r2 = r2->next) {
for (u2 = r->units; u2; u2 = u2->next) {
2001-01-25 10:37:55 +01:00
if(u2->faction == u->faction
2002-03-03 19:13:08 +01:00
&& has_skill(u2, SK_MAGIC)) {
2001-01-25 10:37:55 +01:00
m = get_mage(u2);
m->magietyp = mtyp;
}
}
}
}
}
break;
}
}
}
static boolean
2001-01-25 10:37:55 +01:00
display_item(faction *f, unit *u, const item_type * itype)
{
FILE *fp;
char t[NAMESIZE + 1];
char filename[MAX_PATH];
const char *name;
2001-01-25 10:37:55 +01:00
if (u && *i_find(&u->items, itype) == NULL) return false;
/*
info = mkname("info", itype->rtype->_name[0]);
name = LOC(u->faction->locale, info);
if (strcmp(name, info)==0) {
*/
name = resourcename(itype->rtype, 0);
sprintf(filename, "%s/%s/items/%s", resourcepath(), locale_name(f->locale), name);
fp = fopen(filename, "r");
if (!fp) {
name = locale_string(f->locale, resourcename(itype->rtype, 0));
sprintf(filename, "%s/%s/items/%s", resourcepath(), locale_name(f->locale), name);
fp = fopen(filename, "r");
}
if (!fp) {
name = resourcename(itype->rtype, 0);
2003-09-21 09:48:40 +02:00
sprintf(filename, "%s/%s/items/%s", resourcepath(), locale_name(default_locale), name);
fp = fopen(filename, "r");
}
if (!fp) return false;
2001-01-25 10:37:55 +01:00
buf[0]='\0';
while (fgets(t, NAMESIZE, fp) != NULL) {
if (t[strlen(t) - 1] == '\n') {
t[strlen(t) - 1] = 0;
}
strcat(buf, t);
2001-01-25 10:37:55 +01:00
}
fclose(fp);
name = buf;
/* } */
2002-01-28 03:23:57 +01:00
ADDMSG(&f->msgs, msg_message("displayitem", "item description", itype->rtype, strdup(name)));
2001-01-25 10:37:55 +01:00
return true;
}
static boolean
2001-01-25 10:37:55 +01:00
display_potion(faction *f, unit *u, const potion_type * ptype)
{
attrib *a;
if (ptype==NULL) return false;
else {
int i = i_get(u->items, ptype->itype);
if (i==0 && 2*ptype->level > effskill(u,SK_ALCHEMY)) {
return false;
}
}
2001-01-25 10:37:55 +01:00
a = a_find(f->attribs, &at_showitem);
while (a && a->data.v != ptype) a=a->next;
if (!a) {
a = a_add(&f->attribs, a_new(&at_showitem));
a->data.v = (void*) ptype->itype;
}
return true;
}
static boolean
display_race(faction *f, unit *u, const race * rc)
2001-01-25 10:37:55 +01:00
{
FILE *fp;
char t[NAMESIZE + 1];
char filename[256];
const char *name;
int a, at_count;
char buf2[2048];
if (u && u->race != rc) return false;
name = rc_name(rc, 0);
2001-01-25 10:37:55 +01:00
sprintf(buf, "%s: ", LOC(f->locale, name));
2001-01-25 10:37:55 +01:00
sprintf(filename, "showdata/%s", LOC(default_locale, name));
2001-01-25 10:37:55 +01:00
fp = fopen(filename, "r");
if(fp) {
while (fgets(t, NAMESIZE, fp) != NULL) {
if (t[strlen(t) - 1] == '\n') {
t[strlen(t) - 1] = 0;
}
strcat(buf, t);
}
fclose(fp);
strcat(buf, ". ");
}
2001-01-25 10:37:55 +01:00
/* hp_p : Trefferpunkte */
sprintf(buf2, "Trefferpunkte: %d", rc->hitpoints);
strcat(buf, buf2);
/* b_armor : R<>stung */
if (rc->armor > 0){
sprintf(buf2, ", R<>stung: %d", rc->armor);
strcat(buf, buf2);
}
/* b_attacke : Angriff */
sprintf(buf2, ", Angriff: %d", (rc->at_default+rc->at_bonus));
strcat(buf, buf2);
2001-01-25 10:37:55 +01:00
/* b_defense : Verteidigung */
sprintf(buf2, ", Verteidigung: %d", (rc->df_default+rc->df_bonus));
strcat(buf, buf2);
strcat(buf, ".");
/* b_damage : Schaden */
at_count=0;
for (a = 0; a < 6; a++) {
if (rc->attack[a].type != AT_NONE){
at_count++;
2001-01-25 10:37:55 +01:00
}
}
2002-04-14 12:11:01 +02:00
if (rc->battle_flags & BF_EQUIPMENT) {
strcat(buf, " Kann Waffen benutzen.");
}
2002-04-14 12:11:01 +02:00
if (rc->battle_flags & BF_RES_PIERCE) {
strcat(buf, " Ist durch Stichwaffen, B<>gen und Armbr<62>ste schwer zu verwunden.");
}
if (rc->battle_flags & BF_RES_CUT) {
strcat(buf, " Ist durch Hiebwaffen schwer zu verwunden.");
}
if (rc->battle_flags & BF_RES_BASH) {
strcat(buf, " Ist durch Schlagwaffen und Katapulte schwer zu verwunden.");
}
sprintf(buf2, " Hat %d Angriff%s", at_count, (at_count>1)?"e":"");
strcat(buf, buf2);
for (a = 0; a < 6; a++) {
if (rc->attack[a].type != AT_NONE){
if (a!=0){
strcat(buf, ", ");
} else {
strcat(buf, ": ");
}
switch(rc->attack[a].type) {
case AT_STANDARD:
sprintf(buf2, "ein Angriff mit der Waffe oder macht unbewaffnet %s Schaden", rc->def_damage);
break;
case AT_NATURAL:
sprintf(buf2, "ein Angriff mit Krallen, Z<>hnen oder Klauen, der %s Schaden macht", rc->attack[a].data.dice);
break;
case AT_SPELL:
case AT_COMBATSPELL:
case AT_DRAIN_ST:
case AT_DAZZLE:
sprintf(buf2, "ein magischer Angriff");
break;
case AT_STRUCTURAL:
sprintf(buf2, "ein Angriff, der %s Geb<65>udeschaden verursacht", rc->attack[a].data.dice);
}
strcat(buf, buf2);
}
}
strcat(buf, ".");
2001-01-25 10:37:55 +01:00
addmessage(0, f, buf, MSG_EVENT, ML_IMPORTANT);
return true;
}
static void
reshow(unit * u, const char* cmd, const char * s, param_t p)
{
int skill, c;
const potion_type * ptype;
const item_type * itype;
const spell * sp;
const race * rc;
switch (p) {
case P_ZAUBER:
a_removeall(&u->faction->attribs, &at_seenspell);
break;
case P_POTIONS:
skill = effskill(u, SK_ALCHEMY);
c = 0;
for (ptype = potiontypes; ptype!=NULL; ptype=ptype->next) {
if (ptype->level * 2 <= skill) {
c += display_potion(u->faction, u, ptype);
}
}
if (c == 0) cmistake(u, cmd, 285, MSG_EVENT);
break;
case NOPARAM:
/* check if it's an item */
itype = finditemtype(s, u->faction->locale);
if (itype!=NULL) {
ptype = resource2potion(item2resource(itype));
if (ptype!=NULL) {
if (display_potion(u->faction, u, ptype)) break;
} else {
if (display_item(u->faction, u, itype)) break;
}
}
/* try for a spell */
sp = find_spellbyname(u, s, u->faction->locale);
if (sp!=NULL && has_spell(u, sp)) {
attrib *a = a_find(u->faction->attribs, &at_seenspell);
while (a!=NULL && a->data.i!=sp->id) a = a->nexttype;
if (a!=NULL) a_remove(&u->faction->attribs, a);
break;
}
/* last, check if it's a race. */
rc = findrace(s, u->faction->locale);
if (rc != NULL) {
if (display_race(u->faction, u, rc)) break;
}
cmistake(u, cmd, 21, MSG_EVENT);
break;
default:
cmistake(u, cmd, 222, MSG_EVENT);
break;
}
}
static void
2001-01-25 10:37:55 +01:00
instant_orders(void)
{
region *r;
unit *u;
strlist *S;
const char *s;
const char *param;
2001-01-25 10:37:55 +01:00
spell *spell;
faction *f;
attrib *a;
int level = 0; /* 0 = MAX */
puts(" - Kontakte, Hilfe, Status, Kampfzauber, Texte, Bewachen (aus), Zeigen");
for (f = factions; f; f = f->next) {
#ifdef NEW_ITEMS
a=a_find(f->attribs, &at_showitem);
while(a!=NULL) {
const item_type * itype = (const item_type *)a->data.v;
const potion_type * ptype = resource2potion(itype->rtype);
if (ptype!=NULL) {
attrib * n = a->nexttype;
/* potions werden separat behandelt */
display_item(f, NULL, (const item_type *)a->data.v);
a_remove(&f->attribs, a);
a = n;
} else a = a->nexttype;
}
#else
while((a=a_find(f->attribs, &at_show_item_description))!=NULL) {
display_item(f, NULL, (item_t)(a->data.i));
a_remove(&f->attribs, a);
}
#endif
}
for (r = regions; r; r = r->next)
for (u = r->units; u; u = u->next) {
for (S = u->orders; S; S = S->next)
{
if (igetkeyword(S->s, u->faction->locale)==K_GROUP) {
2001-01-25 10:37:55 +01:00
set_group(u);
}
}
for (S = u->orders; S; S = S->next)
switch (igetkeyword(S->s, u->faction->locale)) {
2001-01-25 10:37:55 +01:00
case K_URSPRUNG:
{
int px, py;
px = atoi(getstrtoken());
py = atoi(getstrtoken());
set_ursprung(u->faction, getplaneid(r), px, py);
}
break;
case K_ALLY:
set_ally(u, S);
break;
case K_PREFIX:
set_prefix(u, S);
break;
case K_SYNONYM:
set_synonym(u, S);
break;
2001-01-25 10:37:55 +01:00
case K_SETSTEALTH:
setstealth(u, S);
break;
2002-04-12 14:46:16 +02:00
case K_WEREWOLF:
setwere(u, S);
break;
2001-01-25 10:37:55 +01:00
case K_STATUS:
param = getstrtoken();
switch (findparam(param, u->faction->locale)) {
2001-01-25 10:37:55 +01:00
case P_NOT:
u->status = ST_AVOID;
break;
case P_BEHIND:
u->status = ST_BEHIND;
break;
case P_FLEE:
u->status = ST_FLEE;
break;
case P_CHICKEN:
u->status = ST_CHICKEN;
break;
case P_AGGRO:
u->status = ST_AGGRO;
break;
2001-01-25 10:37:55 +01:00
case P_VORNE:
u->status = ST_FIGHT;
break;
2001-01-25 10:37:55 +01:00
case P_HELP:
param = getstrtoken();
if( findparam(param, u->faction->locale) == P_NOT) {
fset(u, UFL_NOAID);
} else {
freset(u, UFL_NOAID);
2001-01-25 10:37:55 +01:00
}
break;
default:
if (strlen(param)) {
add_message(&u->faction->msgs,
msg_error(u, S->s, "unknown_status", ""));
2001-01-25 10:37:55 +01:00
} else {
u->status = ST_FIGHT;
}
}
break;
/* KAMPFZAUBER [[STUFE n] "<Spruchname>"] [NICHT] */
case K_COMBAT:
s = getstrtoken();
/* KAMPFZAUBER [NICHT] l<>scht alle gesetzten Kampfzauber */
if (!s || *s == 0 || findparam(s, u->faction->locale) == P_NOT) {
2001-01-25 10:37:55 +01:00
unset_combatspell(u, 0);
break;
}
/* Optional: STUFE n */
if (findparam(s, u->faction->locale) == P_LEVEL) {
2001-01-25 10:37:55 +01:00
/* Merken, setzen kommt erst sp<73>ter */
s = getstrtoken();
level = atoi(s);
level = max(0, level);
s = getstrtoken();
}
else level = 0;
2001-01-25 10:37:55 +01:00
spell = find_spellbyname(u, s, u->faction->locale);
2001-01-25 10:37:55 +01:00
if(!spell){
cmistake(u, S->s, 173, MSG_MAGIC);
2001-01-25 10:37:55 +01:00
break;
}
/* KAMPFZAUBER "<Spruchname>" NICHT l<>scht diesen speziellen
* Kampfzauber */
s = getstrtoken();
if(findparam(s, u->faction->locale) == P_NOT){
2001-01-25 10:37:55 +01:00
unset_combatspell(u,spell);
break;
}
/* KAMPFZAUBER "<Spruchname>" setzt diesen Kampfzauber */
set_combatspell(u,spell, S->s, level);
break;
case K_DISPLAY:
set_display(r, u, S);
break;
case K_NAME:
set_name(r, u, S);
break;
case K_GUARD:
if (u->faction->age < IMMUN_GEGEN_ANGRIFF) {
cmistake(u, S->s, 304, MSG_EVENT);
break;
}
if (fval(u, UFL_HUNGER)) {
2001-01-25 10:37:55 +01:00
cmistake(u, S->s, 223, MSG_EVENT);
break;
}
if (getparam(u->faction->locale) == P_NOT)
2001-01-25 10:37:55 +01:00
setguard(u, GUARD_NONE);
break;
case K_RESHOW:
s = getstrtoken();
if (findparam(s, u->faction->locale) == P_ANY) {
param_t p = getparam(u->faction->locale);
reshow(u, S->s, s, p);
2001-01-25 10:37:55 +01:00
}
else reshow(u, S->s, s, NOPARAM);
2001-01-25 10:37:55 +01:00
break;
}
}
}
/* ------------------------------------------------------------- */
/* Beachten: einige Monster sollen auch unbewaffent die Region bewachen
* k<EFBFBD>nnen */
void
remove_unequipped_guarded(void)
{
region *r;
unit *u;
for (r = regions; r; r = r->next)
for (u = r->units; u; u = u->next) {
if (getguard(u) && (!armedmen(u) || u->faction->age < IMMUN_GEGEN_ANGRIFF))
2001-01-25 10:37:55 +01:00
setguard(u, GUARD_NONE);
}
}
static void
2001-01-25 10:37:55 +01:00
bewache_an(void)
{
region *r;
unit *u;
strlist *S;
/* letzte schnellen befehle - bewache */
for (r = regions; r; r = r->next) {
for (u = r->units; u; u = u->next) {
if (!fval(u, UFL_MOVED)) {
2001-01-25 10:37:55 +01:00
for (S = u->orders; S; S = S->next) {
if (igetkeyword(S->s, u->faction->locale) == K_GUARD && getparam(u->faction->locale) != P_NOT) {
2001-01-25 10:37:55 +01:00
if (rterrain(r) != T_OCEAN) {
if (!fval(u, RCF_ILLUSIONARY) && u->race != new_race[RC_SPELL]) {
2001-01-25 10:37:55 +01:00
#ifdef WACH_WAFF
/* Monster der Monsterpartei d<>rfen immer bewachen */
if (u->faction == findfaction(MONSTER_FACTION)){
guard(u, GUARD_ALL);
continue;
}
2001-01-25 10:37:55 +01:00
if (!armedmen(u)) {
add_message(&u->faction->msgs,
msg_error(u, S->s, "unit_unarmed", ""));
2001-01-25 10:37:55 +01:00
continue;
}
#endif
guard(u, GUARD_ALL);
} else {
cmistake(u, S->s, 95, MSG_EVENT);
}
} else {
cmistake(u, S->s, 2, MSG_EVENT);
}
}
}
}
}
}
2001-01-25 10:37:55 +01:00
}
static void
2001-01-25 10:37:55 +01:00
sinkships(void)
{
region *r;
/* Unbemannte Schiffe k<>nnen sinken */
for (r = regions; r; r = r->next) {
ship *sh;
list_foreach(ship, r->ships, sh) {
if (rterrain(r) == T_OCEAN && (!enoughsailors(r, sh) || !kapitaen(r, sh))) {
/* Schiff nicht seet<65>chtig */
damage_ship(sh, 0.30);
}
if (!shipowner(r, sh)) {
damage_ship(sh, 0.05);
}
if (sh->damage >= sh->size * DAMAGE_SCALE)
destroy_ship(sh);
2001-01-25 10:37:55 +01:00
}
list_next(sh);
}
}
/* The following functions do not really belong here: */
#include "eressea.h"
#include "build.h"
static attrib_type at_number = {
"faction_renum",
2001-01-25 10:37:55 +01:00
NULL, NULL, NULL, NULL, NULL,
ATF_UNIQUE
};
static void
renumber_factions(void)
/* gibt parteien neue nummern */
{
struct renum {
struct renum * next;
int want;
faction * faction;
attrib * attrib;
} * renum = NULL, * rp;
faction * f;
for (f=factions;f;f=f->next) {
attrib * a = a_find(f->attribs, &at_number);
int want;
struct renum ** rn;
faction * old;
if (!a) continue;
want = a->data.i;
if (fval(f, FF_NEWID)) {
sprintf(buf, "NUMMER PARTEI %s: Die Partei kann nicht mehr als einmal ihre Nummer wecheln", itoa36(want));
addmessage(0, f, buf, MSG_MESSAGE, ML_IMPORTANT);
}
old = findfaction(want);
if (old) {
a_remove(&f->attribs, a);
sprintf(buf, "Die Nummer %s wird von einer anderen Partei benutzt.", itoa36(want));
addmessage(0, f, buf, MSG_MESSAGE, ML_IMPORTANT);
continue;
}
if (!faction_id_is_unused(want)) {
a_remove(&f->attribs, a);
sprintf(buf, "Die Nummer %s wurde schon einmal von einer anderen Partei benutzt.", itoa36(want));
addmessage(0, f, buf, MSG_MESSAGE, ML_IMPORTANT);
continue;
}
for (rn=&renum; *rn; rn=&(*rn)->next) {
if ((*rn)->want>=want) break;
}
if (*rn && (*rn)->want==want) {
a_remove(&f->attribs, a);
sprintf(buf, "Die Nummer %s wurde bereits einer anderen Partei zugeteilt.", itoa36(want));
addmessage(0, f, buf, MSG_MESSAGE, ML_IMPORTANT);
} else {
struct renum * r = calloc(sizeof(struct renum), 1);
r->next = *rn;
r->attrib = a;
r->faction = f;
r->want = want;
*rn = r;
}
}
for (rp=renum;rp;rp=rp->next) {
2002-11-02 16:50:51 +01:00
f = rp->faction;
a_remove(&f->attribs, rp->attrib);
if (f->subscription) fprintf(sqlstream, "UPDATE subscriptions set faction='%s' where "
2002-11-02 16:52:07 +01:00
"id=%u;\n", itoa36(rp->want),
f->subscription);
2002-11-02 16:50:51 +01:00
f->no = rp->want;
2001-01-25 10:37:55 +01:00
register_faction_id(rp->want);
2002-11-02 16:50:51 +01:00
fset(f, FF_NEWID);
2001-01-25 10:37:55 +01:00
}
while (renum) {
rp = renum->next;
free(renum);
renum = rp;
}
}
static void
reorder(void)
{
region * r;
for (r=regions;r;r=r->next) {
unit * u, ** up=&r->units;
boolean sorted=false;
2001-01-25 10:37:55 +01:00
while (*up) {
u = *up;
if (!fval(u, FL_MARK)) {
2001-01-25 10:37:55 +01:00
strlist * o;
for (o=u->orders;o;o=o->next) {
if (igetkeyword(o->s, u->faction->locale)==K_SORT) {
2001-01-25 10:37:55 +01:00
const char * s = getstrtoken();
param_t p = findparam(s, u->faction->locale);
2001-01-25 10:37:55 +01:00
int id = getid();
unit **vp, *v = findunit(id);
if (v==NULL || v->faction!=u->faction || v->region!=r) {
cmistake(u, o->s, 258, MSG_EVENT);
} else if (v->building != u->building || v->ship!=u->ship) {
cmistake(u, o->s, 259, MSG_EVENT);
} else if (fval(u, UFL_OWNER)) {
2001-01-25 10:37:55 +01:00
cmistake(u, o->s, 260, MSG_EVENT);
} else if (v == u) {
cmistake(u, o->s, 10, MSG_EVENT);
} else {
switch(p) {
2001-01-25 10:37:55 +01:00
case P_AFTER:
*up = u->next;
u->next = v->next;
v->next = u;
break;
case P_BEFORE:
if (fval(v, UFL_OWNER)) {
2001-01-25 10:37:55 +01:00
cmistake(u, o->s, 261, MSG_EVENT);
} else {
vp=&r->units;
while (*vp!=v) vp=&(*vp)->next;
*vp = u;
*up = u->next;
u->next = v;
}
break;
}
fset(u, FL_MARK);
sorted = true;
2001-01-25 10:37:55 +01:00
}
break;
}
}
}
if (u==*up) up=&u->next;
}
2001-02-11 11:06:07 +01:00
if (sorted) for (u=r->units;u;u=u->next) freset(u, FL_MARK);
2001-01-25 10:37:55 +01:00
}
}
2002-04-21 13:23:58 +02:00
#if 0
2002-04-28 14:47:29 +02:00
/* Aus Geb<65>ude weisen, VERBANNE */
2002-04-21 13:23:58 +02:00
static void
evict(void)
{
region *r;
strlist *S;
unit * u;
for (r=regions;r;r=r->next) {
for (u=r->units;u;u=u->next) {
for (S = u->orders; S; S = S->next) if (igetkeyword(S->s, u->faction->locale)==K_EVICT) {
/* Nur der Kapit<69>n bzw Burgherr kann jemanden rausschmei<65>en */
if(!fval(u, UFL_OWNER)) {
2002-04-28 14:47:29 +02:00
/* Die Einheit ist nicht der Eigent<6E>mer */
cmistake(u,S->s,49,MSG_EVENT);
2002-04-21 13:23:58 +02:00
continue;
}
int id = getid();
unit *u2 = findunit(id);
2002-04-28 14:47:29 +02:00
if (!u2){
/* Einheit nicht gefunden */
cmistake(u,S->s,63,MSG_EVENT);
continue;
}
if (u->building){
/* in der selben Burg? */
if (u->building != u2->building){
/* nicht in Burg */
cmistake(u,S->s,33,MSG_EVENT);
continue;
}
leave_building(u2);
/* meldung an beide */
}
if (u->ship){
if (u->ship != u2->ship){
/* nicht an Bord */
cmistake(u,S->s,32,MSG_EVENT);
continue;
}
leave_ship(u2);
/* meldung an beide */
}
2002-04-21 13:23:58 +02:00
}
}
}
}
#endif
#ifdef REGIONOWNERS
static void
declare_war(void)
{
region *r;
for (r=regions;r;r=r->next) {
unit * u;
for (u=r->units;u;u=u->next) {
strlist *S;
faction * f = u->faction;
for (S = u->orders; S; S = S->next) {
switch (igetkeyword(S->s, f->locale)) {
case K_WAR:
for (;;) {
const char * s = getstrtoken();
if (s[0]==0) break;
else {
faction * enemy = findfaction(atoi36(s));
if (enemy) {
if (!is_enemy(f, enemy)) {
add_enemy(f, enemy);
ADDMSG(&enemy->msgs, msg_message("war_notify", "enemy", f));
ADDMSG(&f->msgs, msg_message("war_confirm", "enemy", enemy));
}
} else {
ADDMSG(&f->msgs, msg_message("error66", "unit region command", u, r, S->s));
}
}
}
break;
case K_PEACE:
for (;;) {
const char * s = getstrtoken();
if (s[0]==0) break;
else {
faction * enemy = findfaction(atoi36(s));
if (enemy) {
if (is_enemy(f, enemy)) {
remove_enemy(f, enemy);
ADDMSG(&enemy->msgs, msg_message("peace_notify", "enemy", f));
ADDMSG(&f->msgs, msg_message("peace_confirm", "enemy", enemy));
}
} else {
ADDMSG(&f->msgs, msg_message("error66", "unit region command", u, r, S->s));
}
}
}
break;
default:
break;
}
}
}
}
}
#endif
2001-01-25 10:37:55 +01:00
static void
renumber(void)
{
region *r;
const char *s;
2001-01-25 10:37:55 +01:00
strlist *S;
unit * u;
int i;
for (r=regions;r;r=r->next) {
2001-01-25 10:37:55 +01:00
for (u=r->units;u;u=u->next) {
faction * f = u->faction;
for (S = u->orders; S; S = S->next) if (igetkeyword(S->s, u->faction->locale)==K_NUMBER) {
2001-01-25 10:37:55 +01:00
s = getstrtoken();
switch(findparam(s, u->faction->locale)) {
2001-01-25 10:37:55 +01:00
case P_FACTION:
s = getstrtoken();
if (s && *s) {
2001-01-25 10:37:55 +01:00
int i = atoi36(s);
attrib * a = a_find(f->attribs, &at_number);
if (!a) a = a_add(&f->attribs, a_new(&at_number));
a->data.i = i;
}
break;
case P_UNIT:
s = getstrtoken();
if(s == NULL || *s == 0) {
2001-01-25 10:37:55 +01:00
i = newunitid();
} else {
i = atoi36(s);
if (i<=0 || i>MAX_UNIT_NR) {
cmistake(u,S->s,114,MSG_EVENT);
continue;
}
if(forbiddenid(i)) {
cmistake(u,S->s,116,MSG_EVENT);
continue;
}
if(findunitg(i, r)) {
cmistake(u,S->s,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;
case P_SHIP:
if(!u->ship) {
cmistake(u,S->s,144,MSG_EVENT);
continue;
}
if(!fval(u, UFL_OWNER)) {
2001-01-25 10:37:55 +01:00
cmistake(u,S->s,146,MSG_EVENT);
continue;
}
s = getstrtoken();
if(s == NULL || *s == 0) {
2001-01-25 10:37:55 +01:00
i = newcontainerid();
} else {
i = atoi36(s);
if (i<=0 || i>MAX_CONTAINER_NR) {
cmistake(u,S->s,114,MSG_EVENT);
continue;
}
if (findship(i) || findbuilding(i)) {
cmistake(u,S->s,115,MSG_EVENT);
continue;
}
}
sunhash(u->ship);
u->ship->no = i;
shash(u->ship);
break;
case P_BUILDING:
2004-03-08 19:39:34 +01:00
case P_GEBAEUDE:
2001-01-25 10:37:55 +01:00
if(!u->building) {
cmistake(u,S->s,145,MSG_EVENT);
continue;
}
if(!fval(u, UFL_OWNER)) {
2001-01-25 10:37:55 +01:00
cmistake(u,S->s,148,MSG_EVENT);
continue;
}
s = getstrtoken();
if(*s == 0) {
i = newcontainerid();
} else {
i = atoi36(s);
if (i<=0 || i>MAX_CONTAINER_NR) {
cmistake(u,S->s,114,MSG_EVENT);
continue;
}
if(findship(i) || findbuilding(i)) {
cmistake(u,S->s,115,MSG_EVENT);
continue;
}
}
bunhash(u->building);
u->building->no = i;
bhash(u->building);
break;
default:
cmistake(u,S->s,239,MSG_EVENT);
}
}
}
}
renumber_factions();
}
static void
ageing(void)
{
faction *f;
region *r;
/* altern spezieller Attribute, die eine Sonderbehandlung brauchen? */
2001-01-25 10:37:55 +01:00
for(r=regions;r;r=r->next) {
unit *u;
for(u=r->units;u;u=u->next) {
/* Goliathwasser */
int i = get_effect(u, oldpotiontype[P_STRONG]);
if (i > 0){
change_effect(u, oldpotiontype[P_STRONG], -1 * min(u->number, i));
}
/* Berserkerblut*/
i = get_effect(u, oldpotiontype[P_BERSERK]);
if (i > 0){
change_effect(u, oldpotiontype[P_BERSERK], -1 * min(u->number, i));
}
2001-01-25 10:37:55 +01:00
if (is_cursed(u->attribs, C_OLDRACE, 0)){
curse *c = get_curse(u->attribs, ct_find("oldrace"));
2001-01-25 10:37:55 +01:00
if (c->duration == 1 && !(c->flag & CURSE_NOAGE)) {
u->race = new_race[curse_geteffect(c)];
u->irace = new_race[curse_geteffect(c)];
2001-01-25 10:37:55 +01:00
}
}
}
}
/* Borders */
age_borders();
/* Factions */
for (f=factions;f;f=f->next) {
a_age(&f->attribs);
handle_event(&f->attribs, "timer", f);
}
/* Regionen */
for (r=regions;r;r=r->next) {
building ** bp;
unit ** up;
ship ** sp;
a_age(&r->attribs);
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) up = &(*up)->next;
}
/* Schiffe */
for (sp=&r->ships;*sp;) {
ship * s = *sp;
a_age(&s->attribs);
if (s==*sp) handle_event(&s->attribs, "timer", s);
if (s==*sp) sp = &(*sp)->next;
}
/* Geb<65>ude */
for (bp=&r->buildings;*bp;) {
building * b = *bp;
a_age(&b->attribs);
if (b==*bp) handle_event(&b->attribs, "timer", b);
if (b==*bp) bp = &(*bp)->next;
}
}
}
static int
maxunits(faction *f)
{
return (int) (global.maxunits * (1 + 0.4 * fspecial(f, FS_ADMINISTRATOR)));
2001-01-25 10:37:55 +01:00
}
2001-01-25 10:37:55 +01:00
static void
new_units (void)
{
region *r;
unit *u, *u2;
strlist *S, *S2;
/* neue einheiten werden gemacht und ihre befehle (bis zum "ende" zu
* ihnen rueberkopiert, damit diese einheiten genauso wie die alten
* einheiten verwendet werden koennen. */
for (r = regions; r; r = r->next)
for (u = r->units; u; u = u->next)
for (S = u->orders; S;) {
if ((igetkeyword(S->s, u->faction->locale) == K_MAKE) && (getparam(u->faction->locale) == P_TEMP)) {
2001-01-25 10:37:55 +01:00
int g;
const char * name;
2001-01-25 10:37:55 +01:00
int alias;
int mu = maxunits(u->faction);
if(u->faction->no_units >= mu) {
sprintf(buf, "Eine Partei darf aus nicht mehr als %d "
"Einheiten bestehen.", mu);
mistake(u, S->s, buf, MSG_PRODUCE);
S = S->next;
while (S) {
if (igetkeyword(S->s, u->faction->locale) == K_END)
2001-01-25 10:37:55 +01:00
break;
S2 = S->next;
removelist(&u->orders, S);
S = S2;
}
continue;
}
alias = getid();
name = getstrtoken();
if (name && strlen(name)==0) name = NULL;
u2 = create_unit(r, u->faction, 0, u->faction->race, alias, name, u);
2001-01-25 10:37:55 +01:00
a_add(&u2->attribs, a_new(&at_alias))->data.i = alias;
2001-01-25 10:37:55 +01:00
g = getguard(u);
if (g) setguard(u2, g);
else setguard(u, GUARD_NONE);
S = S->next;
while (S) {
if (igetkeyword(S->s, u->faction->locale) == K_END)
2001-01-25 10:37:55 +01:00
break;
S2 = S->next;
translist(&u->orders, &u2->orders, S);
S = S2;
}
}
if (S)
S = S->next;
}
/* im for-loop wuerde S = S->next ausgefuehrt, bevor S geprueft wird.
* Wenn S aber schon 0x0 ist, fuehrt das zu einem Fehler. Und wenn wir
* den while (S) ganz durchlaufen, wird S = 0x0 sein! Dh. wir
* sicherstellen, dass S != 0, bevor wir S = S->next auszufuehren! */
}
static void
setdefaults (void)
{
region *r;
2001-01-25 10:37:55 +01:00
for (r = regions; r; r = r->next) {
unit *u;
2001-01-25 10:37:55 +01:00
for (u = r->units; u; u = u->next) {
strlist *slist;
boolean trade = false;
2001-01-25 10:37:55 +01:00
if (LongHunger() && fval(u, UFL_HUNGER)) {
/* Hungernde Einheiten f<>hren NUR den default-Befehl aus */
const char * cmd = locale_string(u->faction->locale, "defaultorder");
set_string(&u->thisorder, cmd);
continue;
}
2001-01-25 10:37:55 +01:00
/* by default the default long order becomes the new long order. */
set_string(&u->thisorder, u->lastorder);
/* check all orders for a potential new long order this round: */
for (slist=u->orders; !trade && slist!=NULL; slist=slist->next) {
const char * cmd = slist->s;
keyword_t keyword = igetkeyword(cmd, u->faction->locale);
switch (keyword) {
case K_BUY:
case K_SELL:
/* Wenn die Einheit handelt, mu<6D> der Default-Befehl gel<65>scht
* werden. */
set_string(&u->thisorder, "");
trade = true;
break;
case K_CAST:
/* dient dazu, das neben Zaubern kein weiterer Befehl
* ausgef<EFBFBD>hrt werden kann, Zaubern ist ein kurzer Befehl */
set_string(&u->thisorder, "");
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). */
if (getparam(u->faction->locale) == P_TEMP) break;
/* else fall through */
2001-01-25 10:37:55 +01:00
#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:
/* <20>ber dieser Zeile nur Befehle, die auch eine idle Faction machen darf */
if (idle (u->faction)) {
set_string (&u->thisorder, locale_string(u->faction->locale, "defaultorder"));
break;
}
/* else fall through */
case K_ROUTE:
case K_WORK:
case K_DRIVE:
case K_MOVE:
case K_WEREWOLF:
set_string(&u->thisorder, cmd);
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. */
}
}
2001-01-25 10:37:55 +01:00
/* 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 <EFBFBD>bernommen werden */
switch (igetkeyword (u->thisorder, u->faction->locale)) {
case K_MOVE:
case K_BIETE:
case K_ATTACK:
case K_WEREWOLF:
case NOKEYWORD:
break;
2001-01-25 10:37:55 +01:00
default:
set_string(&u->lastorder, u->thisorder);
}
2001-01-25 10:37:55 +01:00
/* Attackiere sollte niemals Default werden */
if (igetkeyword(u->lastorder, u->faction->locale) == K_ATTACK) {
set_string(&u->lastorder, locale_string(u->faction->locale, "defaultorder"));
}
}
}
2001-01-25 10:37:55 +01:00
}
static int
use_item(unit * u, const item_type * itype, int amount, const char * cmd)
2001-01-25 10:37:55 +01:00
{
int i;
int target = read_unitid(u->faction, u->region);
2001-01-25 10:37:55 +01:00
i = new_get_pooled(u, itype->rtype, GET_DEFAULT);
2001-01-25 10:37:55 +01:00
if (amount>i) {
amount = i;
}
if (i==0) {
cmistake(u, cmd, 43, MSG_PRODUCE);
return ENOITEM;
}
2001-01-25 10:37:55 +01:00
if (target==-1) {
if (itype->use==NULL) {
cmistake(u, cmd, 76, MSG_PRODUCE);
return EUNUSABLE;
}
return itype->use(u, itype, amount, cmd);
} else {
if (itype->useonother==NULL) {
cmistake(u, cmd, 76, MSG_PRODUCE);
return EUNUSABLE;
}
return itype->useonother(u, target, itype, amount, cmd);
}
2001-01-25 10:37:55 +01:00
}
static int
canheal(const unit *u)
{
switch(old_race(u->race)) {
2001-01-25 10:37:55 +01:00
case RC_DAEMON:
return 15;
break;
case RC_GOBLIN:
return 20;
break;
case RC_TROLL:
return 15;
break;
case RC_FIREDRAGON:
case RC_DRAGON:
case RC_WYRM:
return 10;
break;
}
if (u->race->flags & RCF_NOHEAL) return 0;
2001-01-25 10:37:55 +01:00
return 10;
}
static void
monthly_healing(void)
{
region *r;
static const curse_type * heal_ct = NULL;
if (heal_ct==NULL) heal_ct = ct_find("healingzone");
2001-01-25 10:37:55 +01:00
for (r = regions; r; r = r->next) {
unit *u;
int healingcurse = 0;
if (heal_ct!=NULL) {
/* bonus zur<75>cksetzen */
curse * c = get_curse(r->attribs, heal_ct);
if (c!=NULL) {
healingcurse = curse_geteffect(c);
}
}
for (u = r->units; u; u = u->next) {
int umhp = unit_max_hp(u) * u->number;
int p;
/* hp <20>ber Maximum bauen sich ab. Wird zb durch Elixier der Macht
* oder ver<EFBFBD>ndertes Ausdauertalent verursacht */
if (u->hp > umhp) {
u->hp -= (int) ceil((u->hp - umhp) / 2.0);
if (u->hp < umhp)
u->hp = umhp;
}
if((u->race->flags & RCF_NOHEAL) || fval(u, UFL_HUNGER) || fspecial(u->faction, FS_UNDEAD))
continue;
2001-01-25 10:37:55 +01:00
if(rterrain(r) == T_OCEAN && !u->ship && !(canswim(u)))
continue;
2001-01-25 10:37:55 +01:00
if(fspecial(u->faction, FS_REGENERATION)) {
u->hp = umhp;
continue;
}
2001-01-25 10:37:55 +01:00
p = canheal(u);
if (u->hp < umhp && p > 0) {
/* Mind 1 HP wird pro Runde geheilt, weil angenommen wird,
das alle Personen mind. 10 HP haben. */
int max_unit = max(umhp, u->number * 10);
2001-01-25 10:37:55 +01:00
#ifdef NEW_TAVERN
struct building * b = inside_building(u);
const struct building_type * btype = b?b->type:NULL;
if (btype == bt_find("inn")) {
max_unit = max_unit * 3 / 2;
}
2001-01-25 10:37:55 +01:00
#endif
/* der healing curse ver<65>ndert den Regenerationsprozentsatz.
* Wenn dies f<EFBFBD>r negative Heilung benutzt wird, kann es zu
* negativen u->hp f<EFBFBD>hren! */
if (healingcurse != 0) {
p += healingcurse;
}
2002-05-24 09:12:50 +02:00
/* Aufaddieren der geheilten HP. */
u->hp = min(u->hp + max_unit*p/100, umhp);
if (u->hp < umhp && (rand() % 10 < max_unit % 10)){
++u->hp;
}
/* soll man an negativer regeneration sterben k<>nnen? */
if (u->hp <= 0){
u->hp = 1;
}
}
}
}
2001-01-25 10:37:55 +01:00
}
static void
defaultorders (void)
{
region *r;
unit *u;
const char * c;
2001-01-25 10:37:55 +01:00
int i;
strlist *s;
list_foreach(region, regions, r) {
list_foreach(unit, r->units, u) {
list_foreach(strlist, u->orders, s) {
switch (igetkeyword(s->s, u->faction->locale)) {
2001-01-25 10:37:55 +01:00
case K_DEFAULT:
c = getstrtoken();
i = atoi(c);
switch (i) {
case 0 :
if (c[0]=='0') set_string(&u->lastorder, getstrtoken());
else set_string(&u->lastorder, c);
s->s[0]=0;
break;
case 1 :
sprintf(buf, "%s \"%s\"", locale_string(u->faction->locale, keywords[K_DEFAULT]), getstrtoken());
2001-01-25 10:37:55 +01:00
set_string(&s->s, buf);
break;
default :
sprintf(buf, "%s %d \"%s\"", locale_string(u->faction->locale, keywords[K_DEFAULT]), i-1, getstrtoken());
2001-01-25 10:37:55 +01:00
set_string(&s->s, buf);
break;
}
}
}
list_next(s);
}
list_next(u);
}
list_next(r);
}
/* ************************************************************ */
/* GANZ WICHTIG! ALLE GE<47>NDERTEN SPR<50>CHE NEU ANZEIGEN */
/* GANZ WICHTIG! F<>GT AUCH NEUE ZAUBER IN DIE LISTE DER BEKANNTEN EIN */
/* ************************************************************ */
static void
update_spells(void)
{
region *r;
for(r=regions; r; r=r->next) {
unit *u;
for(u=r->units;u;u=u->next) {
sc_mage *m = get_mage(u);
if (u->faction->no != MONSTER_FACTION && m != NULL) {
if (m->magietyp == M_GRAU) continue;
updatespelllist(u);
}
}
}
}
static void
age_factions(void)
2001-01-25 10:37:55 +01:00
{
faction *f;
for (f = factions; f; f = f->next) {
++f->age;
2001-01-25 10:37:55 +01:00
if (f->age < IMMUN_GEGEN_ANGRIFF) {
add_message(&f->msgs, new_message(f,
"newbieimmunity%i:turns", IMMUN_GEGEN_ANGRIFF - f->age));
}
}
}
2001-01-25 10:37:55 +01:00
static void
use(void)
{
region *r;
unit *u;
strlist *S;
2001-01-25 10:37:55 +01:00
for (r = regions; r; r = r->next) {
for (u = r->units; u; u = u->next) {
for (S = u->orders; S; S = S->next) {
if (igetkeyword(S->s, u->faction->locale) == K_USE) {
const char * t = getstrtoken();
int n = atoi(t);
const item_type * itype;
if (n==0) {
n = 1;
2002-03-17 12:43:55 +01:00
} else {
t = getstrtoken();
}
itype = finditemtype(t, u->faction->locale);
2001-01-25 10:37:55 +01:00
if (itype!=NULL) {
int i = use_item(u, itype, n, S->s);
assert(i<=0 || !"use_item should not return positive values.");
2001-01-25 10:37:55 +01:00
} else {
cmistake(u, S->s, 43, MSG_PRODUCE);
2001-01-25 10:37:55 +01:00
}
}
}
}
}
}
void
processorders (void)
{
region *r;
if (turn == 0) srand(time((time_t *) NULL));
else srand(turn);
puts(" - neue Einheiten erschaffen...");
new_units();
puts(" - Monster KI...");
if (!nomonsters) plan_monsters();
set_passw(); /* und pruefe auf illegale Befehle */
puts(" - Defaults und Instant-Befehle...");
setdefaults();
instant_orders();
2002-09-02 22:36:12 +02:00
#ifdef ALLIANCES
alliancekick();
#endif
mail();
puts(" - Altern");
age_factions();
puts(" - Benutzen");
use();
2001-01-25 10:37:55 +01:00
puts(" - Kontaktieren, Betreten von Schiffen und Geb<65>uden (1.Versuch)");
2002-11-25 20:11:27 +01:00
do_misc(false);
2001-04-26 19:41:06 +02:00
2002-09-02 22:36:12 +02:00
#ifdef ALLIANCES
puts(" - Testen der Allianzbedingungen");
alliancevictory();
#endif
2001-04-26 19:41:06 +02:00
puts(" - GM Kommandos");
infocommands();
gmcommands();
2001-01-25 10:37:55 +01:00
puts(" - Verlassen");
do_leave();
puts(" - Kontakte l<>schen");
remove_contacts();
puts(" - Jihad-Angriffe");
jihad_attacks();
puts(" - Attackieren");
if(nobattle == false) do_battle();
if (turn == 0) srand(time((time_t *) NULL));
else srand(turn);
puts(" - Belagern");
do_siege();
puts(" - Initialisieren des Pools, Reservieren");
init_pool();
puts(" - Kontaktieren, Betreten von Schiffen und Geb<65>uden (2.Versuch)");
2002-11-25 20:11:27 +01:00
do_misc(false);
2001-01-25 10:37:55 +01:00
puts(" - Folge auf Einheiten ersetzen");
follow_unit();
2001-01-25 10:37:55 +01:00
if (turn == 0) srand(time((time_t *) NULL));
else srand(turn);
puts(" - Zerst<73>ren, Geben, Rekrutieren, Vergessen");
economics();
2002-01-27 11:40:40 +01:00
remove_empty_units();
2001-01-25 10:37:55 +01:00
puts(" - Geb<65>udeunterhalt (1. Versuch)");
maintain_buildings(false);
2001-01-25 10:37:55 +01:00
puts(" - Sterben");
quit();
puts(" - Zaubern");
magic();
2002-02-22 20:41:20 +01:00
remove_empty_units();
2001-01-25 10:37:55 +01:00
if (!global.disabled[K_TEACH]) {
puts(" - Lehren");
teaching();
}
2001-01-25 10:37:55 +01:00
puts(" - Lernen");
learn();
puts(" - Produzieren, Geldverdienen, Handeln, Anwerben");
produce();
2002-11-25 20:11:27 +01:00
puts(" - Kontaktieren, Betreten von Schiffen und Geb<65>uden (3.Versuch)");
do_misc(true);
puts(" - Schiffe sinken");
sinkships();
2001-01-25 10:37:55 +01:00
puts(" - Bewegungen");
movement();
puts(" - Bewache (an)");
bewache_an();
puts(" - Zufallsbegegnungen");
encounters();
if (turn == 0) srand(time((time_t *) NULL));
else srand(turn);
puts(" - Monster fressen und vertreiben Bauern");
monsters_kill_peasants();
puts(" - random events");
2001-01-25 10:37:55 +01:00
randomevents();
puts(" - newspaper commands");
xecmd();
2001-01-25 10:37:55 +01:00
puts(" - regeneration (healing & aura)");
monthly_healing();
2001-01-25 10:37:55 +01:00
regeneration_magiepunkte();
puts(" - Defaults setzen");
defaultorders();
puts(" - Unterhaltskosten, Nachfrage, Seuchen, Wachstum, Auswanderung");
demographics();
puts(" - Geb<65>udeunterhalt (2. Versuch)");
maintain_buildings(true);
puts(" - Jihads setzen");
set_jihad();
#ifdef USE_UGROUPS
2001-04-28 17:39:13 +02:00
puts(" - Verb<72>nde bilden");
ugroups();
#endif
2001-04-28 17:39:13 +02:00
puts(" - Einheiten Sortieren");
2001-01-25 10:37:55 +01:00
reorder();
2002-04-21 13:23:58 +02:00
#if 0
puts(" - Einheiten aus Geb<65>uden/Schiffen weisen");
evict();
2002-09-02 22:36:12 +02:00
#endif
#ifdef ALLIANCEJOIN
alliancejoin();
#endif
#ifdef REGIONOWNERS
puts(" - Krieg & Frieden");
declare_war();
2002-04-21 13:23:58 +02:00
#endif
puts(" - Neue Nummern");
renumber();
2001-02-11 13:10:58 +01:00
2001-01-25 10:37:55 +01:00
for (r = regions;r;r=r->next) reorder_owners(r);
puts(" - Attribute altern");
ageing();
2004-02-21 23:25:00 +01:00
#ifdef WORMHOLE_MODULE
create_wormholes();
#endif
/* immer ausf<73>hren, wenn neue Spr<70>che dazugekommen sind, oder sich
* Beschreibungen ge<EFBFBD>ndert haben */
update_spells();
2001-01-25 10:37:55 +01:00
}
2001-02-10 11:40:12 +01:00
int
count_migrants (const faction * f)
{
#ifndef NDEBUG
unit *u = f->units;
int n = 0;
while (u) {
assert(u->faction == f);
if (u->race != f->race && u->race != new_race[RC_ILLUSION] && u->race != new_race[RC_SPELL]
&& !!playerrace(u->race) && !(is_cursed(u->attribs, C_SLAVE, 0)))
2001-02-10 11:40:12 +01:00
{
n += u->number;
}
u = u->nextF;
}
if (f->num_migrants != n)
log_error(("Anzahl Migranten f<>r (%s) ist falsch: %d statt %d.\n", factionid(f), f->num_migrants, n));
2001-02-10 11:40:12 +01:00
#endif
return f->num_migrants;
}
int
writepasswd(void)
{
FILE * F;
char zText[128];
sprintf(zText, "%s/passwd", basepath());
F = cfopen(zText, "w");
if (F) {
faction *f;
puts("Schreibe Passw<73>rter...");
for (f = factions; f; f = f->next) {
fprintf(F, "%s:%s:%s:%s:%u\n",
factionid(f), f->email, f->passw, f->override, f->subscription);
}
fclose(F);
return 0;
}
return 1;
}