server/src/gamecode/laws.c

4369 lines
109 KiB
C
Raw Normal View History

2010-08-08 10:06:34 +02:00
/*
Copyright (c) 1998-2010, Enno Rehling <enno@eressea.de>
Katja Zedel <katze@felidae.kn-bremen.de
Christian Schlittchen <corwin@amber.kn-bremen.de>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
**/
#pragma region includes
#include <platform.h>
#include <kernel/config.h>
#include "laws.h"
#include <modules/gmcmd.h>
#include <modules/wormhole.h>
/* gamecode includes */
#include "economy.h"
#include "archetype.h"
#include "monster.h"
#include "randenc.h"
#include "spy.h"
#include "study.h"
#include "market.h"
/* kernel includes */
#include <kernel/alchemy.h>
#include <kernel/alliance.h>
#include <kernel/battle.h>
#include <kernel/connection.h>
#include <kernel/building.h>
#include <kernel/calendar.h>
#include <kernel/faction.h>
#include <kernel/group.h>
#include <kernel/item.h>
#include <kernel/magic.h>
#include <kernel/message.h>
#include <kernel/move.h>
#include <kernel/order.h>
#include <kernel/plane.h>
#include <kernel/pool.h>
#include <kernel/race.h>
#include <kernel/region.h>
#include <kernel/resources.h>
#include <kernel/save.h>
#include <kernel/ship.h>
#include <kernel/skill.h>
#include <kernel/spell.h>
#include <kernel/teleport.h>
#include <kernel/terrain.h>
2011-03-07 08:02:35 +01:00
#include <kernel/terrainid.h> /* for volcanoes in emigration (needs a flag) */
2010-08-08 10:06:34 +02:00
#include <kernel/unit.h>
/* attributes includes */
#include <attributes/racename.h>
#include <attributes/raceprefix.h>
#include <attributes/object.h>
/* util includes */
#include <util/attrib.h>
#include <util/base36.h>
#include <util/bsdstring.h>
#include <util/event.h>
#include <util/goodies.h>
#include <util/language.h>
#include <util/lists.h>
#include <util/log.h>
#include <util/parser.h>
#include <util/rand.h>
#include <util/rng.h>
#include <util/sql.h>
#include <util/umlaut.h>
#include <util/message.h>
#include <util/rng.h>
#include <util/xml.h>
#include <modules/xecmd.h>
#include <attributes/otherfaction.h>
/* libc includes */
#include <assert.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <tests.h>
#pragma endregion
/* chance that a peasant dies of starvation: */
#define PEASANT_STARVATION_CHANCE 0.9F
/* Pferdevermehrung */
#define HORSEGROWTH 4
/* Wanderungschance pro Pferd */
#define HORSEMOVE 3
/* Vermehrungschance pro Baum */
2011-03-07 08:02:35 +01:00
#define FORESTGROWTH 10000 /* In Millionstel */
2010-08-08 10:06:34 +02:00
/** Ausbreitung und Vermehrung */
#define MAXDEMAND 25
2011-03-07 08:02:35 +01:00
#define DMRISE 0.1F /* weekly chance that demand goes up */
#define DMRISEHAFEN 0.2F /* weekly chance that demand goes up with harbor */
2010-08-08 10:06:34 +02:00
/* - exported global symbols ----------------------------------- */
boolean nobattle = false;
boolean nomonsters = false;
/* ------------------------------------------------------------- */
2011-03-07 08:02:35 +01:00
static int RemoveNMRNewbie(void)
{
2010-08-08 10:06:34 +02:00
static int value = -1;
2010-11-01 03:32:24 +01:00
static int gamecookie = -1;
2011-03-07 08:02:35 +01:00
if (value < 0 || gamecookie != global.cookie) {
2010-08-08 10:06:34 +02:00
value = get_param_int(global.parameters, "nmr.removenewbie", 0);
2010-11-01 03:32:24 +01:00
gamecookie = global.cookie;
2010-08-08 10:06:34 +02:00
}
return value;
}
2011-03-07 08:02:35 +01:00
static void restart_race(unit * u, const race * rc)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
faction *oldf = u->faction;
2011-03-08 08:44:20 +01:00
faction *f = addfaction(oldf->email, oldf->passw, rc, oldf->locale,
oldf->subscription);
2011-03-07 08:02:35 +01:00
unit *nu = addplayer(u->region, f);
order **ordp = &u->orders;
2010-08-08 10:06:34 +02:00
f->subscription = u->faction->subscription;
f->age = u->faction->age;
fset(f, FFL_RESTART);
if (f->subscription) {
2011-03-07 08:02:35 +01:00
sql_print(
("UPDATE subscriptions set faction='%s', race='%s' where id=%u;\n",
itoa36(f->no), dbrace(rc), f->subscription));
2010-08-08 10:06:34 +02:00
}
f->magiegebiet = u->faction->magiegebiet;
f->options = u->faction->options;
free_orders(&nu->orders);
nu->orders = u->orders;
u->orders = NULL;
while (*ordp) {
2011-03-07 08:02:35 +01:00
order *ord = *ordp;
2010-08-08 10:06:34 +02:00
if (get_keyword(ord) != K_RESTART) {
*ordp = ord->next;
ord->next = NULL;
2011-03-07 08:02:35 +01:00
if (u->thisorder == ord)
set_order(&u->thisorder, NULL);
2010-08-08 10:06:34 +02:00
} else {
ordp = &ord->next;
}
}
destroyfaction(u->faction);
}
2011-03-07 08:02:35 +01:00
static void checkorders(void)
2010-08-08 10:06:34 +02:00
{
faction *f;
2011-03-07 08:02:35 +01:00
if (verbosity >= 1)
puts(" - Warne spaete Spieler...");
2010-08-08 10:06:34 +02:00
for (f = factions; f; f = f->next)
if (!is_monsters(f) && turn - f->lastorders == NMRTimeout() - 1)
ADDMSG(&f->msgs, msg_message("turnreminder", ""));
}
2011-03-07 08:02:35 +01:00
static boolean help_money(const unit * u)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
if (u->race->ec_flags & GIVEITEM)
return true;
2010-08-08 10:06:34 +02:00
return false;
}
2011-03-07 08:02:35 +01:00
static void help_feed(unit * donor, unit * u, int *need_p)
2010-08-08 10:06:34 +02:00
{
int need = *need_p;
int give = get_money(donor) - lifestyle(donor);
give = MIN(need, give);
2011-03-07 08:02:35 +01:00
if (give > 0) {
2010-08-08 10:06:34 +02:00
change_money(donor, -give);
change_money(u, give);
need -= give;
add_spende(donor->faction, u->faction, give, donor->region);
}
*need_p = need;
}
enum {
FOOD_FROM_PEASANTS = 1,
FOOD_FROM_OWNER = 2,
FOOD_IS_FREE = 4
};
2011-03-09 06:16:47 +01:00
void get_food(region * r)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
plane *pl = rplane(r);
2010-08-08 10:06:34 +02:00
unit *u;
2011-03-07 08:02:35 +01:00
int peasantfood = rpeasants(r) * 10;
2010-08-08 10:06:34 +02:00
static int food_rules = -1;
static int gamecookie = -1;
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
if (food_rules < 0 || gamecookie != global.cookie) {
gamecookie = global.cookie;
2010-08-08 10:06:34 +02:00
food_rules = get_param_int(global.parameters, "rules.economy.food", 0);
}
2011-03-07 08:02:35 +01:00
if (food_rules & FOOD_IS_FREE) {
return;
}
2010-08-08 10:06:34 +02: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. */
for (u = r->units; u; u = u->next) {
int need = lifestyle(u);
/* Erstmal zur<75>cksetzen */
freset(u, UFL_HUNGER);
2011-03-07 08:02:35 +01:00
if (u->ship && (u->ship->flags & SF_FISHING)) {
unit *v;
2010-08-08 10:06:34 +02:00
int c = 2;
2011-03-07 08:02:35 +01:00
for (v = u; c > 0 && v; v = v->next) {
if (v->ship == u->ship) {
2010-08-08 10:06:34 +02:00
int get = 0;
2011-03-07 08:02:35 +01:00
if (v->number <= c) {
2010-08-08 10:06:34 +02:00
get = lifestyle(v);
} else {
get = lifestyle(v) * c / v->number;
}
if (get) {
change_money(v, get);
}
}
c -= v->number;
}
u->ship->flags -= SF_FISHING;
}
2011-03-07 08:02:35 +01:00
if (food_rules & FOOD_FROM_PEASANTS) {
faction *owner = region_get_owner(r);
2010-08-08 10:06:34 +02:00
/* if the region is owned, and the owner is nice, then we'll get
* food from the peasants - should not be used with WORK */
2011-03-07 08:02:35 +01:00
if (owner != NULL && (get_alliance(owner, u->faction) & HELP_MONEY)) {
2010-08-08 10:06:34 +02:00
int rm = rmoney(r);
int use = MIN(rm, need);
2011-03-07 08:02:35 +01:00
rsetmoney(r, rm - use);
2010-08-08 10:06:34 +02:00
need -= use;
}
}
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);
2011-03-07 08:02:35 +01:00
if (give > 0) {
2010-08-08 10:06:34 +02:00
change_money(v, -give);
change_money(u, give);
need -= give;
}
}
}
}
}
/* 2. Versorgung durch Fremde. Das Silber alliierter Einheiten wird
* entsprechend verteilt. */
for (u = r->units; u; u = u->next) {
int need = lifestyle(u);
2011-03-07 08:02:35 +01:00
faction *f = u->faction;
2010-08-08 10:06:34 +02:00
need -= MAX(0, get_money(u));
if (need > 0) {
unit *v;
2011-03-07 08:02:35 +01:00
if (food_rules & FOOD_FROM_OWNER) {
2010-08-08 10:06:34 +02:00
/* the owner of the region is the first faction to help out when you're hungry */
2011-03-07 08:02:35 +01:00
faction *owner = region_get_owner(r);
if (owner && owner != u->faction) {
for (v = r->units; v; v = v->next) {
if (v->faction == owner && alliedunit(v, f, HELP_MONEY)
&& help_money(v)) {
2010-08-08 10:06:34 +02:00
help_feed(v, u, &need);
break;
}
}
}
}
for (v = r->units; need && v; v = v->next) {
2011-03-08 08:44:20 +01:00
if (v->faction != f && alliedunit(v, f, HELP_MONEY)
&& help_money(v)) {
2010-08-08 10:06:34 +02:00
help_feed(v, u, &need);
}
}
/* Die Einheit hat nicht genug Geld zusammengekratzt und
* nimmt Schaden: */
if (need > 0) {
2011-03-07 08:02:35 +01:00
int lspp = lifestyle(u) / u->number;
2010-08-08 10:06:34 +02:00
if (lspp > 0) {
2011-03-07 08:02:35 +01:00
int number = (need + lspp - 1) / lspp;
if (hunger(number, u))
fset(u, UFL_HUNGER);
2010-08-08 10:06:34 +02: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]) {
2011-03-07 08:02:35 +01:00
unit *donor = r->units;
2010-08-08 10:06:34 +02:00
int hungry = u->number;
2011-03-07 08:02:35 +01:00
while (donor != NULL && hungry > 0) {
2010-08-08 10:06:34 +02:00
/* always start with the first known unit that may have some blood */
2011-03-07 08:02:35 +01:00
static const struct potion_type *pt_blood;
if (pt_blood == NULL) {
const item_type *it_blood = it_find("peasantblood");
if (it_blood)
pt_blood = it_blood->rtype->ptype;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
if (pt_blood != NULL) {
while (donor != NULL) {
if (donor->race == new_race[RC_DAEMON]) {
2010-08-08 10:06:34 +02:00
if (get_effect(donor, pt_blood)) {
/* if he's in our faction, drain him: */
2011-03-07 08:02:35 +01:00
if (donor->faction == u->faction)
break;
2010-08-08 10:06:34 +02:00
}
}
donor = donor->next;
}
if (donor != NULL) {
int blut = get_effect(donor, pt_blood);
blut = MIN(blut, hungry);
change_effect(donor, pt_blood, -blut);
hungry -= blut;
}
}
}
if (pl == NULL || !fval(pl, PFL_NOFEED)) {
2011-03-07 08:02:35 +01:00
if (peasantfood >= hungry) {
2010-08-08 10:06:34 +02:00
peasantfood -= hungry;
hungry = 0;
} else {
hungry -= peasantfood;
peasantfood = 0;
}
if (hungry > 0) {
static int demon_hunger = -1;
2011-03-07 08:02:35 +01:00
if (demon_hunger < 0) {
2010-08-08 10:06:34 +02:00
demon_hunger = get_param_int(global.parameters, "hunger.demons", 0);
}
2011-03-07 08:02:35 +01:00
if (demon_hunger == 0) {
2010-08-08 10:06:34 +02:00
/* nicht gef<65>tterte d<>monen hungern */
#ifdef PEASANT_HUNGRY_DAEMONS_HAVE_FULL_SKILLS
/* wdw special rule */
hunger(hungry, u);
#else
2011-03-07 08:02:35 +01:00
if (hunger(hungry, u))
fset(u, UFL_HUNGER);
2010-08-08 10:06:34 +02:00
#endif
2011-03-07 08:02:35 +01:00
/* used to be: hunger(hungry, u); */
2010-08-08 10:06:34 +02:00
} else {
/* no damage, but set the hungry-flag */
fset(u, UFL_HUNGER);
}
}
}
}
}
2011-03-07 08:02:35 +01:00
rsetpeasants(r, peasantfood / 10);
2010-08-08 10:06:34 +02: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);
}
}
2011-03-07 08:02:35 +01:00
static void age_unit(region * r, unit * u)
2010-08-08 10:06:34 +02:00
{
if (u->race == new_race[RC_SPELL]) {
if (--u->age <= 0) {
remove_unit(&r->units, u);
}
} else {
++u->age;
2011-03-07 08:02:35 +01:00
if (u->number > 0 && u->race->age) {
2010-08-08 10:06:34 +02:00
u->race->age(u);
}
}
#ifdef ASTRAL_ITEM_RESTRICTIONS
if (u->region && is_astral(u->region)) {
2011-03-07 08:02:35 +01:00
item **itemp = &u->items;
2010-08-08 10:06:34 +02:00
while (*itemp) {
2011-03-07 08:02:35 +01:00
item *itm = *itemp;
2010-08-08 10:06:34 +02:00
if ((itm->type->flags & ITF_NOTLOST) == 0) {
2011-03-07 08:02:35 +01:00
if (itm->type->flags & (ITF_BIG | ITF_ANIMAL | ITF_CURSED)) {
ADDMSG(&u->faction->msgs, msg_message("itemcrumble",
2011-03-08 08:44:20 +01:00
"unit region item amount",
u, u->region, itm->type->rtype, itm->number));
2010-08-08 10:06:34 +02:00
i_free(i_remove(itemp, itm));
continue;
}
}
2011-03-07 08:02:35 +01:00
itemp = &itm->next;
2010-08-08 10:06:34 +02:00
}
}
#endif
}
2011-03-07 08:02:35 +01:00
static void live(region * r)
2010-08-08 10:06:34 +02:00
{
unit **up = &r->units;
get_food(r);
while (*up) {
2011-03-07 08:02:35 +01:00
unit *u = *up;
2010-08-08 10:06:34 +02:00
/* IUW: age_unit() kann u loeschen, u->next ist dann
2011-03-07 08:02:35 +01:00
* undefiniert, also muessen wir hier schon das n<EFBFBD>chste
* Element bestimmen */
2010-08-08 10:06:34 +02:00
int effect = get_effect(u, oldpotiontype[P_FOOL]);
2011-03-07 08:02:35 +01:00
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) {
2010-08-08 10:06:34 +02:00
sb = sv;
}
++sv;
}
/* bestes Talent raussuchen */
2011-03-07 08:02:35 +01:00
if (sb != NULL) {
2010-08-08 10:06:34 +02:00
int weeks = MIN(effect, u->number);
reduce_skill(u, sb, weeks);
ADDMSG(&u->faction->msgs, msg_message("dumbeffect",
2011-03-07 08:02:35 +01:00
"unit weeks skill", u, weeks, (skill_t) sb->id));
} /* sonst Gl<47>ck gehabt: wer nix wei<65>, kann nix vergessen... */
2010-08-08 10:06:34 +02:00
change_effect(u, oldpotiontype[P_FOOL], -effect);
}
age_unit(r, u);
2011-03-07 08:02:35 +01:00
if (*up == u)
up = &u->next;
2010-08-08 10:06:34 +02: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.
*/
#define MAX_EMIGRATION(p) ((p)/MAXDIRECTIONS)
#define MAX_IMMIGRATION(p) ((p)*2/3)
2011-03-07 08:02:35 +01:00
static void calculate_emigration(region * r)
2010-08-08 10:06:34 +02:00
{
int i;
int maxp = maxworkingpeasants(r);
int rp = rpeasants(r);
2011-03-07 08:02:35 +01:00
int max_immigrants = MAX_IMMIGRATION(maxp - rp);
if (r->terrain == newterrain(T_VOLCANO)
|| r->terrain == newterrain(T_VOLCANO_SMOKING)) {
max_immigrants = max_immigrants / 10;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
for (i = 0; max_immigrants > 0 && i != MAXDIRECTIONS; i++) {
int dir = (turn + i) % MAXDIRECTIONS;
region *rc = rconnect(r, (direction_t) dir);
2010-08-08 10:06:34 +02:00
if (rc != NULL && fval(rc->terrain, LAND_REGION)) {
int rp2 = rpeasants(rc);
int maxp2 = maxworkingpeasants(rc);
2011-03-07 08:02:35 +01:00
int max_emigration = MAX_EMIGRATION(rp2 - maxp2);
if (max_emigration > 0) {
2010-08-08 10:06:34 +02:00
max_emigration = MIN(max_emigration, max_immigrants);
r->land->newpeasants += max_emigration;
rc->land->newpeasants -= max_emigration;
max_immigrants -= max_emigration;
}
}
}
}
/** Bauern vermehren sich */
2011-03-07 08:02:35 +01:00
static void peasants(region * r)
2010-08-08 10:06:34 +02:00
{
int peasants = rpeasants(r);
int money = rmoney(r);
int maxp = production(r) * MAXPEASANTS_PER_AREA;
int n, satiated;
int dead = 0;
/* Bis zu 1000 Bauern k<>nnen Zwillinge bekommen oder 1000 Bauern
* wollen nicht! */
2011-03-07 08:02:35 +01:00
if (peasants > 0) {
2010-08-08 10:06:34 +02:00
int glueck = 0;
double fraction = peasants * 0.0001F * PEASANTGROWTH;
int births = (int)fraction;
2011-03-07 08:02:35 +01:00
attrib *a = a_find(r->attribs, &at_peasantluck);
if (rng_double() < (fraction - births)) {
2010-08-08 10:06:34 +02:00
/* because we don't want regions that never grow pga. rounding. */
++births;
}
2011-03-07 08:02:35 +01:00
if (a != NULL) {
2010-08-08 10:06:34 +02:00
glueck = a->data.i * 1000;
}
for (n = peasants; n; --n) {
int chances = 0;
2011-03-07 08:02:35 +01:00
if (glueck > 0) {
2010-08-08 10:06:34 +02:00
--glueck;
chances += PEASANTLUCK;
}
while (chances--) {
if (rng_int() % 10000 < PEASANTGROWTH) {
/* Only raise with 75% chance if peasants have
* reached 90% of maxpopulation */
2011-03-07 08:02:35 +01:00
if (peasants / (float)maxp < 0.9 || chance(PEASANTFORCE)) {
2010-08-08 10:06:34 +02:00
++births;
}
}
}
}
peasants += births;
}
/* Alle werden satt, oder halt soviele f<>r die es auch Geld gibt */
satiated = MIN(peasants, money / maintenance_cost(NULL));
rsetmoney(r, money - satiated * maintenance_cost(NULL));
/* Von denjenigen, die nicht satt geworden sind, verhungert der
* Gro<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. */
n = MIN(peasants - satiated, rpeasants(r));
2011-03-07 08:02:35 +01:00
dead += (int)(0.5F + n * PEASANT_STARVATION_CHANCE);
2010-08-08 10:06:34 +02:00
if (dead > 0) {
2011-03-07 08:02:35 +01:00
message *msg = add_message(&r->msgs, msg_message("phunger", "dead", dead));
2010-08-08 10:06:34 +02:00
msg_release(msg);
peasants -= dead;
}
rsetpeasants(r, peasants);
}
/* ------------------------------------------------------------- */
typedef struct migration {
2011-03-07 08:02:35 +01:00
struct migration *next;
region *r;
2010-08-08 10:06:34 +02:00
int horses;
int trees;
} migration;
#define MSIZE 1023
2011-03-07 08:02:35 +01:00
migration *migrants[MSIZE];
migration *free_migrants;
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
static migration *get_migrants(region * r)
2010-08-08 10:06:34 +02:00
{
int key = reg_hashkey(r);
int index = key % MSIZE;
2011-03-07 08:02:35 +01:00
migration *m = migrants[index];
2010-08-08 10:06:34 +02:00
while (m && m->r != r)
m = m->next;
if (m == NULL) {
/* Es gibt noch keine Migration. Also eine erzeugen
*/
m = free_migrants;
2011-03-07 08:02:35 +01:00
if (!m)
m = calloc(1, sizeof(migration));
2010-08-08 10:06:34 +02:00
else {
free_migrants = free_migrants->next;
m->horses = 0;
m->trees = 0;
}
m->r = r;
m->next = migrants[index];
migrants[index] = m;
}
return m;
}
2011-03-07 08:02:35 +01:00
static void migrate(region * r)
2010-08-08 10:06:34 +02:00
{
int key = reg_hashkey(r);
int index = key % MSIZE;
2011-03-07 08:02:35 +01:00
migration **hp = &migrants[index];
2010-08-08 10:06:34 +02:00
fset(r, RF_MIGRATION);
2011-03-07 08:02:35 +01:00
while (*hp && (*hp)->r != r)
hp = &(*hp)->next;
2010-08-08 10:06:34 +02:00
if (*hp) {
2011-03-07 08:02:35 +01:00
migration *m = *hp;
2010-08-08 10:06:34 +02:00
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.
*/
*hp = m->next;
m->next = free_migrants;
free_migrants = m;
}
}
2011-03-07 08:02:35 +01:00
static void horses(region * r)
2010-08-08 10:06:34 +02:00
{
int horses, maxhorses;
direction_t n;
/* Logistisches Wachstum, Optimum bei halbem Maximalbesatz. */
2011-03-07 08:02:35 +01:00
maxhorses = maxworkingpeasants(r) / 10;
2010-08-08 10:06:34 +02:00
maxhorses = MAX(0, maxhorses);
horses = rhorses(r);
if (horses > 0) {
if (is_cursed(r->attribs, C_CURSED_BY_THE_GODS, 0)) {
2011-03-07 08:02:35 +01:00
rsethorses(r, (int)(horses * 0.9F));
2010-08-08 10:06:34 +02:00
} else if (maxhorses) {
int i;
2011-03-07 08:02:35 +01:00
double growth =
(RESOURCE_QUANTITY * HORSEGROWTH * 200 * (maxhorses -
horses)) / maxhorses;
if (growth > 0) {
if (a_find(r->attribs, &at_horseluck))
growth *= 2;
2010-08-08 10:06:34 +02:00
/* printf("Horses: <%d> %d -> ", growth, horses); */
i = (int)(0.5F + (horses * 0.0001F) * growth);
/* printf("%d\n", horses); */
rsethorses(r, horses + i);
}
}
}
/* 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.
*/
2011-03-07 08:02:35 +01:00
for (n = 0; n != MAXDIRECTIONS; n++) {
region *r2 = rconnect(r, n);
2010-08-08 10:06:34 +02:00
if (r2 && fval(r2->terrain, WALK_INTO)) {
2011-03-07 08:02:35 +01:00
int pt = (rhorses(r) * HORSEMOVE) / 100;
pt = (int)normalvariate(pt, pt / 4.0);
2010-08-08 10:06:34 +02:00
pt = MAX(0, pt);
if (fval(r2, RF_MIGRATION))
rsethorses(r2, rhorses(r2) + pt);
else {
2011-03-07 08:02:35 +01:00
migration *nb;
2010-08-08 10:06:34 +02:00
/* 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);
}
2011-03-07 08:02:35 +01:00
static int count_race(const region * r, const race * rc)
2010-08-08 10:06:34 +02:00
{
unit *u;
2011-03-07 08:02:35 +01:00
int c = 0;
for (u = r->units; u; u = u->next)
if (u->race == rc)
c += u->number;
2010-08-08 10:06:34 +02:00
return c;
}
extern struct attrib_type at_germs;
static void
2011-03-07 08:02:35 +01:00
growing_trees_e3(region * r, const int current_season,
const int last_weeks_season)
2010-08-08 10:06:34 +02:00
{
2011-03-07 17:26:50 +01:00
static const int transform[4][3] = {
2011-03-07 08:02:35 +01:00
{-1, -1, 0},
{TREE_SEED, TREE_SAPLING, 2},
{TREE_SAPLING, TREE_TREE, 2},
{TREE_TREE, TREE_SEED, 2}
2010-08-08 10:06:34 +02:00
};
2011-03-07 08:02:35 +01:00
if (r->land && current_season != last_weeks_season
&& transform[current_season][2]) {
2010-08-08 10:06:34 +02:00
int src_type = transform[current_season][0];
int dst_type = transform[current_season][1];
int src = rtrees(r, src_type);
int dst = rtrees(r, dst_type);
2011-03-07 08:02:35 +01:00
int grow = src / transform[current_season][2];
if (grow > 0) {
if (src_type != TREE_TREE) {
rsettrees(r, src_type, src - grow);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
rsettrees(r, dst_type, dst + grow);
if (dst_type == TREE_SEED && r->terrain->size) {
region *rn[MAXDIRECTIONS];
2010-08-08 10:06:34 +02:00
int d;
2011-03-07 08:02:35 +01:00
double fgrow = grow / (double)MAXDIRECTIONS;
2010-08-08 10:06:34 +02:00
get_neighbours(r, rn);
2011-03-07 08:02:35 +01:00
for (d = 0; d != MAXDIRECTIONS; ++d) {
region *rx = rn[d];
2010-08-08 10:06:34 +02:00
if (rx && rx->land) {
double scale = 1.0;
int g;
double fg, ch;
int seeds = rtrees(rx, dst_type);
2011-03-07 08:02:35 +01:00
if (r->terrain->size > rx->terrain->size) {
scale = (scale * rx->terrain->size) / r->terrain->size;
2010-08-08 10:06:34 +02:00
}
fg = scale * fgrow;
g = (int)fg;
ch = fg - g;
2011-03-07 08:02:35 +01:00
if (chance(ch))
++g;
if (g > 0) {
2010-08-08 10:06:34 +02:00
rsettrees(rx, dst_type, seeds + g);
}
}
}
}
}
}
}
static void
growing_trees(region * r, const int current_season, const int last_weeks_season)
{
int growth, grownup_trees, i, seeds, sprout;
direction_t d;
attrib *a;
2011-03-07 08:02:35 +01:00
if (current_season == SEASON_SUMMER || current_season == SEASON_AUTUMN) {
2010-08-08 10:06:34 +02:00
double seedchance = 0.01F * RESOURCE_QUANTITY;
int elves = count_race(r, new_race[RC_ELF]);
a = a_find(r->attribs, &at_germs);
2011-03-07 08:02:35 +01:00
if (a && last_weeks_season == SEASON_SPRING) {
2010-08-08 10:06:34 +02:00
/* 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);
}
2011-03-07 08:02:35 +01:00
if (is_cursed(r->attribs, C_CURSED_BY_THE_GODS, 0)) {
2010-08-08 10:06:34 +02:00
rsettrees(r, 1, (int)(rtrees(r, 1) * 0.9));
rsettrees(r, 2, (int)(rtrees(r, 2) * 0.9));
return;
}
2011-03-07 08:02:35 +01:00
if (production(r) <= 0)
return;
2010-08-08 10:06:34 +02:00
/* Grundchance 1.0% */
/* Jeder Elf in der Region erh<72>ht die Chance marginal */
2011-03-07 08:02:35 +01:00
elves = MIN(elves, (production(r) * MAXPEASANTS_PER_AREA) / 8);
2010-08-08 10:06:34 +02:00
if (elves) {
2011-03-07 08:02:35 +01:00
seedchance += 1.0 - pow(0.99999, elves * RESOURCE_QUANTITY);
2010-08-08 10:06:34 +02:00
}
grownup_trees = rtrees(r, 2);
seeds = 0;
2011-03-07 08:02:35 +01:00
if (grownup_trees > 0) {
double remainder = seedchance * grownup_trees;
2010-08-08 10:06:34 +02:00
seeds = (int)(remainder);
remainder -= seeds;
if (chance(remainder)) {
++seeds;
}
2011-03-07 08:02:35 +01:00
if (seeds > 0) {
2010-08-08 10:06:34 +02:00
seeds += rtrees(r, 0);
rsettrees(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 */
2011-03-07 08:02:35 +01:00
seeds = (rtrees(r, 2) * FORESTGROWTH * 3) / 1000000;
for (d = 0; d != MAXDIRECTIONS; ++d) {
region *r2 = rconnect(r, d);
2010-08-08 10:06:34 +02:00
if (r2 && fval(r2->terrain, LAND_REGION) && r2->terrain->size) {
/* 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 = (1000 * maxworkingpeasants(r2)) / r2->terrain->size;
2011-03-07 08:02:35 +01:00
for (i = 0; i < seeds / MAXDIRECTIONS; i++) {
if (rng_int() % 10000 < seedchance)
sprout++;
2010-08-08 10:06:34 +02:00
}
rsettrees(r2, 0, rtrees(r2, 0) + sprout);
}
}
2011-03-07 08:02:35 +01:00
} else if (current_season == SEASON_SPRING) {
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
if (is_cursed(r->attribs, C_CURSED_BY_THE_GODS, 0))
return;
2010-08-08 10:06:34 +02:00
/* 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);
2011-03-07 08:02:35 +01:00
if (!a) {
2010-08-08 10:06:34 +02:00
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;
2011-03-07 08:02:35 +01:00
for (i = 0; i < seeds; i++) {
if (rng_int() % 10000 < growth)
sprout++;
2010-08-08 10:06:34 +02:00
}
/* 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;
2011-03-07 08:02:35 +01:00
for (i = 0; i < sprout; i++) {
if (rng_int() % 10000 < growth)
grownup_trees++;
2010-08-08 10:06:34 +02:00
}
/* 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);
}
}
static void
growing_herbs(region * r, const int current_season, const int last_weeks_season)
{
/* 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_WINTER) {
int i;
for (i = rherbs(r); i > 0; i--) {
2011-03-07 08:02:35 +01:00
if (rng_int() % 100 < (100 - rherbs(r)))
rsetherbs(r, (short)(rherbs(r) + 1));
2010-08-08 10:06:34 +02:00
}
}
}
2011-03-07 08:02:35 +01:00
void demographics(void)
2010-08-08 10:06:34 +02:00
{
region *r;
static int last_weeks_season = -1;
static int current_season = -1;
2011-03-07 08:02:35 +01:00
if (current_season < 0) {
2010-08-08 10:06:34 +02:00
gamedate date;
get_gamedate(turn, &date);
current_season = date.season;
2011-03-07 08:02:35 +01:00
get_gamedate(turn - 1, &date);
2010-08-08 10:06:34 +02:00
last_weeks_season = date.season;
}
for (r = regions; r; r = r->next) {
2011-03-07 08:02:35 +01:00
++r->age; /* also oceans. no idea why we didn't always do that */
2010-08-08 10:06:34 +02:00
live(r);
/* check_split_dragons(); */
if (!fval(r->terrain, SEA_REGION)) {
/* die Nachfrage nach Produkten steigt. */
2011-03-07 08:02:35 +01:00
struct demand *dmd;
2010-08-08 10:06:34 +02:00
if (r->land) {
static int plant_rules = -1;
2011-03-07 08:02:35 +01:00
if (plant_rules < 0) {
plant_rules =
get_param_int(global.parameters, "rules.economy.grow", 0);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
for (dmd = r->land->demands; dmd; dmd = dmd->next) {
if (dmd->value > 0 && dmd->value < MAXDEMAND) {
2010-08-08 10:06:34 +02:00
float rise = DMRISE;
2011-03-07 08:02:35 +01:00
if (buildingtype_exists(r, bt_find("harbour"), true))
rise = DMRISEHAFEN;
if (rng_double() < rise)
++dmd->value;
2010-08-08 10:06:34 +02:00
}
}
/* Seuchen erst nachdem die Bauern sich vermehrt haben
2011-03-07 08:02:35 +01:00
* und gewandert sind */
2010-08-08 10:06:34 +02:00
calculate_emigration(r);
peasants(r);
2011-03-07 08:02:35 +01:00
if (r->age > 20) {
2010-08-08 10:06:34 +02:00
plagues(r, false);
}
horses(r);
2011-03-07 08:02:35 +01:00
if (plant_rules == 0) { /* E1 */
2010-08-08 10:06:34 +02:00
growing_trees(r, current_season, last_weeks_season);
growing_herbs(r, current_season, last_weeks_season);
2011-03-07 08:02:35 +01:00
} else { /* E3 */
2010-08-08 10:06:34 +02:00
growing_trees_e3(r, current_season, last_weeks_season);
}
}
update_resources(r);
2011-03-07 08:02:35 +01:00
if (r->land)
migrate(r);
2010-08-08 10:06:34 +02:00
}
}
while (free_migrants) {
2011-03-07 08:02:35 +01:00
migration *m = free_migrants->next;
2010-08-08 10:06:34 +02:00
free(free_migrants);
free_migrants = m;
};
2011-03-07 08:02:35 +01:00
if (verbosity >= 1)
putchar('\n');
2010-08-08 10:06:34 +02:00
remove_empty_units();
2011-03-07 08:02:35 +01:00
if (verbosity >= 1)
puts(" - Einwanderung...");
2010-08-08 10:06:34 +02:00
for (r = regions; r; r = r->next) {
if (r->land && r->land->newpeasants) {
int rp = rpeasants(r) + r->land->newpeasants;
rsetpeasants(r, MAX(0, rp));
}
}
checkorders();
}
2011-03-07 08:02:35 +01:00
2010-08-08 10:06:34 +02:00
/* ------------------------------------------------------------- */
2011-03-07 08:02:35 +01:00
static int modify(int i)
2010-08-08 10:06:34 +02:00
{
int c;
c = i * 2 / 3;
if (c >= 1) {
return (c + rng_int() % c);
} else {
return (i);
}
}
2011-03-07 08:02:35 +01:00
static void inactivefaction(faction * f)
2010-08-08 10:06:34 +02:00
{
FILE *inactiveFILE;
char zText[128];
sprintf(zText, "%s/%s", datapath(), "inactive");
inactiveFILE = fopen(zText, "a");
if (inactiveFILE) {
fprintf(inactiveFILE, "%s:%s:%d:%d\n",
factionid(f),
LOC(default_locale, rc_name(f->race, 1)),
2011-03-07 08:02:35 +01:00
modify(count_all(f)), turn - f->lastorders);
2010-08-08 10:06:34 +02:00
fclose(inactiveFILE);
}
}
2011-03-07 08:02:35 +01:00
static void transfer_faction(faction * f, faction * f2)
2010-08-08 10:06:34 +02:00
{
unit *u, *un;
for (u = f->units; u;) {
un = u->nextF;
2011-03-07 08:02:35 +01:00
if (!unit_has_cursed_item(u)
2011-03-08 08:44:20 +01:00
&& !has_skill(u, SK_MAGIC) && !has_skill(u, SK_ALCHEMY)) {
2010-08-08 10:06:34 +02:00
u_setfaction(u, f2);
}
u = un;
}
}
2011-03-07 08:02:35 +01:00
static int restart_cmd(unit * u, struct order *ord)
2010-08-08 10:06:34 +02:00
{
init_tokens(ord);
2011-03-07 08:02:35 +01:00
skip_token(); /* skip keyword */
2010-08-08 10:06:34 +02:00
if (!fval(u->region->terrain, LAND_REGION)) {
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", ""));
} else {
2011-03-07 08:02:35 +01:00
const char *s_race = getstrtoken(), *s_pass;
const race *frace = findrace(s_race, u->faction->locale);
2010-08-08 10:06:34 +02:00
if (!frace) {
frace = u->faction->race;
s_pass = s_race;
} else {
s_pass = getstrtoken();
}
if (u->faction->age > 3 && fval(u->faction, FFL_RESTART)) {
cmistake(u, ord, 314, MSG_EVENT);
return 0;
}
2011-03-07 08:02:35 +01:00
if ( /* frace != u->faction->race && */ u->faction->age < 81) {
2010-08-08 10:06:34 +02:00
cmistake(u, ord, 241, MSG_EVENT);
return 0;
}
if (!playerrace(frace)) {
cmistake(u, ord, 243, MSG_EVENT);
return 0;
}
if (!checkpasswd(u->faction, (const char *)s_pass, false)) {
cmistake(u, ord, 86, MSG_EVENT);
log_warning("RESTART with wrong password, faction %s, pass %s\n", factionid(u->faction), s_pass);
2010-08-08 10:06:34 +02:00
return 0;
}
restart_race(u, frace);
return -1;
}
return 0;
}
2011-03-07 08:02:35 +01:00
static boolean EnhancedQuit(void)
2010-08-08 10:06:34 +02:00
{
static int value = -1;
2011-03-07 08:02:35 +01:00
if (value < 0) {
const char *str = get_param(global.parameters, "alliance.transferquit");
value = (str != 0 && strcmp(str, "true") == 0);
2010-08-08 10:06:34 +02:00
}
return value;
}
2011-03-07 08:02:35 +01:00
static int quit_cmd(unit * u, struct order *ord)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
faction *f = u->faction;
const char *passwd;
2010-08-08 10:06:34 +02:00
init_tokens(ord);
2011-03-07 08:02:35 +01:00
skip_token(); /* skip keyword */
2010-08-08 10:06:34 +02:00
passwd = getstrtoken();
if (checkpasswd(f, (const char *)passwd, false)) {
if (EnhancedQuit()) {
int f2_id = getid();
2011-03-07 08:02:35 +01:00
if (f2_id > 0) {
2010-08-08 10:06:34 +02:00
faction *f2 = findfaction(f2_id);
2011-03-07 08:02:35 +01:00
if (f2 == NULL) {
2010-08-08 10:06:34 +02:00
cmistake(u, ord, 66, MSG_EVENT);
return 0;
2011-03-07 08:02:35 +01:00
} else if (!u->faction->alliance
|| u->faction->alliance != f2->alliance) {
2010-08-08 10:06:34 +02:00
cmistake(u, ord, 315, MSG_EVENT);
return 0;
2011-03-07 08:02:35 +01:00
} else if (!alliedfaction(NULL, f, f2, HELP_MONEY)) {
2010-08-08 10:06:34 +02:00
cmistake(u, ord, 316, MSG_EVENT);
return 0;
} else {
variant var;
var.i = f2_id;
a_add(&f->attribs, object_create("quit", TINTEGER, var));
}
}
}
fset(f, FFL_QUIT);
} else {
char buffer[64];
write_order(ord, buffer, sizeof(buffer));
cmistake(u, ord, 86, MSG_EVENT);
log_warning("QUIT with illegal password for faction %s: %s\n", factionid(f), buffer);
2010-08-08 10:06:34 +02:00
}
return 0;
}
2011-03-07 08:02:35 +01:00
static void quit(void)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
faction **fptr = &factions;
2010-08-08 10:06:34 +02:00
while (*fptr) {
2011-03-07 08:02:35 +01:00
faction *f = *fptr;
2010-08-08 10:06:34 +02:00
if (f->flags & FFL_QUIT) {
if (EnhancedQuit()) {
/* this doesn't work well (use object_name()) */
2011-03-07 08:02:35 +01:00
attrib *a = a_find(f->attribs, &at_object);
2010-08-08 10:06:34 +02:00
if (a) {
variant var;
object_type type;
var.i = 0;
object_get(a, &type, &var);
2011-03-07 08:02:35 +01:00
assert(var.i && type == TINTEGER);
2010-08-08 10:06:34 +02:00
if (var.i) {
int f2_id = var.i;
faction *f2 = findfaction(f2_id);
2011-03-07 08:02:35 +01:00
assert(f2_id > 0);
assert(f2 != NULL);
2010-08-08 10:06:34 +02:00
transfer_faction(f, f2);
}
}
}
destroyfaction(f);
}
2011-03-07 08:02:35 +01:00
if (*fptr == f)
fptr = &f->next;
2010-08-08 10:06:34 +02:00
}
}
int dropouts[2];
2011-03-07 08:02:35 +01:00
int *age = NULL;
static void nmr_death(faction * f)
2010-08-08 10:06:34 +02:00
{
static int rule = -1;
2011-03-07 08:02:35 +01:00
if (rule < 0)
rule = get_param_int(global.parameters, "rules.nmr.destroy", 0);
2010-08-08 10:06:34 +02:00
if (rule) {
2011-03-07 08:02:35 +01:00
unit *u;
for (u = f->units; u; u = u->nextF) {
2010-08-08 10:06:34 +02:00
if (u->building && fval(u, UFL_OWNER)) {
remove_building(&u->region->buildings, u->building);
}
}
}
}
2011-03-07 08:02:35 +01:00
static void parse_restart(void)
2010-08-08 10:06:34 +02:00
{
region *r;
faction *f;
/* Sterben erst nachdem man allen anderen gegeben hat - bzw. man kann
2011-03-07 08:02:35 +01:00
* alles machen, was nicht ein drei<EFBFBD>igt<EFBFBD>giger Befehl ist. */
2010-08-08 10:06:34 +02:00
for (r = regions; r; r = r->next) {
2011-03-07 08:02:35 +01:00
unit *u, *un;
2010-08-08 10:06:34 +02:00
for (u = r->units; u;) {
2011-03-07 08:02:35 +01:00
order *ord;
2010-08-08 10:06:34 +02:00
un = u->next;
2011-03-07 08:02:35 +01:00
for (ord = u->orders; ord != NULL; ord = ord->next) {
2010-08-08 10:06:34 +02:00
if (get_keyword(ord) == K_RESTART) {
if (u->number > 0) {
2011-03-07 08:02:35 +01:00
if (restart_cmd(u, ord) != 0) {
2010-08-08 10:06:34 +02:00
break;
}
}
}
}
u = un;
}
}
2011-03-07 08:02:35 +01:00
if (verbosity >= 1)
puts
(" - beseitige Spieler, die sich zu lange nicht mehr gemeldet haben...");
2010-08-08 10:06:34 +02:00
for (f = factions; f; f = f->next) {
2011-03-07 08:02:35 +01:00
if (fval(f, FFL_NOIDLEOUT))
f->lastorders = turn;
if (NMRTimeout() > 0 && turn - f->lastorders >= NMRTimeout()) {
2010-08-08 10:06:34 +02:00
nmr_death(f);
destroyfaction(f);
continue;
}
if (fval(f, FFL_OVERRIDE)) {
free(f->override);
f->override = strdup(itoa36(rng_int()));
freset(f, FFL_OVERRIDE);
}
2011-03-07 08:02:35 +01:00
if (turn != f->lastorders) {
2010-08-08 10:06:34 +02:00
char info[256];
sprintf(info, "%d Einheiten, %d Personen, %d Silber",
f->no_units, f->num_total, f->money);
if (f->subscription) {
2011-03-07 08:02:35 +01:00
sql_print(
("UPDATE subscriptions SET lastturn=%d, password='%s', info='%s' WHERE id=%u;\n",
f->lastorders, f->override, info, f->subscription));
2010-08-08 10:06:34 +02:00
}
} else {
if (f->subscription) {
2011-03-07 08:02:35 +01:00
sql_print(
("UPDATE subscriptions SET status='ACTIVE', lastturn=%d, firstturn=greatest(firstturn,%d), password='%s' WHERE id=%u;\n",
f->lastorders, f->lastorders - f->age, f->override,
f->subscription));
2010-08-08 10:06:34 +02:00
}
}
2011-03-07 08:02:35 +01:00
if (NMRTimeout() > 0 && turn - f->lastorders >= (NMRTimeout() - 1)) {
2010-08-08 10:06:34 +02:00
inactivefaction(f);
continue;
}
}
2011-03-07 08:02:35 +01:00
if (verbosity >= 1) {
2010-08-08 10:06:34 +02:00
puts(" - beseitige Spieler, die sich nach der Anmeldung nicht "
"gemeldet haben...");
}
2011-03-07 08:02:35 +01:00
age = calloc(MAX(4, turn + 1), sizeof(int));
for (f = factions; f; f = f->next)
if (!is_monsters(f)) {
if (RemoveNMRNewbie() && !fval(f, FFL_NOIDLEOUT)) {
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;
}
2010-08-08 10:06:34 +02:00
}
}
}
2011-03-07 08:02:35 +01:00
if (verbosity >= 1)
puts(" - beseitige leere Einheiten und leere Parteien...");
2010-08-08 10:06:34 +02:00
remove_empty_units();
}
2011-03-07 08:02:35 +01:00
2010-08-08 10:06:34 +02:00
/* ------------------------------------------------------------- */
/* HELFE partei [<ALLES | SILBER | GIB | KAEMPFE | WAHRNEHMUNG>] [NICHT] */
2011-03-07 08:02:35 +01:00
static int ally_cmd(unit * u, struct order *ord)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
ally *sf, **sfp;
2010-08-08 10:06:34 +02:00
faction *f;
int keyword, not_kw;
const char *s;
init_tokens(ord);
skip_token();
f = getfaction();
2011-03-07 08:02:35 +01:00
if (f == NULL || is_monsters(f)) {
2010-08-08 10:06:34 +02:00
cmistake(u, ord, 66, MSG_EVENT);
return 0;
}
2011-03-07 08:02:35 +01:00
if (f == u->faction)
return 0;
2010-08-08 10:06:34 +02:00
s = getstrtoken();
if (!s[0])
keyword = P_ANY;
else
keyword = findparam(s, u->faction->locale);
sfp = &u->faction->allies;
if (fval(u, UFL_GROUP)) {
2011-03-07 08:02:35 +01:00
attrib *a = a_find(u->attribs, &at_group);
if (a)
sfp = &((group *) a->data.v)->allies;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
for (sf = *sfp; sf; sf = sf->next)
2010-08-08 10:06:34 +02:00
if (sf->faction == f)
2011-03-07 08:02:35 +01:00
break; /* Gleich die passende raussuchen, wenn vorhanden */
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
not_kw = getparam(u->faction->locale); /* HELFE partei [modus] NICHT */
2010-08-08 10:06:34 +02:00
if (!sf) {
if (keyword == P_NOT || not_kw == P_NOT) {
/* Wir helfen der Partei gar nicht... */
return 0;
} else {
sf = calloc(1, sizeof(ally));
sf->faction = f;
sf->status = 0;
addlist(sfp, sf);
}
}
switch (keyword) {
2011-03-08 08:44:20 +01:00
case P_NOT:
sf->status = 0;
break;
2011-03-07 08:02:35 +01:00
2011-03-08 08:44:20 +01:00
case NOPARAM:
cmistake(u, ord, 137, MSG_EVENT);
return 0;
2011-03-07 08:02:35 +01:00
2011-03-08 08:44:20 +01:00
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_GIVE:
if (not_kw == P_NOT)
sf->status = sf->status & (HELP_ALL - HELP_GIVE);
else
sf->status = sf->status | HELP_GIVE;
break;
case P_MONEY:
if (not_kw == P_NOT)
sf->status = sf->status & (HELP_ALL - HELP_MONEY);
else
sf->status = sf->status | HELP_MONEY;
break;
case P_FIGHT:
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;
case P_GUARD:
if (not_kw == P_NOT)
sf->status = sf->status & (HELP_ALL - HELP_GUARD);
else
sf->status = sf->status | HELP_GUARD;
break;
2010-08-08 10:06:34 +02:00
}
sf->status &= HelpMask();
2011-03-07 08:02:35 +01:00
if (sf->status == 0) { /* Alle HELPs geloescht */
2010-08-08 10:06:34 +02:00
removelist(sfp, sf);
}
return 0;
}
2011-03-07 08:02:35 +01:00
static struct local_names *pnames;
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
static void init_prefixnames(void)
2010-08-08 10:06:34 +02:00
{
int i;
2011-03-07 08:02:35 +01:00
for (i = 0; localenames[i]; ++i) {
const struct locale *lang = find_locale(localenames[i]);
2010-08-08 10:06:34 +02:00
boolean exist = false;
2011-03-07 08:02:35 +01:00
struct local_names *in = pnames;
while (in != NULL) {
if (in->lang == lang) {
2010-08-08 10:06:34 +02:00
exist = true;
break;
}
in = in->next;
}
2011-03-07 08:02:35 +01:00
if (in == NULL)
in = calloc(sizeof(local_names), 1);
2010-08-08 10:06:34 +02:00
in->next = pnames;
in->lang = lang;
if (!exist) {
int key;
2011-03-07 08:02:35 +01:00
for (key = 0; race_prefixes[key]; ++key) {
2010-08-08 10:06:34 +02:00
variant var;
2011-03-07 08:02:35 +01:00
const char *pname =
locale_string(lang, mkname("prefix", race_prefixes[key]));
if (findtoken(in->names, pname, &var) == E_TOK_NOMATCH || var.i != key) {
2010-08-08 10:06:34 +02:00
var.i = key;
addtoken(&in->names, pname, var);
2011-03-07 08:02:35 +01:00
addtoken(&in->names, locale_string(lang, mkname("prefix",
race_prefixes[key])), var);
2010-08-08 10:06:34 +02:00
}
}
}
pnames = in;
}
}
2011-03-07 08:02:35 +01:00
static int prefix_cmd(unit * u, struct order *ord)
2010-08-08 10:06:34 +02:00
{
attrib **ap;
const char *s;
2011-03-07 08:02:35 +01:00
local_names *in = pnames;
2010-08-08 10:06:34 +02:00
variant var;
2011-03-07 08:02:35 +01:00
const struct locale *lang = u->faction->locale;
while (in != NULL) {
if (in->lang == lang)
break;
2010-08-08 10:06:34 +02:00
in = in->next;
}
2011-03-07 08:02:35 +01:00
if (in == NULL) {
2010-08-08 10:06:34 +02:00
init_prefixnames();
2011-03-07 08:02:35 +01:00
for (in = pnames; in->lang != lang; in = in->next) ;
2010-08-08 10:06:34 +02:00
}
init_tokens(ord);
skip_token();
s = getstrtoken();
if (!*s) {
attrib *a = NULL;
if (fval(u, UFL_GROUP)) {
a = a_find(u->attribs, &at_group);
}
if (a) {
2011-03-07 08:02:35 +01:00
group *g = (group *) a->data.v;
2010-08-08 10:06:34 +02:00
a_removeall(&g->attribs, &at_raceprefix);
} else {
a_removeall(&u->faction->attribs, &at_raceprefix);
}
return 0;
}
if (findtoken(in->names, s, &var) == E_TOK_NOMATCH) {
2010-08-08 10:06:34 +02:00
return 0;
} else if (race_prefixes[var.i] == NULL) {
cmistake(u, ord, 299, MSG_EVENT);
} else {
ap = &u->faction->attribs;
if (fval(u, UFL_GROUP)) {
2011-03-07 08:02:35 +01:00
attrib *a = a_find(u->attribs, &at_group);
group *g = (group *) a->data.v;
if (a)
ap = &g->attribs;
2010-08-08 10:06:34 +02:00
}
set_prefix(ap, race_prefixes[var.i]);
}
return 0;
}
2011-03-07 08:02:35 +01:00
static cmp_building_cb get_cmp_region_owner(void)
2010-08-08 10:06:34 +02:00
{
if (rule_region_owners()) {
return &cmp_current_owner;
} else {
return &cmp_wage;
}
}
2011-03-07 08:02:35 +01:00
static int display_cmd(unit * u, struct order *ord)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
building *b = u->building;
2010-08-08 10:06:34 +02:00
char **s = NULL;
const char *str;
2011-03-07 08:02:35 +01:00
region *r = u->region;
2010-08-08 10:06:34 +02:00
init_tokens(ord);
skip_token();
str = getstrtoken();
switch (findparam_ex(str, u->faction->locale)) {
2011-03-08 08:44:20 +01:00
case P_BUILDING:
case P_GEBAEUDE:
if (!b) {
cmistake(u, ord, 145, MSG_PRODUCE);
2010-08-08 10:06:34 +02:00
break;
2011-03-08 08:44:20 +01:00
}
if (!fval(u, UFL_OWNER)) {
cmistake(u, ord, 5, MSG_PRODUCE);
2010-08-08 10:06:34 +02:00
break;
2011-03-08 08:44:20 +01:00
}
if (!fval(b->type, BTF_NAMECHANGE) && b->display && b->display[0] != 0) {
cmistake(u, ord, 278, MSG_EVENT);
2011-03-07 08:02:35 +01:00
break;
2011-03-08 08:44:20 +01:00
}
s = &b->display;
break;
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
case P_SHIP:
if (!u->ship) {
cmistake(u, ord, 144, MSG_PRODUCE);
break;
2010-08-08 10:06:34 +02:00
}
2011-03-08 08:44:20 +01:00
if (!fval(u, UFL_OWNER)) {
cmistake(u, ord, 12, MSG_PRODUCE);
2010-08-08 10:06:34 +02:00
break;
2011-03-08 08:44:20 +01:00
}
s = &u->ship->display;
break;
2011-03-07 08:02:35 +01:00
2011-03-08 08:44:20 +01:00
case P_UNIT:
s = &u->display;
break;
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
case P_PRIVAT:
{
const char *d = getstrtoken();
if (d == NULL || *d == 0) {
usetprivate(u, NULL);
} else {
usetprivate(u, d);
}
}
break;
case P_REGION:
if (!b) {
cmistake(u, ord, 145, MSG_EVENT);
2011-03-07 08:02:35 +01:00
break;
2011-03-08 08:44:20 +01:00
}
if (!fval(u, UFL_OWNER)) {
cmistake(u, ord, 148, MSG_EVENT);
break;
}
if (b != largestbuilding(r, get_cmp_region_owner(), false)) {
cmistake(u, ord, 147, MSG_EVENT);
break;
}
s = &r->display;
break;
default:
cmistake(u, ord, 110, MSG_EVENT);
break;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
if (s != NULL) {
const char *s2 = getstrtoken();
2010-08-08 10:06:34 +02:00
free(*s);
*s = strdup(s2);
2011-03-07 08:02:35 +01:00
if (strlen(s2) >= DISPLAYSIZE) {
2010-08-08 10:06:34 +02:00
(*s)[DISPLAYSIZE] = 0;
}
}
return 0;
}
2011-03-09 06:16:47 +01:00
boolean renamed_building(const building * b)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
const struct locale *lang = locales;
size_t len = strlen(b->name);
2011-03-07 08:02:35 +01:00
for (; lang; lang = nextlocale(lang)) {
const char *bdname = LOC(lang, b->type->_name);
if (bdname) {
size_t bdlen = strlen(bdname);
if (len >= bdlen && strncmp(b->name, bdname, bdlen) == 0) {
return false;
}
2010-08-08 10:06:34 +02:00
}
}
return true;
}
2011-03-07 08:02:35 +01:00
static int rename_cmd(unit * u, order * ord, char **s, const char *s2)
2010-08-08 10:06:34 +02:00
{
if (!s2[0]) {
cmistake(u, ord, 84, MSG_EVENT);
return 0;
}
/* TODO: Validate to make sure people don't have illegal characters in
2011-03-07 08:02:35 +01:00
* names, phishing-style? () come to mind. */
2010-08-08 10:06:34 +02:00
free(*s);
*s = strdup(s2);
2011-03-07 08:02:35 +01:00
if (strlen(s2) >= NAMESIZE) {
2010-08-08 10:06:34 +02:00
(*s)[NAMESIZE] = 0;
}
return 0;
}
2011-03-09 06:16:47 +01:00
int
2011-03-07 08:02:35 +01:00
rename_building(unit * u, order * ord, building * b, const char *name)
{
unit *owner = b ? building_owner(b) : 0;
boolean foreign = !(owner && owner->faction == u->faction);
2010-08-08 10:06:34 +02:00
if (!b) {
2011-03-07 08:02:35 +01:00
cmistake(u, ord, u->building ? 6 : 145, MSG_EVENT);
2010-08-08 10:06:34 +02:00
return -1;
}
if (!fval(b->type, BTF_NAMECHANGE) && renamed_building(b)) {
cmistake(u, ord, 278, MSG_EVENT);
return -1;
}
if (foreign) {
2011-03-07 08:02:35 +01:00
if (renamed_building(b)) {
2010-08-08 10:06:34 +02:00
cmistake(u, ord, 246, MSG_EVENT);
return -1;
}
if (owner) {
if (cansee(owner->faction, u->region, u, 0)) {
2011-03-08 08:44:20 +01:00
ADDMSG(&owner->faction->msgs,
msg_message("renamed_building_seen",
2011-03-07 08:02:35 +01:00
"building renamer region", b, u, u->region));
2010-08-08 10:06:34 +02:00
} else {
2011-03-08 08:44:20 +01:00
ADDMSG(&owner->faction->msgs,
msg_message("renamed_building_notseen",
2011-03-07 08:02:35 +01:00
"building region", b, u->region));
2010-08-08 10:06:34 +02:00
}
}
} else {
if (!fval(u, UFL_OWNER)) {
cmistake(u, ord, 148, MSG_PRODUCE);
return -1;
}
}
return rename_cmd(u, ord, &b->name, name);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
static int name_cmd(unit * u, struct order *ord)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
building *b = u->building;
region *r = u->region;
2010-08-08 10:06:34 +02:00
char **s = NULL;
param_t p;
boolean foreign = false;
const char *str;
2010-08-08 10:06:34 +02:00
init_tokens(ord);
skip_token();
str = getstrtoken();
p = findparam_ex(str, u->faction->locale);
2010-08-08 10:06:34 +02:00
if (p == P_FOREIGN) {
str = getstrtoken();
2010-08-08 10:06:34 +02:00
foreign = true;
p = findparam_ex(str, u->faction->locale);
2010-08-08 10:06:34 +02:00
}
switch (p) {
2011-03-08 08:44:20 +01:00
case P_ALLIANCE:
if (foreign == false && f_get_alliance(u->faction)) {
alliance *al = u->faction->alliance;
faction *lead = alliance_get_leader(al);
if (lead == u->faction) {
s = &al->name;
2011-03-07 08:02:35 +01:00
}
2011-03-08 08:44:20 +01:00
}
break;
case P_BUILDING:
case P_GEBAEUDE:
if (foreign) {
b = getbuilding(u->region);
}
2011-03-07 08:02:35 +01:00
2011-03-08 08:44:20 +01:00
return rename_building(u, ord, b, getstrtoken());
2011-03-07 08:02:35 +01:00
2011-03-08 08:44:20 +01:00
case P_FACTION:
if (foreign == true) {
faction *f;
2011-03-07 08:02:35 +01:00
2011-03-08 08:44:20 +01:00
f = getfaction();
if (!f) {
cmistake(u, ord, 66, MSG_EVENT);
break;
}
if (f->age < 10) {
cmistake(u, ord, 248, MSG_EVENT);
break;
} else {
const struct locale *lang = locales;
for (; lang; lang = nextlocale(lang)) {
const char *fdname = LOC(lang, "factiondefault");
size_t fdlen = strlen(fdname);
if (strlen(f->name) >= fdlen && strncmp(f->name, fdname, fdlen) == 0) {
2010-08-08 10:06:34 +02:00
break;
}
}
2011-03-08 08:44:20 +01:00
if (lang == NULL) {
cmistake(u, ord, 247, MSG_EVENT);
break;
2010-08-08 10:06:34 +02:00
}
2011-03-08 08:44:20 +01:00
}
if (cansee(f, r, u, 0)) {
ADDMSG(&f->msgs,
msg_message("renamed_faction_seen", "unit region", u, r));
2010-08-08 10:06:34 +02:00
} else {
2011-03-08 08:44:20 +01:00
ADDMSG(&f->msgs, msg_message("renamed_faction_notseen", "", r));
2010-08-08 10:06:34 +02:00
}
2011-03-08 08:44:20 +01:00
s = &f->name;
} else {
s = &u->faction->name;
}
break;
2011-03-07 08:02:35 +01:00
2011-03-08 08:44:20 +01:00
case P_SHIP:
if (foreign == true) {
ship *sh = getship(r);
unit *uo;
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
if (!sh) {
cmistake(u, ord, 20, MSG_EVENT);
break;
} else {
const struct locale *lang = locales;
for (; lang; lang = nextlocale(lang)) {
const char *sdname = LOC(lang, sh->type->name[0]);
size_t sdlen = strlen(sdname);
if (strlen(sh->name) >= sdlen
&& strncmp(sh->name, sdname, sdlen) == 0) {
2010-08-08 10:06:34 +02:00
break;
}
2011-03-08 08:44:20 +01:00
sdname = LOC(lang, parameters[P_SHIP]);
sdlen = strlen(sdname);
if (strlen(sh->name) >= sdlen
&& strncmp(sh->name, sdname, sdlen) == 0) {
break;
2011-03-07 08:02:35 +01:00
}
2011-03-08 08:44:20 +01:00
2011-03-07 08:02:35 +01:00
}
2011-03-08 08:44:20 +01:00
if (lang == NULL) {
cmistake(u, ord, 245, MSG_EVENT);
2011-03-07 08:02:35 +01:00
break;
}
2010-08-08 10:06:34 +02:00
}
uo = ship_owner(sh);
2011-03-08 08:44:20 +01:00
if (uo) {
if (cansee(uo->faction, r, u, 0)) {
ADDMSG(&uo->faction->msgs,
msg_message("renamed_ship_seen", "ship renamer region", sh, u, r));
2010-08-08 10:06:34 +02:00
} else {
2011-03-08 08:44:20 +01:00
ADDMSG(&uo->faction->msgs,
msg_message("renamed_ship_notseen", "ship region", sh, r));
2010-08-08 10:06:34 +02:00
}
}
2011-03-08 08:44:20 +01:00
s = &sh->name;
} else {
if (!u->ship) {
cmistake(u, ord, 144, MSG_PRODUCE);
2010-08-08 10:06:34 +02:00
break;
}
if (!fval(u, UFL_OWNER)) {
2011-03-08 08:44:20 +01:00
cmistake(u, ord, 12, MSG_PRODUCE);
2010-08-08 10:06:34 +02:00
break;
}
2011-03-08 08:44:20 +01:00
s = &u->ship->name;
}
break;
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
case P_UNIT:
if (foreign == true) {
unit *u2 = getunit(r, u->faction);
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
if (!u2 || !cansee(u->faction, r, u2, 0)) {
ADDMSG(&u->faction->msgs, msg_feedback(u, ord,
"feedback_unit_not_found", ""));
2010-08-08 10:06:34 +02:00
break;
} else {
2011-03-08 08:44:20 +01:00
const char *udefault = LOC(u2->faction->locale, "unitdefault");
size_t udlen = strlen(udefault);
size_t unlen = strlen(u2->name);
if (unlen >= udlen && strncmp(u2->name, udefault, udlen) != 0) {
cmistake(u2, ord, 244, MSG_EVENT);
break;
}
}
if (cansee(u2->faction, r, u, 0)) {
ADDMSG(&u2->faction->msgs, msg_message("renamed_seen",
"renamer renamed region", u, u2, r));
} else {
ADDMSG(&u2->faction->msgs, msg_message("renamed_notseen",
"renamed region", u2, r));
2010-08-08 10:06:34 +02:00
}
2011-03-08 08:44:20 +01:00
s = &u2->name;
} else {
s = &u->name;
2010-08-08 10:06:34 +02:00
}
2011-03-08 08:44:20 +01:00
break;
case P_REGION:
if (!b) {
cmistake(u, ord, 145, MSG_EVENT);
2011-03-07 08:02:35 +01:00
break;
2011-03-08 08:44:20 +01:00
}
if (!fval(u, UFL_OWNER)) {
cmistake(u, ord, 148, MSG_EVENT);
break;
}
if (b != largestbuilding(r, get_cmp_region_owner(), false)) {
cmistake(u, ord, 147, MSG_EVENT);
break;
}
s = &r->land->name;
break;
case P_GROUP:
{
attrib *a = NULL;
if (fval(u, UFL_GROUP))
a = a_find(u->attribs, &at_group);
if (a) {
group *g = (group *) a->data.v;
s = &g->name;
break;
} else {
2011-03-07 08:02:35 +01:00
cmistake(u, ord, 109, MSG_EVENT);
break;
2011-03-08 08:44:20 +01:00
}
}
break;
default:
cmistake(u, ord, 109, MSG_EVENT);
break;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
if (s != NULL) {
2010-08-08 10:06:34 +02:00
return rename_cmd(u, ord, s, getstrtoken());
}
return 0;
}
2011-03-07 08:02:35 +01:00
2010-08-08 10:06:34 +02:00
/* ------------------------------------------------------------- */
void
deliverMail(faction * f, region * r, unit * u, const char *s, unit * receiver)
{
if (!cansee(f, r, u, 0)) {
u = NULL;
}
2011-03-07 08:02:35 +01:00
if (!receiver) { /* BOTSCHAFT an PARTEI */
2011-03-08 08:44:20 +01:00
ADDMSG(&f->msgs,
msg_message("regionmessage", "region sender string", r, u, s));
2011-03-07 08:02:35 +01:00
} else { /* BOTSCHAFT an EINHEIT */
2011-03-08 08:44:20 +01:00
ADDMSG(&f->msgs,
msg_message("unitmessage", "region unit sender string", r,
2011-03-07 08:02:35 +01:00
receiver, u, s));
2010-08-08 10:06:34 +02:00
}
}
static void
2011-03-07 08:02:35 +01:00
mailunit(region * r, unit * u, int n, struct order *ord, const char *s)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
unit *u2 = findunitr(r, n);
2010-08-08 10:06:34 +02:00
if (u2 && cansee(u->faction, r, u2, 0)) {
deliverMail(u2->faction, r, u, s, u2);
/* now done in prepare_mail_cmd */
2011-03-07 08:02:35 +01:00
} else {
2010-08-08 10:06:34 +02:00
/* Immer eine Meldung - sonst k<>nnte man so getarnte EHs enttarnen:
2011-03-07 08:02:35 +01:00
* keine Meldung -> EH hier. */
2011-03-08 08:44:20 +01:00
ADDMSG(&u->faction->msgs,
msg_feedback(u, ord, "feedback_unit_not_found", ""));
2010-08-08 10:06:34 +02:00
}
}
2011-03-07 08:02:35 +01:00
static void mailfaction(unit * u, int n, struct order *ord, const char *s)
2010-08-08 10:06:34 +02:00
{
faction *f;
f = findfaction(n);
2011-03-07 08:02:35 +01:00
if (f && n > 0)
2010-08-08 10:06:34 +02:00
deliverMail(f, u->region, u, s, NULL);
else
cmistake(u, ord, 66, MSG_MESSAGE);
}
2011-03-07 08:02:35 +01:00
static int mail_cmd(unit * u, struct order *ord)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
region *r = u->region;
2010-08-08 10:06:34 +02:00
unit *u2;
const char *s;
int n, cont;
init_tokens(ord);
2011-03-07 08:02:35 +01:00
skip_token(); /* skip the keyword */
2010-08-08 10:06:34 +02:00
s = getstrtoken();
/* Falls kein Parameter, ist das eine Einheitsnummer;
2011-03-07 08:02:35 +01:00
* das F<EFBFBD>llwort "AN" mu<EFBFBD> wegfallen, da g<EFBFBD>ltige Nummer! */
2010-08-08 10:06:34 +02:00
do {
cont = 0;
switch (findparam_ex(s, u->faction->locale)) {
2011-03-08 08:44:20 +01:00
case P_REGION:
/* k<>nnen alle Einheiten in der Region sehen */
s = getstrtoken();
if (!s[0]) {
cmistake(u, ord, 30, MSG_MESSAGE);
break;
} else {
ADDMSG(&r->msgs, msg_message("mail_result", "unit message", u, s));
return 0;
}
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
case P_FACTION:
{
boolean see = false;
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
n = getfactionid();
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
for (u2 = r->units; u2; u2 = u2->next) {
if (u2->faction->no == n && seefaction(u->faction, r, u2, 0)) {
see = true;
2010-08-08 10:06:34 +02:00
break;
}
2011-03-08 08:44:20 +01:00
}
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
if (see == false) {
cmistake(u, ord, 66, MSG_MESSAGE);
break;
2010-08-08 10:06:34 +02:00
}
2011-03-08 08:44:20 +01:00
s = getstrtoken();
if (!s[0]) {
cmistake(u, ord, 30, MSG_MESSAGE);
break;
}
mailfaction(u, n, ord, s);
return 0;
}
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
case P_UNIT:
{
boolean see = false;
n = getid();
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
for (u2 = r->units; u2; u2 = u2->next) {
if (u2->no == n && cansee(u->faction, r, u2, 0)) {
see = true;
break;
2010-08-08 10:06:34 +02:00
}
2011-03-08 08:44:20 +01:00
}
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
if (see == false) {
ADDMSG(&u->faction->msgs, msg_feedback(u, ord,
"feedback_unit_not_found", ""));
return 0;
}
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
s = getstrtoken();
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);
2010-08-08 10:06:34 +02:00
}
2011-03-08 08:44:20 +01:00
mailunit(r, u, n, ord, s);
2010-08-08 10:06:34 +02:00
}
2011-03-08 08:44:20 +01:00
return 0;
}
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
case P_BUILDING:
case P_GEBAEUDE:
{
building *b = getbuilding(r);
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
if (!b) {
cmistake(u, ord, 6, MSG_MESSAGE);
break;
}
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
s = getstrtoken();
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
if (!s[0]) {
cmistake(u, ord, 30, MSG_MESSAGE);
break;
}
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
for (u2 = r->units; u2; u2 = u2->next)
freset(u2->faction, FFL_SELECT);
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
for (u2 = r->units; u2; u2 = u2->next) {
if (u2->building == b && !fval(u2->faction, FFL_SELECT)
&& cansee(u->faction, r, u2, 0)) {
mailunit(r, u, u2->no, ord, s);
fset(u2->faction, FFL_SELECT);
2010-08-08 10:06:34 +02:00
}
}
2011-03-08 08:44:20 +01:00
return 0;
}
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
case P_SHIP:
{
ship *sh = getship(r);
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
if (!sh) {
cmistake(u, ord, 20, MSG_MESSAGE);
break;
}
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
s = getstrtoken();
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
if (!s[0]) {
cmistake(u, ord, 30, MSG_MESSAGE);
break;
}
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
for (u2 = r->units; u2; u2 = u2->next)
freset(u2->faction, FFL_SELECT);
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
for (u2 = r->units; u2; u2 = u2->next) {
if (u2->ship == sh && !fval(u2->faction, FFL_SELECT)
&& cansee(u->faction, r, u2, 0)) {
mailunit(r, u, u2->no, ord, s);
fset(u2->faction, FFL_SELECT);
2010-08-08 10:06:34 +02:00
}
}
2011-03-08 08:44:20 +01:00
return 0;
}
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
default:
/* possibly filler token? */
s = getstrtoken();
if (s && *s)
cont = 1;
break;
2010-08-08 10:06:34 +02:00
}
2011-03-08 08:44:20 +01:00
}
while (cont);
2010-08-08 10:06:34 +02:00
cmistake(u, ord, 149, MSG_MESSAGE);
return 0;
}
2011-03-07 08:02:35 +01:00
2010-08-08 10:06:34 +02:00
/* ------------------------------------------------------------- */
2011-03-07 08:02:35 +01:00
static int banner_cmd(unit * u, struct order *ord)
2010-08-08 10:06:34 +02:00
{
init_tokens(ord);
skip_token();
free(u->faction->banner);
u->faction->banner = strdup(getstrtoken());
add_message(&u->faction->msgs, msg_message("changebanner", "value",
2011-03-07 08:02:35 +01:00
u->faction->banner));
2010-08-08 10:06:34 +02:00
return 0;
}
2011-03-07 08:02:35 +01:00
static int email_cmd(unit * u, struct order *ord)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
const char *s;
2010-08-08 10:06:34 +02:00
init_tokens(ord);
skip_token();
s = getstrtoken();
if (!s[0]) {
cmistake(u, ord, 85, MSG_EVENT);
} else {
2011-03-07 08:02:35 +01:00
faction *f = u->faction;
if (set_email(&f->email, (const char *)s) != 0) {
log_error("Invalid email address for faction %s: %s\n", itoa36(f->no), s);
2010-08-08 10:06:34 +02:00
ADDMSG(&f->msgs, msg_message("changemail_invalid", "value", s));
} else {
ADDMSG(&f->msgs, msg_message("changemail", "value", f->email));
}
}
return 0;
}
2011-03-07 08:02:35 +01:00
static int password_cmd(unit * u, struct order *ord)
2010-08-08 10:06:34 +02:00
{
char pwbuf[32];
int i;
2011-03-07 08:02:35 +01:00
const char *s;
2010-08-08 10:06:34 +02:00
boolean pwok = true;
init_tokens(ord);
skip_token();
s = getstrtoken();
if (!s || !*s) {
2011-03-07 08:02:35 +01:00
for (i = 0; i < 6; i++)
pwbuf[i] = (char)(97 + rng_int() % 26);
2010-08-08 10:06:34 +02:00
pwbuf[6] = 0;
} else {
char *c;
strlcpy(pwbuf, (const char *)s, 31);
pwbuf[31] = 0;
c = pwbuf;
while (*c && pwok) {
2011-03-07 08:02:35 +01:00
if (!isalnum(*(unsigned char *)c))
pwok = false;
2010-08-08 10:06:34 +02:00
c++;
}
}
free(u->faction->passw);
if (pwok == false) {
cmistake(u, ord, 283, MSG_EVENT);
u->faction->passw = strdup(itoa36(rng_int()));
} else {
u->faction->passw = strdup(pwbuf);
}
fset(u->faction, FFL_OVERRIDE);
ADDMSG(&u->faction->msgs, msg_message("changepasswd",
2011-03-07 08:02:35 +01:00
"value", u->faction->passw));
2010-08-08 10:06:34 +02:00
return 0;
}
2011-03-07 08:02:35 +01:00
static int send_cmd(unit * u, struct order *ord)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
const char *s;
2010-08-08 10:06:34 +02:00
int option;
init_tokens(ord);
skip_token();
s = getstrtoken();
option = findoption(s, u->faction->locale);
if (option == -1) {
cmistake(u, ord, 135, MSG_EVENT);
} else {
if (getparam(u->faction->locale) == P_NOT) {
if (option == O_COMPRESS || option == O_BZIP2) {
cmistake(u, ord, 305, MSG_EVENT);
} else {
2011-03-07 08:02:35 +01:00
u->faction->options = u->faction->options & ~(1 << option);
2010-08-08 10:06:34 +02:00
}
} else {
2011-03-07 08:02:35 +01:00
u->faction->options = u->faction->options | (1 << option);
if (option == O_COMPRESS)
u->faction->options &= ~(1 << O_BZIP2);
if (option == O_BZIP2)
u->faction->options &= ~(1 << O_COMPRESS);
2010-08-08 10:06:34 +02:00
}
}
return 0;
}
2011-03-07 08:02:35 +01:00
static boolean display_item(faction * f, unit * u, const item_type * itype)
2010-08-08 10:06:34 +02:00
{
const char *name;
const char *key;
const char *info;
2011-03-07 08:02:35 +01:00
if (u != NULL) {
2010-08-08 10:06:34 +02:00
int i = i_get(u->items, itype);
2011-03-07 08:02:35 +01:00
if (i == 0) {
if (u->region->land != NULL) {
2010-08-08 10:06:34 +02:00
i = i_get(u->region->land->items, itype);
}
2011-03-07 08:02:35 +01:00
if (i == 0) {
2010-08-08 10:06:34 +02:00
i = i_get(u->faction->items, itype);
2011-03-07 08:02:35 +01:00
if (i == 0)
return false;
2010-08-08 10:06:34 +02:00
}
}
}
name = resourcename(itype->rtype, 0);
key = mkname("iteminfo", name);
info = locale_getstring(f->locale, key);
2011-03-07 08:02:35 +01:00
if (info == NULL) {
2010-08-08 10:06:34 +02:00
info = locale_string(f->locale, mkname("iteminfo", "no_info"));
}
ADDMSG(&f->msgs, msg_message("displayitem", "weight item description",
2011-03-07 08:02:35 +01:00
itype->weight, itype->rtype, info));
2010-08-08 10:06:34 +02:00
return true;
}
2011-03-07 08:02:35 +01:00
static boolean display_potion(faction * f, unit * u, const potion_type * ptype)
2010-08-08 10:06:34 +02:00
{
attrib *a;
2011-03-07 08:02:35 +01:00
if (ptype == NULL)
return false;
2010-08-08 10:06:34 +02:00
else {
int i = i_get(u->items, ptype->itype);
2011-03-07 08:02:35 +01:00
if (i == 0 && 2 * ptype->level > effskill(u, SK_ALCHEMY)) {
2010-08-08 10:06:34 +02:00
return false;
}
}
a = a_find(f->attribs, &at_showitem);
2011-03-07 08:02:35 +01:00
while (a && a->data.v != ptype)
a = a->next;
2010-08-08 10:06:34 +02:00
if (!a) {
a = a_add(&f->attribs, a_new(&at_showitem));
2011-03-07 08:02:35 +01:00
a->data.v = (void *)ptype->itype;
2010-08-08 10:06:34 +02:00
}
return true;
}
2011-03-07 08:02:35 +01:00
static boolean display_race(faction * f, unit * u, const race * rc)
2010-08-08 10:06:34 +02:00
{
const char *name, *key;
const char *info;
int a, at_count;
2011-03-07 08:02:35 +01:00
char buf[2048], *bufp = buf;
2010-08-08 10:06:34 +02:00
size_t size = sizeof(buf) - 1;
int bytes;
2011-03-07 08:02:35 +01:00
if (u && u->race != rc)
return false;
2010-08-08 10:06:34 +02:00
name = rc_name(rc, 0);
bytes = slprintf(bufp, size, "%s: ", LOC(f->locale, name));
2011-03-07 08:02:35 +01:00
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();
2010-08-08 10:06:34 +02:00
key = mkname("raceinfo", rc->_name[0]);
info = locale_getstring(f->locale, key);
2011-03-07 08:02:35 +01:00
if (info == NULL) {
2010-08-08 10:06:34 +02:00
info = locale_string(f->locale, mkname("raceinfo", "no_info"));
}
bytes = (int)strlcpy(bufp, info, size);
2011-03-07 08:02:35 +01:00
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();
2010-08-08 10:06:34 +02:00
/* hp_p : Trefferpunkte */
2011-03-07 08:02:35 +01:00
bytes =
snprintf(bufp, size, " %d %s", rc->hitpoints, LOC(f->locale,
"stat_hitpoints"));
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();
2010-08-08 10:06:34 +02:00
/* b_attacke : Angriff */
2011-03-07 08:02:35 +01:00
bytes =
snprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_attack"),
(rc->at_default + rc->at_bonus));
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();
2010-08-08 10:06:34 +02:00
/* b_defense : Verteidigung */
2011-03-07 08:02:35 +01:00
bytes =
snprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_defense"),
(rc->df_default + rc->df_bonus));
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();
2010-08-08 10:06:34 +02:00
/* b_armor : R<>stung */
if (rc->armor > 0) {
2011-03-07 08:02:35 +01:00
bytes =
snprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_armor"), rc->armor);
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
if (size > 1) {
*bufp++ = '.';
2010-08-08 10:06:34 +02:00
--size;
2011-03-07 08:02:35 +01:00
} else
WARN_STATIC_BUFFER();
2010-08-08 10:06:34 +02:00
/* b_damage : Schaden */
2011-03-07 08:02:35 +01:00
at_count = 0;
2010-08-08 10:06:34 +02:00
for (a = 0; a < 6; a++) {
2011-03-07 08:02:35 +01:00
if (rc->attack[a].type != AT_NONE) {
2010-08-08 10:06:34 +02:00
at_count++;
}
}
if (rc->battle_flags & BF_EQUIPMENT) {
bytes = snprintf(bufp, size, " %s", LOC(f->locale, "stat_equipment"));
2011-03-07 08:02:35 +01:00
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();
2010-08-08 10:06:34 +02:00
}
if (rc->battle_flags & BF_RES_PIERCE) {
bytes = snprintf(bufp, size, " %s", LOC(f->locale, "stat_pierce"));
2011-03-07 08:02:35 +01:00
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();
2010-08-08 10:06:34 +02:00
}
if (rc->battle_flags & BF_RES_CUT) {
bytes = snprintf(bufp, size, " %s", LOC(f->locale, "stat_cut"));
2011-03-07 08:02:35 +01:00
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();
2010-08-08 10:06:34 +02:00
}
if (rc->battle_flags & BF_RES_BASH) {
bytes = snprintf(bufp, size, " %s", LOC(f->locale, "stat_bash"));
2011-03-07 08:02:35 +01:00
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
bytes =
snprintf(bufp, size, " %d %s", at_count, LOC(f->locale,
(at_count == 1) ? "stat_attack" : "stat_attacks"));
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();
2010-08-08 10:06:34 +02:00
for (a = 0; a < 6; a++) {
2011-03-07 08:02:35 +01:00
if (rc->attack[a].type != AT_NONE) {
if (a != 0)
bytes = (int)strlcpy(bufp, ", ", size);
else
bytes = (int)strlcpy(bufp, ": ", size);
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();
switch (rc->attack[a].type) {
2011-03-08 08:44:20 +01:00
case AT_STANDARD:
bytes =
snprintf(bufp, size, "%s (%s)",
LOC(f->locale, "attack_standard"), rc->def_damage);
break;
case AT_NATURAL:
bytes =
snprintf(bufp, size, "%s (%s)",
LOC(f->locale, "attack_natural"), rc->attack[a].data.dice);
break;
case AT_SPELL:
case AT_COMBATSPELL:
case AT_DRAIN_ST:
case AT_DAZZLE:
bytes = snprintf(bufp, size, "%s", LOC(f->locale, "attack_magical"));
break;
case AT_STRUCTURAL:
bytes =
snprintf(bufp, size, "%s (%s)",
LOC(f->locale, "attack_structural"), rc->attack[a].data.dice);
break;
default:
bytes = 0;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
if (bytes && wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();
2010-08-08 10:06:34 +02:00
}
}
2011-03-07 08:02:35 +01:00
if (size > 1) {
2010-08-08 10:06:34 +02:00
*bufp++ = '.';
--size;
2011-03-07 08:02:35 +01:00
} else
WARN_STATIC_BUFFER();
2010-08-08 10:06:34 +02:00
*bufp = 0;
addmessage(0, f, buf, MSG_EVENT, ML_IMPORTANT);
return true;
}
2011-03-07 08:02:35 +01:00
static void reshow(unit * u, struct order *ord, const char *s, param_t p)
2010-08-08 10:06:34 +02:00
{
int skill, c;
2011-03-07 08:02:35 +01:00
const potion_type *ptype;
const item_type *itype;
const spell *sp = 0;
2011-03-07 08:02:35 +01:00
const race *rc;
sc_mage * mage;
2010-08-08 10:06:34 +02:00
switch (p) {
2011-03-08 08:44:20 +01:00
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, ord, 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))
2011-03-07 08:02:35 +01:00
break;
2010-08-08 10:06:34 +02:00
}
2011-03-08 08:44:20 +01:00
}
/* try for a spell */
mage = get_mage(u);
if (mage) {
sp = get_spellfromtoken(mage, s, u->faction->locale);
}
if (sp) {
2011-03-08 08:44:20 +01:00
attrib *a = a_find(u->faction->attribs, &at_seenspell);
while (a != NULL && a->type == &at_seenspell && a->data.v != sp) {
2011-03-08 08:44:20 +01:00
a = a->next;
}
if (a != NULL) {
2011-03-08 08:44:20 +01:00
a_remove(&u->faction->attribs, a);
}
2010-08-08 10:06:34 +02:00
break;
2011-03-08 08:44:20 +01:00
}
/* 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, ord, 21, MSG_EVENT);
break;
default:
cmistake(u, ord, 222, MSG_EVENT);
break;
2010-08-08 10:06:34 +02:00
}
}
2011-03-07 08:02:35 +01:00
static int promotion_cmd(unit * u, struct order *ord)
2010-08-08 10:06:34 +02:00
{
int money, people;
if (fval(u, UFL_HERO)) {
/* TODO: message "is already a hero" */
return 0;
}
2011-03-07 08:02:35 +01:00
if (maxheroes(u->faction) < countheroes(u->faction) + u->number) {
2011-03-08 08:44:20 +01:00
ADDMSG(&u->faction->msgs,
msg_feedback(u, ord, "heroes_maxed", "max count",
2011-03-07 08:02:35 +01:00
maxheroes(u->faction), countheroes(u->faction)));
2010-08-08 10:06:34 +02:00
return 0;
}
if (!valid_race(u->faction, u->race)) {
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "heroes_race", "race",
2011-03-07 08:02:35 +01:00
u->race));
2010-08-08 10:06:34 +02:00
return 0;
}
people = count_all(u->faction) * u->number;
money = get_pooled(u, i_silver->rtype, GET_ALL, people);
2011-03-07 08:02:35 +01:00
if (people > money) {
2011-03-08 08:44:20 +01:00
ADDMSG(&u->faction->msgs,
msg_feedback(u, ord, "heroes_cost", "cost have", people, money));
2010-08-08 10:06:34 +02:00
return 0;
}
use_pooled(u, i_silver->rtype, GET_ALL, people);
fset(u, UFL_HERO);
ADDMSG(&u->faction->msgs, msg_message("hero_promotion", "unit cost",
2011-03-07 08:02:35 +01:00
u, people));
2010-08-08 10:06:34 +02:00
return 0;
}
2011-03-07 08:02:35 +01:00
static int group_cmd(unit * u, struct order *ord)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
const char *s;
2010-08-08 10:06:34 +02:00
init_tokens(ord);
skip_token();
s = getstrtoken();
join_group(u, s);
return 0;
}
2011-03-07 08:02:35 +01:00
static int origin_cmd(unit * u, struct order *ord)
2010-08-08 10:06:34 +02:00
{
short px, py;
init_tokens(ord);
skip_token();
px = (short)getint();
py = (short)getint();
set_ursprung(u->faction, getplaneid(u->region), px, py);
return 0;
}
2011-03-07 08:02:35 +01:00
static int guard_off_cmd(unit * u, struct order *ord)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
assert(get_keyword(ord) == K_GUARD);
2010-08-08 10:06:34 +02:00
init_tokens(ord);
skip_token();
if (getparam(u->faction->locale) == P_NOT) {
setguard(u, GUARD_NONE);
}
return 0;
}
2011-03-07 08:02:35 +01:00
static int reshow_cmd(unit * u, struct order *ord)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
const char *s;
2010-08-08 10:06:34 +02:00
param_t p = NOPARAM;
init_tokens(ord);
skip_token();
s = getstrtoken();
if (findparam(s, u->faction->locale) == P_ANY) {
p = getparam(u->faction->locale);
s = NULL;
}
reshow(u, ord, s, p);
return 0;
}
2011-03-07 08:02:35 +01:00
static int status_cmd(unit * u, struct order *ord)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
const char *param;
2010-08-08 10:06:34 +02:00
init_tokens(ord);
skip_token();
param = getstrtoken();
switch (findparam(param, u->faction->locale)) {
2011-03-08 08:44:20 +01:00
case P_NOT:
setstatus(u, ST_AVOID);
break;
case P_BEHIND:
setstatus(u, ST_BEHIND);
break;
case P_FLEE:
setstatus(u, ST_FLEE);
break;
case P_CHICKEN:
setstatus(u, ST_CHICKEN);
break;
case P_AGGRO:
setstatus(u, ST_AGGRO);
break;
case P_VORNE:
setstatus(u, ST_FIGHT);
break;
case P_HELP:
if (getparam(u->faction->locale) == P_NOT) {
fset(u, UFL_NOAID);
} else {
freset(u, UFL_NOAID);
}
break;
default:
if (param[0]) {
add_message(&u->faction->msgs,
msg_feedback(u, ord, "unknown_status", ""));
} else {
2010-08-08 10:06:34 +02:00
setstatus(u, ST_FIGHT);
2011-03-08 08:44:20 +01:00
}
2010-08-08 10:06:34 +02:00
}
return 0;
}
2011-03-07 08:02:35 +01:00
static int combatspell_cmd(unit * u, struct order *ord)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
const char *s;
2010-08-08 10:06:34 +02:00
int level = 0;
spell *sp = 0;
sc_mage * mage;
2010-08-08 10:06:34 +02:00
init_tokens(ord);
skip_token();
s = getstrtoken();
/* KAMPFZAUBER [NICHT] l<>scht alle gesetzten Kampfzauber */
if (!s || *s == 0 || findparam(s, u->faction->locale) == P_NOT) {
unset_combatspell(u, 0);
return 0;
}
/* Optional: STUFE n */
if (findparam(s, u->faction->locale) == P_LEVEL) {
/* Merken, setzen kommt erst sp<73>ter */
level = getint();
level = MAX(0, level);
s = getstrtoken();
}
mage = get_mage(u);
if (mage) {
sp = get_spellfromtoken(mage, s, u->faction->locale);
}
if (!sp) {
2010-08-08 10:06:34 +02:00
cmistake(u, ord, 173, MSG_MAGIC);
return 0;
}
s = getstrtoken();
if (findparam(s, u->faction->locale) == P_NOT) {
/* KAMPFZAUBER "<Spruchname>" NICHT l<>scht diesen speziellen
2011-03-07 08:02:35 +01:00
* Kampfzauber */
unset_combatspell(u, sp);
2010-08-08 10:06:34 +02:00
return 0;
} else {
/* KAMPFZAUBER "<Spruchname>" setzt diesen Kampfzauber */
set_combatspell(u, sp, ord, level);
2010-08-08 10:06:34 +02:00
}
return 0;
}
/* ------------------------------------------------------------- */
/* Beachten: einige Monster sollen auch unbewaffent die Region bewachen
* k<EFBFBD>nnen */
enum { E_GUARD_OK, E_GUARD_UNARMED, E_GUARD_NEWBIE, E_GUARD_FLEEING };
2011-03-07 08:02:35 +01:00
static int can_start_guarding(const unit * u)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
if (u->status >= ST_FLEE)
return E_GUARD_FLEEING;
if (fval(u->race, RCF_UNARMEDGUARD))
return E_GUARD_OK;
if (!armedmen(u, true))
return E_GUARD_UNARMED;
if (IsImmune(u->faction))
return E_GUARD_NEWBIE;
2010-08-08 10:06:34 +02:00
return E_GUARD_OK;
}
2011-03-07 08:02:35 +01:00
void update_guards(void)
2010-08-08 10:06:34 +02:00
{
const region *r;
for (r = regions; r; r = r->next) {
unit *u;
for (u = r->units; u; u = u->next) {
if (fval(u, UFL_GUARD)) {
2011-03-07 08:02:35 +01:00
if (can_start_guarding(u) != E_GUARD_OK) {
2010-08-08 10:06:34 +02:00
setguard(u, GUARD_NONE);
} else {
2011-03-07 08:02:35 +01:00
attrib *a = a_find(u->attribs, &at_guard);
if (a && a->data.i == (int)guard_flags(u)) {
2010-08-08 10:06:34 +02:00
/* this is really rather not necessary */
a_remove(&u->attribs, a);
}
}
}
}
}
}
2011-03-07 08:02:35 +01:00
static int guard_on_cmd(unit * u, struct order *ord)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
assert(get_keyword(ord) == K_GUARD);
2010-08-08 10:06:34 +02:00
init_tokens(ord);
skip_token();
/* GUARD NOT is handled in goard_off_cmd earlier in the turn */
2011-03-07 08:02:35 +01:00
if (getparam(u->faction->locale) == P_NOT)
return 0;
2010-08-08 10:06:34 +02:00
if (fval(u->region->terrain, SEA_REGION)) {
cmistake(u, ord, 2, MSG_EVENT);
} else {
if (fval(u, UFL_MOVED)) {
cmistake(u, ord, 187, MSG_EVENT);
2011-03-08 08:44:20 +01:00
} else if (fval(u->race, RCF_ILLUSIONARY)
|| u->race == new_race[RC_SPELL]) {
2010-08-08 10:06:34 +02:00
cmistake(u, ord, 95, MSG_EVENT);
} else {
/* Monster der Monsterpartei d<>rfen immer bewachen */
if (is_monsters(u->faction)) {
guard(u, GUARD_ALL);
} else {
int err = can_start_guarding(u);
2011-03-07 08:02:35 +01:00
if (err == E_GUARD_OK) {
2010-08-08 10:06:34 +02:00
guard(u, GUARD_ALL);
2011-03-07 08:02:35 +01:00
} else if (err == E_GUARD_UNARMED) {
2010-08-08 10:06:34 +02:00
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unit_unarmed", ""));
2011-03-07 08:02:35 +01:00
} else if (err == E_GUARD_FLEEING) {
2010-08-08 10:06:34 +02:00
cmistake(u, ord, 320, MSG_EVENT);
2011-03-07 08:02:35 +01:00
} else if (err == E_GUARD_NEWBIE) {
2010-08-08 10:06:34 +02:00
cmistake(u, ord, 304, MSG_EVENT);
}
}
}
}
return 0;
}
2011-03-07 08:02:35 +01:00
static void sinkships(region * r)
2010-08-08 10:06:34 +02:00
{
ship **shp = &r->ships;
while (*shp) {
2011-03-07 08:02:35 +01:00
ship *sh = *shp;
2011-03-07 08:02:35 +01:00
if (!sh->type->construction || sh->size >= sh->type->construction->maxsize) {
if (fval(r->terrain, SEA_REGION) && (!enoughsailors(sh, r)
|| get_captain(sh) == NULL)) {
/* Schiff nicht seet<65>chtig */
2011-03-08 08:44:20 +01:00
float dmg = get_param_flt(global.parameters,
"rules.ship.damage.nocrewocean",
2011-03-07 08:02:35 +01:00
0.30F);
2011-03-06 12:11:57 +01:00
damage_ship(sh, dmg);
}
if (ship_owner(sh) == NULL) {
2011-03-08 08:44:20 +01:00
float dmg = get_param_flt(global.parameters, "rules.ship.damage.nocrew",
0.05F);
2011-03-06 12:11:57 +01:00
damage_ship(sh, dmg);
}
2010-08-08 10:06:34 +02:00
}
if (sh->damage >= sh->size * DAMAGE_SCALE) {
remove_ship(shp, sh);
}
2011-03-07 08:02:35 +01:00
if (*shp == sh)
shp = &sh->next;
2010-08-08 10:06:34 +02:00
}
}
/* The following functions do not really belong here: */
#include <kernel/config.h>
#include <kernel/build.h>
static attrib_type at_number = {
"faction_renum",
NULL, NULL, NULL, NULL, NULL,
ATF_UNIQUE
};
2011-03-07 08:02:35 +01:00
static void renumber_factions(void)
2010-08-08 10:06:34 +02:00
/* gibt parteien neue nummern */
{
struct renum {
2011-03-07 08:02:35 +01:00
struct renum *next;
2010-08-08 10:06:34 +02:00
int want;
2011-03-07 08:02:35 +01:00
faction *faction;
attrib *attrib;
} *renum = NULL, *rp;
faction *f;
for (f = factions; f; f = f->next) {
attrib *a = a_find(f->attribs, &at_number);
2010-08-08 10:06:34 +02:00
int want;
2011-03-07 08:02:35 +01:00
struct renum **rn;
faction *old;
if (!a)
continue;
2010-08-08 10:06:34 +02:00
want = a->data.i;
if (fval(f, FFL_NEWID)) {
ADDMSG(&f->msgs, msg_message("renumber_twice", "id", want));
continue;
}
old = findfaction(want);
if (old) {
a_remove(&f->attribs, a);
ADDMSG(&f->msgs, msg_message("renumber_inuse", "id", want));
continue;
}
if (!faction_id_is_unused(want)) {
a_remove(&f->attribs, a);
ADDMSG(&f->msgs, msg_message("renumber_inuse", "id", want));
continue;
}
2011-03-07 08:02:35 +01:00
for (rn = &renum; *rn; rn = &(*rn)->next) {
if ((*rn)->want >= want)
break;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
if (*rn && (*rn)->want == want) {
2010-08-08 10:06:34 +02:00
ADDMSG(&f->msgs, msg_message("renumber_inuse", "id", want));
} else {
2011-03-07 08:02:35 +01:00
struct renum *r = calloc(sizeof(struct renum), 1);
2010-08-08 10:06:34 +02:00
r->next = *rn;
r->attrib = a;
r->faction = f;
r->want = want;
*rn = r;
}
}
2011-03-07 08:02:35 +01:00
for (rp = renum; rp; rp = rp->next) {
2010-08-08 10:06:34 +02:00
f = rp->faction;
a_remove(&f->attribs, rp->attrib);
renumber_faction(f, rp->want);
}
while (renum) {
rp = renum->next;
free(renum);
renum = rp;
}
}
2011-03-07 08:02:35 +01:00
static void reorder(void)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
region *r;
for (r = regions; r; r = r->next) {
unit **up = &r->units;
boolean sorted = false;
2010-08-08 10:06:34 +02:00
while (*up) {
2011-03-07 08:02:35 +01:00
unit *u = *up;
2010-08-08 10:06:34 +02:00
if (!fval(u, UFL_MARK)) {
2011-03-07 08:02:35 +01:00
struct order *ord;
for (ord = u->orders; ord; ord = ord->next) {
if (get_keyword(ord) == K_SORT) {
const char *s;
2010-08-08 10:06:34 +02:00
param_t p;
int id;
unit *v;
init_tokens(ord);
skip_token();
s = getstrtoken();
p = findparam(s, u->faction->locale);
id = getid();
v = findunit(id);
2011-03-07 08:02:35 +01:00
if (v == NULL || v->faction != u->faction || v->region != r) {
2010-08-08 10:06:34 +02:00
cmistake(u, ord, 258, MSG_EVENT);
2011-03-07 08:02:35 +01:00
} else if (v->building != u->building || v->ship != u->ship) {
2010-08-08 10:06:34 +02:00
cmistake(u, ord, 259, MSG_EVENT);
} else if (fval(u, UFL_OWNER)) {
cmistake(u, ord, 260, MSG_EVENT);
} else if (v == u) {
cmistake(u, ord, 10, MSG_EVENT);
} else {
2011-03-07 08:02:35 +01:00
switch (p) {
2011-03-08 08:44:20 +01:00
case P_AFTER:
*up = u->next;
u->next = v->next;
v->next = u;
fset(u, UFL_MARK);
sorted = true;
break;
case P_BEFORE:
if (fval(v, UFL_OWNER)) {
cmistake(v, ord, 261, MSG_EVENT);
} else {
unit **vp = &r->units;
while (*vp != v)
vp = &(*vp)->next;
*vp = u;
2010-08-08 10:06:34 +02:00
*up = u->next;
2011-03-08 08:44:20 +01:00
u->next = v;
}
fset(u, UFL_MARK);
sorted = true;
break;
default:
/* TODO: syntax error message? */
break;
2010-08-08 10:06:34 +02:00
}
}
break;
}
}
}
2011-03-07 08:02:35 +01:00
if (u == *up)
up = &u->next;
2010-08-08 10:06:34 +02:00
}
if (sorted) {
2011-03-07 08:02:35 +01:00
unit *u;
2011-03-08 08:44:20 +01:00
for (u = r->units; u; u = u->next) {
2011-03-07 08:02:35 +01:00
freset(u, UFL_MARK);
2011-03-08 08:44:20 +01:00
}
2010-08-08 10:06:34 +02:00
}
}
}
2011-03-07 08:02:35 +01:00
static int renumber_cmd(unit * u, order * ord)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
const char *s;
2010-08-08 10:06:34 +02:00
int i;
2011-03-07 08:02:35 +01:00
faction *f = u->faction;
2010-08-08 10:06:34 +02:00
init_tokens(ord);
skip_token();
s = getstrtoken();
switch (findparam_ex(s, u->faction->locale)) {
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
case P_FACTION:
s = getstrtoken();
if (s && *s) {
int id = atoi36((const char *)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;
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
case P_UNIT:
s = getstrtoken();
if (s == NULL || *s == 0) {
i = newunitid();
} else {
i = atoi36((const char *)s);
if (i <= 0 || i > MAX_UNIT_NR) {
cmistake(u, ord, 114, MSG_EVENT);
break;
2010-08-08 10:06:34 +02:00
}
2011-03-08 08:44:20 +01:00
if (forbiddenid(i)) {
cmistake(u, ord, 116, MSG_EVENT);
2010-08-08 10:06:34 +02:00
break;
}
2011-03-08 08:44:20 +01:00
if (findunitg(i, u->region)) {
cmistake(u, ord, 115, MSG_EVENT);
2010-08-08 10:06:34 +02:00
break;
}
2011-03-08 08:44:20 +01:00
}
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, ord, 144, MSG_EVENT);
break;
}
if (u->ship->coast != NODIRECTION) {
cmistake(u, ord, 116, 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((const char *)s);
if (i <= 0 || i > MAX_CONTAINER_NR) {
cmistake(u, ord, 114, MSG_EVENT);
2010-08-08 10:06:34 +02:00
break;
}
2011-03-08 08:44:20 +01:00
if (findship(i) || findbuilding(i)) {
cmistake(u, ord, 115, MSG_EVENT);
break;
2010-08-08 10:06:34 +02:00
}
2011-03-08 08:44:20 +01:00
}
sunhash(u->ship);
u->ship->no = i;
shash(u->ship);
break;
case P_BUILDING:
case P_GEBAEUDE:
if (!u->building) {
cmistake(u, ord, 145, MSG_EVENT);
2010-08-08 10:06:34 +02:00
break;
2011-03-08 08:44:20 +01:00
}
if (!fval(u, UFL_OWNER)) {
cmistake(u, ord, 148, MSG_EVENT);
break;
}
s = getstrtoken();
if (*s == 0) {
i = newcontainerid();
} else {
i = atoi36((const char *)s);
if (i <= 0 || i > MAX_CONTAINER_NR) {
cmistake(u, ord, 114, MSG_EVENT);
2010-08-08 10:06:34 +02:00
break;
}
2011-03-08 08:44:20 +01:00
if (findship(i) || findbuilding(i)) {
cmistake(u, ord, 115, MSG_EVENT);
2010-08-08 10:06:34 +02:00
break;
}
2011-03-08 08:44:20 +01:00
}
bunhash(u->building);
u->building->no = i;
bhash(u->building);
break;
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
default:
cmistake(u, ord, 239, MSG_EVENT);
2010-08-08 10:06:34 +02:00
}
return 0;
}
2011-03-07 08:02:35 +01:00
static building *age_building(building * b)
2010-08-08 10:06:34 +02:00
{
static boolean init = false;
2011-03-07 08:02:35 +01:00
static const building_type *bt_blessed;
static const curse_type *ct_astralblock;
2010-08-08 10:06:34 +02:00
if (!init) {
init = true;
bt_blessed = bt_find("blessedstonecircle");
ct_astralblock = ct_find("astralblock");
}
/* blesses stone circles create an astral protection in the astral region
* above the shield, which prevents chaos suction and other spells.
* The shield is created when a magician enters the blessed stone circle,
* and lasts for as long as his skill level / 2 is, at no mana cost.
*
* TODO: this would be nicer in a btype->age function, but we don't have it.
*/
2011-03-07 08:02:35 +01:00
if (ct_astralblock && bt_blessed && b->type == bt_blessed) {
region *r = b->region;
region *rt = r_standard_to_astral(r);
unit *u, *mage = NULL;
if (fval(rt->terrain, FORBIDDEN_REGION))
rt = NULL;
2010-08-08 10:06:34 +02:00
/* step 1: give unicorns to people in the building,
* find out if there's a magician in there. */
2011-03-07 08:02:35 +01:00
for (u = r->units; u; u = u->next) {
if (b == u->building && inside_building(u)) {
if (!(u->race->ec_flags & GIVEITEM) == 0) {
2010-08-08 10:06:34 +02:00
int n, unicorns = 0;
2011-03-07 08:02:35 +01:00
for (n = 0; n != u->number; ++n) {
2010-08-08 10:06:34 +02:00
if (chance(0.02)) {
i_change(&u->items, olditemtype[I_ELVENHORSE], 1);
++unicorns;
}
if (unicorns) {
2011-03-07 08:02:35 +01:00
ADDMSG(&u->faction->msgs, msg_message("scunicorn",
2011-03-08 08:44:20 +01:00
"unit amount rtype",
u, unicorns, olditemtype[I_ELVENHORSE]->rtype));
2010-08-08 10:06:34 +02:00
}
}
}
2011-03-07 08:02:35 +01:00
if (mage == NULL && is_mage(u)) {
2010-08-08 10:06:34 +02:00
mage = u;
}
}
}
/* if there's a magician, and a connection to astral space, create the
* curse. */
2011-03-07 08:02:35 +01:00
if (rt != NULL && mage != NULL) {
curse *c = get_curse(rt->attribs, ct_astralblock);
if (c == NULL) {
if (mage != NULL) {
2010-08-08 10:06:34 +02:00
int sk = effskill(mage, SK_MAGIC);
double effect;
effect = 100;
/* the mage reactivates the circle */
c = create_curse(mage, &rt->attribs, ct_astralblock,
2011-03-07 08:02:35 +01:00
(float)MAX(1, sk), MAX(1, sk / 2), effect, 0);
2011-03-08 08:44:20 +01:00
ADDMSG(&r->msgs,
msg_message("astralshield_activate", "region unit", r, mage));
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
} else if (mage != NULL) {
2010-08-08 10:06:34 +02:00
int sk = effskill(mage, SK_MAGIC);
2011-03-07 08:02:35 +01:00
c->duration = MAX(c->duration, sk / 2);
2010-08-08 10:06:34 +02:00
c->vigour = MAX(c->vigour, sk);
}
}
}
a_age(&b->attribs);
handle_event(b->attribs, "timer", b);
if (b->type->age) {
b->type->age(b);
}
return b;
}
2011-03-07 08:02:35 +01:00
static double rc_popularity(const struct race *rc)
2010-08-08 10:06:34 +02:00
{
int pop = get_param_int(rc->parameters, "morale", MORALE_AVERAGE);
2011-03-07 08:02:35 +01:00
return 1.0 / (pop - MORALE_COOLDOWN); /* 10 turns average */
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
static void age_region(region * r)
2010-08-08 10:06:34 +02:00
{
a_age(&r->attribs);
handle_event(r->attribs, "timer", r);
2011-03-07 08:02:35 +01:00
if (!r->land)
return;
2010-08-08 10:06:34 +02:00
if (r->land->ownership && r->land->ownership->owner) {
int stability = turn - r->land->ownership->morale_turn;
int maxmorale = MORALE_DEFAULT;
2011-03-07 08:02:35 +01:00
building *b = largestbuilding(r, &cmp_taxes, false);
2010-08-08 10:06:34 +02:00
if (b) {
int bsize = buildingeffsize(b, false);
2011-03-07 08:02:35 +01:00
maxmorale = (int)(0.5 + b->type->taxes(b, bsize + 1) / MORALE_TAX_FACTOR);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
if (r->land->morale < maxmorale) {
if (stability > MORALE_COOLDOWN && r->land->ownership->owner
&& r->land->morale < MORALE_MAX) {
2010-08-08 10:06:34 +02:00
double ch = rc_popularity(r->land->ownership->owner->race);
if (is_cursed(r->attribs, C_GENEROUS, 0)) {
2011-03-07 08:02:35 +01:00
ch *= 1.2; /* 20% improvement */
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
if (stability >= MORALE_AVERAGE * 2 || chance(ch)) {
region_set_morale(r, r->land->morale + 1, turn);
2010-08-08 10:06:34 +02:00
}
}
2011-03-07 08:02:35 +01:00
} else if (r->land->morale > maxmorale) {
region_set_morale(r, r->land->morale - 1, turn);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
} else if (r->land->morale > MORALE_DEFAULT) {
region_set_morale(r, r->land->morale - 1, turn);
2010-08-08 10:06:34 +02:00
}
}
2011-03-07 08:02:35 +01:00
static void ageing(void)
2010-08-08 10:06:34 +02:00
{
faction *f;
region *r;
/* altern spezieller Attribute, die eine Sonderbehandlung brauchen? */
2011-03-07 08:02:35 +01:00
for (r = regions; r; r = r->next) {
2010-08-08 10:06:34 +02:00
unit *u;
2011-03-07 08:02:35 +01:00
for (u = r->units; u; u = u->next) {
2010-08-08 10:06:34 +02:00
/* Goliathwasser */
int i = get_effect(u, oldpotiontype[P_STRONG]);
2011-03-07 08:02:35 +01:00
if (i > 0) {
2010-08-08 10:06:34 +02:00
change_effect(u, oldpotiontype[P_STRONG], -1 * MIN(u->number, i));
}
2011-03-07 08:02:35 +01:00
/* Berserkerblut */
2010-08-08 10:06:34 +02:00
i = get_effect(u, oldpotiontype[P_BERSERK]);
2011-03-07 08:02:35 +01:00
if (i > 0) {
2010-08-08 10:06:34 +02:00
change_effect(u, oldpotiontype[P_BERSERK], -1 * MIN(u->number, i));
}
2011-03-07 08:02:35 +01:00
if (is_cursed(u->attribs, C_OLDRACE, 0)) {
2010-08-08 10:06:34 +02:00
curse *c = get_curse(u->attribs, ct_find("oldrace"));
if (c->duration == 1 && !(c_flags(c) & CURSE_NOAGE)) {
u->race = new_race[curse_geteffect_int(c)];
u->irace = NULL;
}
}
}
}
/* Borders */
age_borders();
/* Factions */
2011-03-07 08:02:35 +01:00
for (f = factions; f; f = f->next) {
2010-08-08 10:06:34 +02:00
a_age(&f->attribs);
handle_event(f->attribs, "timer", f);
}
/* Regionen */
2011-03-07 08:02:35 +01:00
for (r = regions; r; r = r->next) {
building **bp;
unit **up;
ship **sp;
2010-08-08 10:06:34 +02:00
age_region(r);
/* Einheiten */
2011-03-07 08:02:35 +01:00
for (up = &r->units; *up;) {
unit *u = *up;
2010-08-08 10:06:34 +02:00
a_age(&u->attribs);
2011-03-07 08:02:35 +01:00
if (u == *up)
handle_event(u->attribs, "timer", u);
if (u == *up)
up = &(*up)->next;
2010-08-08 10:06:34 +02:00
}
/* Schiffe */
2011-03-07 08:02:35 +01:00
for (sp = &r->ships; *sp;) {
ship *s = *sp;
2010-08-08 10:06:34 +02:00
a_age(&s->attribs);
2011-03-07 08:02:35 +01:00
if (s == *sp)
handle_event(s->attribs, "timer", s);
if (s == *sp)
sp = &(*sp)->next;
2010-08-08 10:06:34 +02:00
}
/* Geb<65>ude */
2011-03-07 08:02:35 +01:00
for (bp = &r->buildings; *bp;) {
building *b = *bp;
2010-08-08 10:06:34 +02:00
age_building(b);
2011-03-07 08:02:35 +01:00
if (b == *bp)
bp = &b->next;
2010-08-08 10:06:34 +02:00
}
if (rule_region_owners()) {
update_owners(r);
}
}
}
2011-03-07 08:02:35 +01:00
static int maxunits(const faction * f)
2010-08-08 10:06:34 +02:00
{
int flimit = rule_faction_limit();
int alimit = rule_alliance_limit();
2011-03-07 08:02:35 +01:00
if (alimit == 0) {
2010-08-08 10:06:34 +02:00
return flimit;
}
2011-03-07 08:02:35 +01:00
if (flimit == 0) {
2010-08-08 10:06:34 +02:00
return alimit;
}
return MIN(alimit, flimit);
}
2011-03-07 08:02:35 +01:00
int checkunitnumber(const faction * f, int add)
2010-08-08 10:06:34 +02:00
{
int alimit, flimit;
alimit = rule_alliance_limit();
if (alimit) {
/* if unitsperalliance is true, maxunits returns the
2011-03-07 08:02:35 +01:00
number of units allowed in an alliance */
2010-08-08 10:06:34 +02:00
faction *f2;
int unitsinalliance = add;
for (f2 = factions; f2; f2 = f2->next) {
if (f->alliance == f2->alliance) {
unitsinalliance += f2->no_units;
}
if (unitsinalliance > alimit) {
return 1;
}
}
}
flimit = rule_faction_limit();
if (flimit) {
if (f->no_units + add > flimit) {
return 2;
}
}
return 0;
}
2011-03-07 08:02:35 +01:00
static void new_units(void)
2010-08-08 10:06:34 +02:00
{
region *r;
unit *u, *u2;
/* neue einheiten werden gemacht und ihre befehle (bis zum "ende" zu
2011-03-07 08:02:35 +01:00
* ihnen rueberkopiert, damit diese einheiten genauso wie die alten
* einheiten verwendet werden koennen. */
2010-08-08 10:06:34 +02:00
for (r = regions; r; r = r->next) {
for (u = r->units; u; u = u->next) {
2011-03-07 08:02:35 +01:00
order **ordp = &u->orders;
2010-08-08 10:06:34 +02:00
/* this needs to happen very early in the game somewhere. since this is
2011-03-07 08:02:35 +01:00
** pretty much the first function called per turn, and I am lazy, I
** decree that it goes here */
if (u->flags & UFL_GUARD) {
2010-08-08 10:06:34 +02:00
fset(r, RF_GUARDED);
}
while (*ordp) {
2011-03-07 08:02:35 +01:00
order *makeord = *ordp;
2010-08-08 10:06:34 +02:00
if (get_keyword(makeord) == K_MAKE) {
init_tokens(makeord);
skip_token();
if (isparam(getstrtoken(), u->faction->locale, P_TEMP)) {
2011-03-07 08:02:35 +01:00
const char *token;
char *name = NULL;
2010-08-08 10:06:34 +02:00
int alias;
2011-03-07 08:02:35 +01:00
ship *sh;
order **newordersp;
2010-08-08 10:06:34 +02:00
int err = checkunitnumber(u->faction, 1);
if (err) {
2011-03-07 08:02:35 +01:00
if (err == 1) {
2011-03-08 08:44:20 +01:00
ADDMSG(&u->faction->msgs,
msg_feedback(u, makeord,
"too_many_units_in_alliance",
"allowed", maxunits(u->faction)));
2010-08-08 10:06:34 +02:00
} else {
2011-03-08 08:44:20 +01:00
ADDMSG(&u->faction->msgs,
msg_feedback(u, makeord,
"too_many_units_in_faction",
"allowed", maxunits(u->faction)));
2010-08-08 10:06:34 +02:00
}
ordp = &makeord->next;
while (*ordp) {
2011-03-07 08:02:35 +01:00
order *ord = *ordp;
if (get_keyword(ord) == K_END)
break;
2010-08-08 10:06:34 +02:00
*ordp = ord->next;
ord->next = NULL;
free_order(ord);
}
continue;
}
alias = getid();
token = getstrtoken();
if (token && token[0]) {
name = strdup(token);
}
2011-03-07 08:02:35 +01:00
u2 =
create_unit(r, u->faction, 0, u->faction->race, alias, name, u);
if (name != NULL)
free(name);
2010-08-08 10:06:34 +02:00
fset(u2, UFL_ISNEW);
a_add(&u2->attribs, a_new(&at_alias))->data.i = alias;
sh = leftship(u);
if (sh) {
2011-03-07 08:02:35 +01:00
set_leftship(u2, sh);
}
2010-08-08 10:06:34 +02:00
setstatus(u2, u->status);
ordp = &makeord->next;
newordersp = &u2->orders;
while (*ordp) {
2011-03-07 08:02:35 +01:00
order *ord = *ordp;
if (get_keyword(ord) == K_END)
break;
2010-08-08 10:06:34 +02:00
*ordp = ord->next;
ord->next = NULL;
*newordersp = ord;
newordersp = &ord->next;
}
}
}
2011-03-07 08:02:35 +01:00
if (*ordp == makeord)
ordp = &makeord->next;
2010-08-08 10:06:34 +02:00
}
}
}
}
/** Checks for two long orders and issues a warning if necessary.
*/
2011-03-07 08:02:35 +01:00
void check_long_orders(unit * u)
{
order *ord;
keyword_t otherorder = MAXKEYWORDS;
for (ord = u->orders; ord; ord = ord->next) {
if (get_keyword(ord) == NOKEYWORD) {
cmistake(u, ord, 22, MSG_EVENT);
} else if (is_long(ord)) {
keyword_t longorder = get_keyword(ord);
if (otherorder != MAXKEYWORDS) {
switch (longorder) {
2011-03-08 08:44:20 +01:00
case K_CAST:
if (otherorder != longorder) {
cmistake(u, ord, 52, MSG_EVENT);
}
break;
case K_BUY:
if (otherorder == K_SELL) {
otherorder = K_BUY;
} else {
cmistake(u, ord, 52, MSG_EVENT);
2011-03-08 08:44:20 +01:00
}
break;
case K_SELL:
if (otherorder != K_SELL && otherorder != K_BUY) {
cmistake(u, ord, 52, MSG_EVENT);
}
break;
case K_WEREWOLF:
/* don't know what WEREWOLF does... */
default:
cmistake(u, ord, 52, MSG_EVENT);
}
} else {
otherorder = longorder;
}
}
}
}
2011-03-07 08:02:35 +01:00
static void setdefaults(unit * u)
2010-08-08 10:06:34 +02:00
{
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));
} else {
check_long_orders(u);
2010-08-08 10:06:34 +02:00
}
/* check all orders for a potential new long order this round: */
for (ord = u->orders; ord; ord = ord->next) {
if (get_keyword(ord) == NOKEYWORD)
continue;
2010-08-08 10:06:34 +02:00
if (u->old_orders && is_repeated(ord)) {
/* this new order will replace the old defaults */
free_orders(&u->old_orders);
2011-03-07 08:02:35 +01:00
if (hunger)
break;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
if (hunger)
continue;
2010-08-08 10:06:34 +02:00
if (is_exclusive(ord)) {
/* <20>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) {
2011-03-08 08:44:20 +01:00
/* Wenn gehandelt wird, darf kein langer Befehl ausgef<65>hrt
* werden. Da Handel erst nach anderen langen Befehlen kommt,
* mu<EFBFBD> das vorher abgefangen werden. Wir merken uns also
* hier, ob die Einheit handelt. */
case K_BUY:
case K_SELL:
/* Wenn die Einheit handelt, mu<6D> der Default-Befehl gel<65>scht
* werden. */
trade = true;
break;
2011-03-07 08:02:35 +01:00
2011-03-08 08:44:20 +01:00
case K_CAST:
/* dient dazu, das neben Zaubern kein weiterer Befehl
* ausgef<EFBFBD>hrt werden kann, Zaubern ist ein kurzer Befehl */
set_order(&u->thisorder, NULL);
break;
2011-03-07 08:02:35 +01:00
2011-03-08 08:44:20 +01:00
case K_WEREWOLF:
set_order(&u->thisorder, copy_order(ord));
break;
2011-03-07 08:02:35 +01:00
2011-03-08 08:44:20 +01:00
/* Wird je diese Ausschliesslichkeit aufgehoben, muss man aufpassen
* mit der Reihenfolge von Kaufen, Verkaufen etc., damit es Spielern
* nicht moeglich ist, Schulden zu machen. */
default:
break;
2010-08-08 10:06:34 +02:00
}
}
}
2011-03-08 08:44:20 +01:00
if (hunger) {
2011-03-07 08:02:35 +01:00
return;
2011-03-08 08:44:20 +01:00
}
2010-08-08 10:06:34 +02:00
/* Wenn die Einheit handelt, mu<6D> der Default-Befehl gel<65>scht
2011-03-07 08:02:35 +01:00
* werden. */
2010-08-08 10:06:34 +02:00
if (trade == true) {
/* fset(u, UFL_LONGACTION|UFL_NOTMOVING); */
set_order(&u->thisorder, NULL);
}
}
static int
2011-03-07 08:02:35 +01:00
use_item(unit * u, const item_type * itype, int amount, struct order *ord)
2010-08-08 10:06:34 +02:00
{
int i;
int target = read_unitid(u->faction, u->region);
i = get_pooled(u, itype->rtype, GET_DEFAULT, amount);
2011-03-07 08:02:35 +01:00
if (amount > i) {
2010-08-08 10:06:34 +02:00
amount = i;
}
2011-03-07 08:02:35 +01:00
if (amount == 0) {
2010-08-08 10:06:34 +02:00
cmistake(u, ord, 43, MSG_PRODUCE);
return ENOITEM;
}
2011-03-07 08:02:35 +01:00
if (target == -1) {
if (itype->use == NULL) {
2010-08-08 10:06:34 +02:00
cmistake(u, ord, 76, MSG_PRODUCE);
return EUNUSABLE;
}
return itype->use(u, itype, amount, ord);
} else {
2011-03-07 08:02:35 +01:00
if (itype->useonother == NULL) {
2010-08-08 10:06:34 +02:00
cmistake(u, ord, 76, MSG_PRODUCE);
return EUNUSABLE;
}
return itype->useonother(u, target, itype, amount, ord);
}
}
2011-03-07 08:02:35 +01:00
static double heal_factor(const unit * u)
2010-08-08 10:06:34 +02:00
{
static float elf_regen = -1;
2011-03-07 08:02:35 +01:00
switch (old_race(u->race)) {
2011-03-08 08:44:20 +01:00
case RC_TROLL:
case RC_DAEMON:
return 1.5;
case RC_GOBLIN:
return 2.0;
case RC_ELF:
if (elf_regen < 0)
elf_regen = get_param_flt(u->race->parameters, "regen.forest", 1.0F);
if (elf_regen != 1.0 && r_isforest(u->region)) {
return elf_regen;
}
return 1.0;
default:
return 1.0;
2010-08-08 10:06:34 +02:00
}
}
2011-03-07 08:02:35 +01:00
static void monthly_healing(void)
2010-08-08 10:06:34 +02:00
{
region *r;
2011-03-07 08:02:35 +01:00
static const curse_type *heal_ct = NULL;
if (heal_ct == NULL)
heal_ct = ct_find("healingzone");
2010-08-08 10:06:34 +02:00
for (r = regions; r; r = r->next) {
unit *u;
double healingcurse = 0;
2011-03-07 08:02:35 +01:00
if (heal_ct != NULL) {
2010-08-08 10:06:34 +02:00
/* bonus zur<75>cksetzen */
2011-03-07 08:02:35 +01:00
curse *c = get_curse(r->attribs, heal_ct);
if (c != NULL) {
2010-08-08 10:06:34 +02:00
healingcurse = curse_geteffect(c);
}
}
for (u = r->units; u; u = u->next) {
int umhp = unit_max_hp(u) * u->number;
double p = 1.0;
/* hp <20>ber Maximum bauen sich ab. Wird zb durch Elixier der Macht
2011-03-07 08:02:35 +01:00
* oder ver<EFBFBD>ndertes Ausdauertalent verursacht */
2010-08-08 10:06:34 +02:00
if (u->hp > umhp) {
2011-03-07 08:02:35 +01:00
u->hp -= (int)ceil((u->hp - umhp) / 2.0);
if (u->hp < umhp)
u->hp = umhp;
2010-08-08 10:06:34 +02:00
continue;
}
2011-03-07 08:02:35 +01:00
if (u->race->flags & RCF_NOHEAL)
continue;
if (fval(u, UFL_HUNGER))
continue;
2010-08-08 10:06:34 +02:00
2011-03-08 08:44:20 +01:00
if (fval(r->terrain, SEA_REGION) && u->ship == NULL
&& !(canswim(u) || canfly(u))) {
2010-08-08 10:06:34 +02:00
continue;
}
p *= heal_factor(u);
if (u->hp < umhp) {
#ifdef NEW_DAEMONHUNGER_RULE
2011-03-07 08:02:35 +01:00
double maxheal = MAX(u->number, umhp / 20.0);
2010-08-08 10:06:34 +02:00
#else
2011-03-07 08:02:35 +01:00
double maxheal = MAX(u->number, umhp / 10.0);
2010-08-08 10:06:34 +02:00
#endif
int addhp;
2011-03-07 08:02:35 +01:00
struct building *b = inside_building(u);
const struct building_type *btype = b ? b->type : NULL;
2010-08-08 10:06:34 +02:00
if (btype == bt_find("inn")) {
p *= 1.5;
}
/* pro punkt 5% h<>her */
p *= (1.0 + healingcurse * 0.05);
maxheal = p * maxheal;
addhp = (int)maxheal;
maxheal -= addhp;
2011-03-07 08:02:35 +01:00
if (maxheal > 0.0 && chance(maxheal))
++addhp;
2010-08-08 10:06:34 +02:00
/* Aufaddieren der geheilten HP. */
u->hp = MIN(u->hp + addhp, umhp);
/* soll man an negativer regeneration sterben k<>nnen? */
assert(u->hp > 0);
}
}
}
}
2011-03-07 08:02:35 +01:00
static void remove_exclusive(order ** ordp)
2010-08-08 10:06:34 +02:00
{
while (*ordp) {
2011-03-07 08:02:35 +01:00
order *ord = *ordp;
2010-08-08 10:06:34 +02:00
if (is_exclusive(ord)) {
*ordp = ord->next;
ord->next = NULL;
free_order(ord);
} else {
ordp = &ord->next;
}
}
}
2011-03-07 08:02:35 +01:00
static void defaultorders(void)
2010-08-08 10:06:34 +02:00
{
region *r;
2011-03-07 08:02:35 +01:00
for (r = regions; r; r = r->next) {
2010-08-08 10:06:34 +02:00
unit *u;
2011-03-07 08:02:35 +01:00
for (u = r->units; u; u = u->next) {
2010-08-08 10:06:34 +02:00
boolean neworders = false;
2011-03-07 08:02:35 +01:00
order **ordp = &u->orders;
while (*ordp != NULL) {
order *ord = *ordp;
if (get_keyword(ord) == K_DEFAULT) {
2010-08-08 10:06:34 +02:00
char lbuf[8192];
2011-03-07 08:02:35 +01:00
order *new_order;
2010-08-08 10:06:34 +02:00
init_tokens(ord);
2011-03-07 08:02:35 +01:00
skip_token(); /* skip the keyword */
2010-08-08 10:06:34 +02:00
strcpy(lbuf, getstrtoken());
new_order = parse_order(lbuf, u->faction->locale);
*ordp = ord->next;
ord->next = NULL;
free_order(ord);
if (!neworders) {
/* lange Befehle aus orders und old_orders l<>schen zu gunsten des neuen */
remove_exclusive(&u->orders);
remove_exclusive(&u->old_orders);
neworders = true;
2011-03-07 08:02:35 +01:00
ordp = &u->orders; /* we could have broken ordp */
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
if (new_order)
addlist(&u->old_orders, new_order);
} else
ordp = &ord->next;
2010-08-08 10:06:34 +02:00
}
}
}
}
/* ************************************************************ */
/* GANZ WICHTIG! ALLE GE<47>NDERTEN SPR<50>CHE NEU ANZEIGEN */
/* GANZ WICHTIG! F<>GT AUCH NEUE ZAUBER IN DIE LISTE DER BEKANNTEN EIN */
/* ************************************************************ */
2011-03-07 08:02:35 +01:00
#define MAXMAGES 128 /* should be enough */
static void update_spells(void)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
faction *f;
for (f = factions; f; f = f->next) {
if (f->magiegebiet != M_NONE && !is_monsters(f)) {
unit *mages[MAXMAGES];
2010-08-08 10:06:34 +02:00
unit *u;
int maxlevel = 0, n = 0, i;
2011-03-07 08:02:35 +01:00
for (u = f->units; u; u = u->nextF) {
if (u->number > 0) {
2010-08-08 10:06:34 +02:00
sc_mage *mage = get_mage(u);
if (mage) {
int level = eff_skill(u, SK_MAGIC, u->region);
2011-03-07 08:02:35 +01:00
if (level > maxlevel)
maxlevel = level;
assert(n < MAXMAGES);
2010-08-08 10:06:34 +02:00
mages[n++] = u;
}
}
}
2011-03-07 08:02:35 +01:00
if (FactionSpells() && maxlevel > f->max_spelllevel) {
2010-08-08 10:06:34 +02:00
update_spellbook(f, maxlevel);
}
2011-03-07 08:02:35 +01:00
for (i = 0; i != n; ++i) {
2010-08-08 10:06:34 +02:00
updatespelllist(mages[i]);
}
}
}
}
2011-03-07 08:02:35 +01:00
static void age_factions(void)
2010-08-08 10:06:34 +02:00
{
faction *f;
for (f = factions; f; f = f->next) {
++f->age;
2011-03-07 08:02:35 +01:00
if (f->age + 1 < NewbieImmunity()) {
ADDMSG(&f->msgs, msg_message("newbieimmunity", "turns",
NewbieImmunity() - f->age - 1));
2010-08-08 10:06:34 +02:00
}
}
}
2011-03-07 08:02:35 +01:00
static int use_cmd(unit * u, struct order *ord)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
const char *t;
2010-08-08 10:06:34 +02:00
int n;
2011-03-07 08:02:35 +01:00
const item_type *itype;
2010-08-08 10:06:34 +02:00
init_tokens(ord);
skip_token();
t = getstrtoken();
n = atoi((const char *)t);
2011-03-07 08:02:35 +01:00
if (n == 0) {
2010-08-08 10:06:34 +02:00
if (findparam(t, u->faction->locale) == P_ANY) {
/* BENUTZE ALLES Yanxspirit */
n = INT_MAX;
t = getstrtoken();
} else {
/* BENUTZE Yanxspirit */
n = 1;
}
} else {
/* BENUTZE 42 Yanxspirit */
t = getstrtoken();
}
itype = finditemtype(t, u->faction->locale);
2011-03-07 08:02:35 +01:00
if (itype != NULL) {
2010-08-08 10:06:34 +02:00
int i = use_item(u, itype, n, ord);
2011-03-07 08:02:35 +01:00
assert(i <= 0 || !"use_item should not return positive values.");
if (i > 0) {
log_error("use_item returned a value>0 for %s\n", resourcename(itype->rtype, 0));
2011-03-07 08:02:35 +01:00
}
2010-08-08 10:06:34 +02:00
} else {
cmistake(u, ord, 43, MSG_PRODUCE);
}
return 0;
}
2011-03-07 08:02:35 +01:00
static int pay_cmd(unit * u, struct order *ord)
2010-08-08 10:06:34 +02:00
{
if (!u->building) {
cmistake(u, ord, 6, MSG_EVENT);
} else {
param_t p;
init_tokens(ord);
skip_token();
p = getparam(u->faction->locale);
2011-03-07 08:02:35 +01:00
if (p == P_NOT) {
unit *owner = building_owner(u->building);
if (owner->faction != u->faction) {
2010-08-08 10:06:34 +02:00
cmistake(u, ord, 1222, MSG_EVENT);
} else {
u->building->flags |= BLD_DONTPAY;
}
}
}
return 0;
}
2011-03-07 08:02:35 +01:00
static int claim_cmd(unit * u, struct order *ord)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
const char *t;
2010-08-08 10:06:34 +02:00
int n;
2011-03-07 08:02:35 +01:00
const item_type *itype;
2010-08-08 10:06:34 +02:00
init_tokens(ord);
skip_token();
t = getstrtoken();
n = atoi((const char *)t);
2011-03-07 08:02:35 +01:00
if (n == 0) {
2010-08-08 10:06:34 +02:00
n = 1;
} else {
t = getstrtoken();
}
itype = finditemtype(t, u->faction->locale);
2011-03-07 08:02:35 +01:00
if (itype != NULL) {
item **iclaim = i_find(&u->faction->items, itype);
if (iclaim != NULL && *iclaim != NULL) {
2010-08-08 10:06:34 +02:00
n = MIN(n, (*iclaim)->number);
i_change(iclaim, itype, -n);
i_change(&u->items, itype, n);
}
} else {
cmistake(u, ord, 43, MSG_PRODUCE);
}
return 0;
}
enum {
2011-03-07 08:02:35 +01:00
PROC_THISORDER = 1 << 0,
PROC_LONGORDER = 1 << 1
2010-08-08 10:06:34 +02:00
};
typedef struct processor {
2011-03-07 08:02:35 +01:00
struct processor *next;
2010-08-08 10:06:34 +02:00
int priority;
enum { PR_GLOBAL, PR_REGION_PRE, PR_UNIT, PR_ORDER, PR_REGION_POST } type;
unsigned int flags;
union {
struct {
keyword_t kword;
2011-03-07 08:02:35 +01:00
int (*process) (struct unit *, struct order *);
2010-08-08 10:06:34 +02:00
} per_order;
struct {
2011-03-07 08:02:35 +01:00
void (*process) (struct unit *);
2010-08-08 10:06:34 +02:00
} per_unit;
struct {
2011-03-07 08:02:35 +01:00
void (*process) (struct region *);
2010-08-08 10:06:34 +02:00
} per_region;
struct {
2011-03-07 08:02:35 +01:00
void (*process) (void);
2010-08-08 10:06:34 +02:00
} global;
} data;
2011-03-07 08:02:35 +01:00
const char *name;
2010-08-08 10:06:34 +02:00
} processor;
2011-03-07 08:02:35 +01:00
static processor *processors;
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
processor *add_proc(int priority, const char *name, int type)
2010-08-08 10:06:34 +02:00
{
processor **pproc = &processors;
processor *proc;
while (*pproc) {
proc = *pproc;
2011-03-07 08:02:35 +01:00
if (proc->priority > priority)
break;
else if (proc->priority == priority && proc->type >= type)
break;
2010-08-08 10:06:34 +02:00
pproc = &proc->next;
}
proc = malloc(sizeof(processor));
proc->priority = priority;
proc->type = type;
proc->name = name;
proc->next = *pproc;
*pproc = proc;
return proc;
}
void
2011-03-07 08:02:35 +01:00
add_proc_order(int priority, keyword_t kword, int (*parser) (struct unit *,
struct order *), unsigned int flags, const char *name)
2010-08-08 10:06:34 +02:00
{
if (!global.disabled[kword]) {
2011-03-07 08:02:35 +01:00
processor *proc = add_proc(priority, name, PR_ORDER);
2010-08-08 10:06:34 +02:00
if (proc) {
proc->data.per_order.process = parser;
proc->data.per_order.kword = kword;
proc->flags = flags;
}
}
}
2011-03-07 08:02:35 +01:00
void add_proc_global(int priority, void (*process) (void), const char *name)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
processor *proc = add_proc(priority, name, PR_GLOBAL);
2010-08-08 10:06:34 +02:00
if (proc) {
proc->data.global.process = process;
}
}
2011-03-07 08:02:35 +01:00
void add_proc_region(int priority, void (*process) (region *), const char *name)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
processor *proc = add_proc(priority, name, PR_REGION_PRE);
2010-08-08 10:06:34 +02:00
if (proc) {
proc->data.per_region.process = process;
}
}
void
2011-03-07 08:02:35 +01:00
add_proc_postregion(int priority, void (*process) (region *), const char *name)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
processor *proc = add_proc(priority, name, PR_REGION_POST);
2010-08-08 10:06:34 +02:00
if (proc) {
proc->data.per_region.process = process;
}
}
2011-03-07 08:02:35 +01:00
void add_proc_unit(int priority, void (*process) (unit *), const char *name)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
processor *proc = add_proc(priority, name, PR_UNIT);
2010-08-08 10:06:34 +02:00
if (proc) {
proc->data.per_unit.process = process;
}
}
/* per priority, execute processors in order from PR_GLOBAL down to PR_ORDER */
2011-03-07 08:02:35 +01:00
void process(void)
2010-08-08 10:06:34 +02:00
{
processor *proc = processors;
2011-03-07 08:02:35 +01:00
faction *f;
2010-08-08 10:06:34 +02:00
while (proc) {
int prio = proc->priority;
region *r;
processor *pglobal = proc;
2011-03-07 08:02:35 +01:00
if (verbosity >= 3)
printf("- Step %u\n", prio);
while (proc && proc->priority == prio) {
if (proc->name && verbosity >= 1)
2012-05-16 07:21:59 +02:00
log_printf(stdout, " - %s\n", proc->name);
2010-08-08 10:06:34 +02:00
proc = proc->next;
}
2011-03-07 08:02:35 +01:00
while (pglobal && pglobal->priority == prio && pglobal->type == PR_GLOBAL) {
2010-08-08 10:06:34 +02:00
pglobal->data.global.process();
pglobal = pglobal->next;
}
2011-03-07 08:02:35 +01:00
if (pglobal == NULL || pglobal->priority != prio)
continue;
2010-08-08 10:06:34 +02:00
for (r = regions; r; r = r->next) {
unit *u;
processor *pregion = pglobal;
2011-03-07 08:02:35 +01:00
while (pregion && pregion->priority == prio
&& pregion->type == PR_REGION_PRE) {
2010-08-08 10:06:34 +02:00
pregion->data.per_region.process(r);
pregion = pregion->next;
}
2011-03-07 08:02:35 +01:00
if (pregion == NULL || pregion->priority != prio)
continue;
2010-08-08 10:06:34 +02:00
if (r->units) {
2011-03-07 08:02:35 +01:00
for (u = r->units; u; u = u->next) {
2010-08-08 10:06:34 +02:00
processor *porder, *punit = pregion;
2011-03-07 08:02:35 +01:00
while (punit && punit->priority == prio && punit->type == PR_UNIT) {
2010-08-08 10:06:34 +02:00
punit->data.per_unit.process(u);
punit = punit->next;
}
2011-03-07 08:02:35 +01:00
if (punit == NULL || punit->priority != prio)
continue;
2010-08-08 10:06:34 +02:00
porder = punit;
2011-03-07 08:02:35 +01:00
while (porder && porder->priority == prio && porder->type == PR_ORDER) {
order **ordp = &u->orders;
if (porder->flags & PROC_THISORDER)
2011-03-07 08:02:35 +01:00
ordp = &u->thisorder;
2010-08-08 10:06:34 +02:00
while (*ordp) {
2011-03-07 08:02:35 +01:00
order *ord = *ordp;
2010-08-08 10:06:34 +02:00
if (get_keyword(ord) == porder->data.per_order.kword) {
if (porder->flags & PROC_LONGORDER) {
2011-03-07 08:02:35 +01:00
if (u->number == 0) {
2010-08-08 10:06:34 +02:00
ord = NULL;
2011-03-07 08:02:35 +01:00
} else if (u->race == new_race[RC_INSECT]
&& r_insectstalled(r)
&& !is_cursed(u->attribs, C_KAELTESCHUTZ, 0)) {
2010-08-08 10:06:34 +02:00
ord = NULL;
} else if (LongHunger(u)) {
cmistake(u, ord, 224, MSG_MAGIC);
ord = NULL;
} else if (fval(u, UFL_LONGACTION)) {
/* this message was already given in laws.setdefaults
2011-03-07 08:02:35 +01:00
cmistake(u, ord, 52, MSG_PRODUCE);
*/
2010-08-08 10:06:34 +02:00
ord = NULL;
2011-03-07 08:02:35 +01:00
} else if (fval(r->terrain, SEA_REGION)
&& u->race != new_race[RC_AQUARIAN]
&& !(u->race->flags & RCF_SWIM)) {
2010-08-08 10:06:34 +02:00
/* error message disabled by popular demand */
ord = NULL;
}
}
if (ord) {
porder->data.per_order.process(u, ord);
}
}
2011-03-07 08:02:35 +01:00
if (!ord || *ordp == ord)
ordp = &(*ordp)->next;
2010-08-08 10:06:34 +02:00
}
porder = porder->next;
}
}
}
2011-03-07 08:02:35 +01:00
while (pregion && pregion->priority == prio
&& pregion->type != PR_REGION_POST) {
2010-08-08 10:06:34 +02:00
pregion = pregion->next;
}
2011-03-07 08:02:35 +01:00
while (pregion && pregion->priority == prio
&& pregion->type == PR_REGION_POST) {
2010-08-08 10:06:34 +02:00
pregion->data.per_region.process(r);
pregion = pregion->next;
}
2011-03-07 08:02:35 +01:00
if (pregion == NULL || pregion->priority != prio)
continue;
2010-08-08 10:06:34 +02:00
}
}
2011-03-07 08:02:35 +01:00
if (verbosity >= 3)
printf("\n - Leere Gruppen loeschen...\n");
for (f = factions; f; f = f->next) {
group **gp = &f->groups;
2010-08-08 10:06:34 +02:00
while (*gp) {
2011-03-07 08:02:35 +01:00
group *g = *gp;
if (g->members == 0) {
2010-08-08 10:06:34 +02:00
*gp = g->next;
free_group(g);
} else
gp = &g->next;
}
}
}
2011-03-07 08:02:35 +01:00
static void enter_1(region * r)
{
do_misc(r, 0);
2011-03-07 08:02:35 +01:00
}
static void enter_2(region * r)
{
do_misc(r, 1);
2011-03-07 08:02:35 +01:00
}
static void maintain_buildings_1(region * r)
{
maintain_buildings(r, false);
}
2010-08-08 10:06:34 +02:00
#ifdef COLLAPSE_CHANCE
2011-03-07 08:02:35 +01:00
static void maintain_buildings_2(region * r)
{
maintain_buildings(r, true);
}
2010-08-08 10:06:34 +02:00
#endif
2011-03-07 08:02:35 +01:00
static void reset_moved(unit * u)
{
freset(u, UFL_MOVED);
}
2010-08-08 10:06:34 +02:00
/** warn about passwords that are not US ASCII.
* even though passwords are technically UTF8 strings, the server receives
* them as part of the Subject of an email when reports are requested.
* This means that we need to limit them to ASCII characters until that
* mechanism has been changed.
*/
2011-03-07 08:02:35 +01:00
static int warn_password(void)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
faction *f = factions;
2010-08-08 10:06:34 +02:00
while (f) {
boolean pwok = true;
2011-03-07 08:02:35 +01:00
const char *c = f->passw;
2010-08-08 10:06:34 +02:00
while (*c && pwok) {
2011-03-07 08:02:35 +01:00
if (!isalnum((unsigned char)*c))
pwok = false;
2010-08-08 10:06:34 +02:00
c++;
}
if (!pwok) {
free(f->passw);
f->passw = strdup(itoa36(rng_int()));
ADDMSG(&f->msgs, msg_message("illegal_password", "newpass", f->passw));
}
f = f->next;
}
return 0;
}
2011-03-07 08:02:35 +01:00
void init_processor(void)
2010-08-08 10:06:34 +02:00
{
int p;
p = 10;
add_proc_global(p, &new_units, "Neue Einheiten erschaffen");
2011-03-07 08:02:35 +01:00
p += 10;
2010-08-08 10:06:34 +02:00
add_proc_unit(p, &setdefaults, "Default-Befehle");
add_proc_order(p, K_BANNER, &banner_cmd, 0, NULL);
add_proc_order(p, K_EMAIL, &email_cmd, 0, NULL);
add_proc_order(p, K_PASSWORD, &password_cmd, 0, NULL);
add_proc_order(p, K_SEND, &send_cmd, 0, NULL);
add_proc_order(p, K_GROUP, &group_cmd, 0, NULL);
2011-03-07 08:02:35 +01:00
p += 10;
2010-08-08 10:06:34 +02:00
add_proc_unit(p, &reset_moved, "Instant-Befehle");
add_proc_order(p, K_QUIT, &quit_cmd, 0, NULL);
add_proc_order(p, K_URSPRUNG, &origin_cmd, 0, NULL);
add_proc_order(p, K_ALLY, &ally_cmd, 0, NULL);
add_proc_order(p, K_PREFIX, &prefix_cmd, 0, NULL);
add_proc_order(p, K_SETSTEALTH, &setstealth_cmd, 0, NULL);
add_proc_order(p, K_STATUS, &status_cmd, 0, NULL);
add_proc_order(p, K_COMBATSPELL, &combatspell_cmd, 0, NULL);
add_proc_order(p, K_DISPLAY, &display_cmd, 0, NULL);
add_proc_order(p, K_NAME, &name_cmd, 0, NULL);
add_proc_order(p, K_GUARD, &guard_off_cmd, 0, NULL);
add_proc_order(p, K_RESHOW, &reshow_cmd, 0, NULL);
2011-03-07 08:02:35 +01:00
if (get_param_int(global.parameters, "rules.alliances", 0) == 1) {
p += 10;
2010-08-08 10:06:34 +02:00
add_proc_global(p, &alliance_cmd, NULL);
}
2011-03-07 08:02:35 +01:00
p += 10;
2010-08-08 10:06:34 +02:00
add_proc_global(p, &age_factions, "Parteienalter++");
add_proc_order(p, K_MAIL, &mail_cmd, 0, "Botschaften");
2011-03-07 08:02:35 +01:00
p += 10; /* all claims must be done before we can USE */
2010-08-08 10:06:34 +02:00
add_proc_region(p, &enter_1, "Kontaktieren & Betreten (1. Versuch)");
add_proc_order(p, K_USE, &use_cmd, 0, "Benutzen");
if (!global.disabled[K_GM]) {
add_proc_global(p, &gmcommands, "GM Kommandos");
}
2011-03-07 08:02:35 +01:00
p += 10; /* in case it has any effects on alliance victories */
2010-08-08 10:06:34 +02:00
add_proc_order(p, K_GIVE, &give_control_cmd, 0, "GIB KOMMANDO");
2011-03-07 08:02:35 +01:00
p += 10; /* in case it has any effects on alliance victories */
2010-08-08 10:06:34 +02:00
add_proc_order(p, K_LEAVE, &leave_cmd, 0, "Verlassen");
if (!nobattle) {
add_proc_region(p, &do_battle, "Attackieren");
}
if (!global.disabled[K_BESIEGE]) {
2011-03-07 08:02:35 +01:00
p += 10;
2010-08-08 10:06:34 +02:00
add_proc_region(p, &do_siege, "Belagern");
}
2011-03-07 08:02:35 +01:00
p += 10; /* can't allow reserve before siege (weapons) */
2010-08-08 10:06:34 +02:00
add_proc_region(p, &enter_1, "Kontaktieren & Betreten (2. Versuch)");
add_proc_order(p, K_RESERVE, &reserve_cmd, 0, "Reservieren");
add_proc_order(p, K_CLAIM, &claim_cmd, 0, NULL);
add_proc_unit(p, &follow_unit, "Folge auf Einheiten setzen");
2011-03-07 08:02:35 +01:00
p += 10; /* rest rng again before economics */
2010-08-08 10:06:34 +02:00
add_proc_region(p, &economics, "Zerstoeren, Geben, Rekrutieren, Vergessen");
2011-03-07 08:02:35 +01:00
p += 10;
2010-08-08 10:06:34 +02:00
if (!global.disabled[K_PAY]) {
add_proc_order(p, K_PAY, &pay_cmd, 0, "Gebaeudeunterhalt (disable)");
}
2011-03-07 08:02:35 +01:00
add_proc_postregion(p, &maintain_buildings_1,
"Gebaeudeunterhalt (1. Versuch)");
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
p += 10; /* QUIT fuer sich alleine */
2010-08-08 10:06:34 +02:00
add_proc_global(p, &quit, "Sterben");
if (!global.disabled[K_RESTART]) {
add_proc_global(p, &parse_restart, "Neustart");
}
if (!global.disabled[K_CAST]) {
2011-03-07 08:02:35 +01:00
p += 10;
2010-08-08 10:06:34 +02:00
add_proc_global(p, &magic, "Zaubern");
}
2011-03-07 08:02:35 +01:00
p += 10;
add_proc_order(p, K_TEACH, &teach_cmd, PROC_THISORDER | PROC_LONGORDER,
"Lehren");
p += 10;
add_proc_order(p, K_STUDY, &learn_cmd, PROC_THISORDER | PROC_LONGORDER,
"Lernen");
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
p += 10;
add_proc_order(p, K_MAKE, &make_cmd, PROC_THISORDER | PROC_LONGORDER,
"Produktion");
2010-08-08 10:06:34 +02:00
add_proc_postregion(p, &produce, "Arbeiten, Handel, Rekruten");
add_proc_postregion(p, &split_allocations, "Produktion II");
2011-03-07 08:02:35 +01:00
p += 10;
2010-08-08 10:06:34 +02:00
add_proc_region(p, &enter_2, "Kontaktieren & Betreten (3. Versuch)");
2011-03-07 08:02:35 +01:00
p += 10;
2010-08-08 10:06:34 +02:00
add_proc_region(p, &sinkships, "Schiffe sinken");
2011-03-07 08:02:35 +01:00
p += 10;
2010-08-08 10:06:34 +02:00
add_proc_global(p, &movement, "Bewegungen");
if (get_param_int(global.parameters, "work.auto", 0)) {
2011-03-07 08:02:35 +01:00
p += 10;
2010-08-08 10:06:34 +02:00
add_proc_region(p, &auto_work, "Arbeiten (auto)");
}
2011-03-07 08:02:35 +01:00
p += 10;
2010-08-08 10:06:34 +02:00
add_proc_order(p, K_GUARD, &guard_on_cmd, 0, "Bewache (an)");
#if XECMD_MODULE
/* can do together with guard */
add_proc_order(p, K_XE, &xecmd, 0, "Zeitung");
#endif
2011-03-07 08:02:35 +01:00
p += 10;
2010-08-08 10:06:34 +02:00
add_proc_global(p, &encounters, "Zufallsbegegnungen");
2011-03-07 08:02:35 +01:00
p += 10;
add_proc_unit(p, &monster_kills_peasants,
"Monster fressen und vertreiben Bauern");
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
p += 10;
2010-08-08 10:06:34 +02:00
add_proc_global(p, &randomevents, "Zufallsereignisse");
2011-03-07 08:02:35 +01:00
p += 10;
2010-08-08 10:06:34 +02:00
add_proc_global(p, &monthly_healing, "Regeneration (HP)");
add_proc_global(p, &regeneration_magiepunkte, "Regeneration (Aura)");
if (!global.disabled[K_DEFAULT]) {
add_proc_global(p, &defaultorders, "Defaults setzen");
}
add_proc_global(p, &demographics, "Nahrung, Seuchen, Wachstum, Wanderung");
#ifdef COLLAPSE_CHANCE
2011-03-07 08:02:35 +01:00
p += 10;
2010-08-08 10:06:34 +02:00
add_proc_region(p, &maintain_buildings_2, "Gebaeudeunterhalt (2. Versuch)");
#endif
if (!global.disabled[K_SORT]) {
2011-03-07 08:02:35 +01:00
p += 10;
2010-08-08 10:06:34 +02:00
add_proc_global(p, &reorder, "Einheiten sortieren");
}
add_proc_order(p, K_PROMOTION, &promotion_cmd, 0, "Heldenbefoerderung");
if (!global.disabled[K_NUMBER]) {
add_proc_order(p, K_NUMBER, &renumber_cmd, 0, "Neue Nummern (Einheiten)");
2011-03-07 08:02:35 +01:00
p += 10;
2010-08-08 10:06:34 +02:00
add_proc_global(p, &renumber_factions, "Neue Nummern");
}
}
2011-03-07 08:02:35 +01:00
void processorders(void)
2010-08-08 10:06:34 +02:00
{
static int init = 0;
if (!init) {
init_processor();
init = 1;
}
update_spells();
process();
/*************************************************/
if (get_param_int(global.parameters, "modules.markets", 0)) {
do_markets();
}
2011-03-07 08:02:35 +01:00
if (verbosity >= 1)
puts(" - Attribute altern");
2010-08-08 10:06:34 +02:00
ageing();
remove_empty_units();
/* must happen AFTER age, because that would destroy them right away */
if (get_param_int(global.parameters, "modules.wormholes", 0)) {
create_wormholes();
}
/* immer ausf<73>hren, wenn neue Spr<70>che dazugekommen sind, oder sich
* Beschreibungen ge<EFBFBD>ndert haben */
update_spells();
warn_password();
}
2011-03-07 08:02:35 +01:00
int writepasswd(void)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
FILE *F;
2010-08-08 10:06:34 +02:00
char zText[128];
sprintf(zText, "%s/passwd", basepath());
F = cfopen(zText, "w");
if (F) {
faction *f;
puts("writing passwords...");
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;
}
2011-03-07 08:02:35 +01:00
void update_subscriptions(void)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
FILE *F;
2010-08-08 10:06:34 +02:00
char zText[MAX_PATH];
2011-03-07 08:02:35 +01:00
faction *f;
2010-08-08 10:06:34 +02:00
strcat(strcpy(zText, basepath()), "/subscriptions");
F = fopen(zText, "r");
2011-03-07 08:02:35 +01:00
if (F == NULL) {
log_warning(0, "could not open %s.\n", zText);
2010-08-08 10:06:34 +02:00
return;
}
for (;;) {
char zFaction[5];
int subscription, fno;
2011-03-07 08:02:35 +01:00
if (fscanf(F, "%d %s", &subscription, zFaction) <= 0)
break;
2010-08-08 10:06:34 +02:00
fno = atoi36(zFaction);
f = findfaction(fno);
2011-03-07 08:02:35 +01:00
if (f != NULL) {
f->subscription = subscription;
2010-08-08 10:06:34 +02:00
}
}
fclose(F);
sprintf(zText, "subscriptions.%u", turn);
F = fopen(zText, "w");
2011-03-07 08:02:35 +01:00
for (f = factions; f != NULL; f = f->next) {
2010-08-08 10:06:34 +02:00
fprintf(F, "%s:%u:%s:%s:%s:%u:\n",
itoa36(f->no), f->subscription, f->email, f->override,
dbrace(f->race), f->lastorders);
}
fclose(F);
}
2011-03-07 08:02:35 +01:00
int init_data(const char *filename, const char *catalog)
2010-08-08 10:06:34 +02:00
{
int l;
l = read_xml(filename, catalog);
2011-03-07 08:02:35 +01:00
if (l)
return l;
2010-08-08 10:06:34 +02:00
init_locales();
init_archetypes();
2011-03-07 08:02:35 +01:00
if (turn < 0) {
2010-08-08 10:06:34 +02:00
turn = first_turn;
}
return 0;
}