2001-01-25 10:37:55 +01:00
|
|
|
|
/* vi: set ts=2:
|
|
|
|
|
*
|
2001-04-14 13:39:14 +02:00
|
|
|
|
*
|
2001-01-25 10:37:55 +01:00
|
|
|
|
* Eressea PB(E)M host Copyright (C) 1998-2000
|
|
|
|
|
* Christian Schlittchen (corwin@amber.kn-bremen.de)
|
|
|
|
|
* Katja Zedel (katze@felidae.kn-bremen.de)
|
|
|
|
|
* Henning Peters (faroul@beyond.kn-bremen.de)
|
|
|
|
|
* Enno Rehling (enno@eressea-pbem.de)
|
|
|
|
|
* Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
|
|
|
|
|
*
|
|
|
|
|
* based on:
|
|
|
|
|
*
|
|
|
|
|
* Atlantis v1.0 13 September 1993 Copyright 1993 by Russell Wallace
|
|
|
|
|
* Atlantis v1.7 Copyright 1996 by Alex Schr<EFBFBD>der
|
|
|
|
|
*
|
|
|
|
|
* This program may not be used, modified or distributed without
|
|
|
|
|
* prior permission by the authors of Eressea.
|
|
|
|
|
* This program may not be sold or used commercially without prior written
|
|
|
|
|
* permission from the authors.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#include "eressea.h"
|
|
|
|
|
#include "region.h"
|
|
|
|
|
|
|
|
|
|
/* kernel includes */
|
|
|
|
|
#include "border.h"
|
2002-12-18 01:34:19 +01:00
|
|
|
|
#include "building.h"
|
2001-12-10 01:13:39 +01:00
|
|
|
|
#include "curse.h"
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#include "faction.h"
|
|
|
|
|
#include "item.h"
|
2001-12-10 01:13:39 +01:00
|
|
|
|
#include "message.h"
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#include "plane.h"
|
|
|
|
|
#include "region.h"
|
2001-12-10 01:13:39 +01:00
|
|
|
|
#include "resources.h"
|
2002-12-18 01:34:19 +01:00
|
|
|
|
#include "unit.h"
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
/* util includes */
|
|
|
|
|
#include <resolve.h>
|
|
|
|
|
|
|
|
|
|
/* libc includes */
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <ctype.h>
|
2001-01-28 09:01:52 +01:00
|
|
|
|
#include <limits.h>
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
2002-01-27 18:22:04 +01:00
|
|
|
|
extern int dice_rand(const char *s);
|
|
|
|
|
|
2001-04-16 16:34:19 +02:00
|
|
|
|
static int g_maxluxuries = 0;
|
2001-02-03 14:45:35 +01:00
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
const int delta_x[MAXDIRECTIONS] =
|
|
|
|
|
{
|
|
|
|
|
-1, 0, 1, 1, 0, -1
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const int delta_y[MAXDIRECTIONS] =
|
|
|
|
|
{
|
|
|
|
|
1, 1, 0, -1, -1, 0
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const direction_t back[MAXDIRECTIONS] =
|
|
|
|
|
{
|
|
|
|
|
D_SOUTHEAST,
|
|
|
|
|
D_SOUTHWEST,
|
|
|
|
|
D_WEST,
|
|
|
|
|
D_NORTHWEST,
|
|
|
|
|
D_NORTHEAST,
|
|
|
|
|
D_EAST,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const char *
|
- Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of
message_type*) gespeichert, das man in beliebige Formate (CR oder NR)
rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht
wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.
- make_message
Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
eine neue Nachricht, die dann einfach mit add_message wie bisher an die
Nachrichtenliste gehängt werden kann.
TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
unabhängig sind. Das spart einigen Speicher.
- CR Version erhöht.
Weil die MESSAGETYPES Blocks anders sind als früher
- OFFENSIVE_DELAY
Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den
Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
Status der letzten Runde wird in neuem Attribut at_moved gespeichert.
- SHORT_ATTACKS
ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.
- XML Parser
xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 19:21:57 +02:00
|
|
|
|
regionname(const region * r, const faction * f)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
static char buf[65];
|
|
|
|
|
plane *pl = getplane(r);
|
|
|
|
|
|
|
|
|
|
if (f == NULL) {
|
|
|
|
|
strncpy(buf, rname(r, NULL), 65);
|
|
|
|
|
} else if (pl && fval(pl, PFL_NOCOORDS)) {
|
|
|
|
|
strncpy(buf, rname(r, f->locale), 65);
|
|
|
|
|
} else {
|
2001-02-05 17:11:59 +01:00
|
|
|
|
#ifdef HAVE_SNPRINTF
|
2001-01-25 10:37:55 +01:00
|
|
|
|
snprintf(buf, 65, "%s (%d,%d)", rname(r, f->locale), region_x(r, f), region_y(r, f));
|
|
|
|
|
#else
|
2001-02-05 17:11:59 +01:00
|
|
|
|
strncpy(buf, rname(r, f->locale), 50);
|
|
|
|
|
buf[50]=0;
|
|
|
|
|
sprintf(buf+strlen(buf), " (%d,%d)", region_x(r, f), region_y(r, f));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
buf[64] = 0;
|
|
|
|
|
return buf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
deathcount(const region * r) {
|
|
|
|
|
attrib * a = a_find(r->attribs, &at_deathcount);
|
|
|
|
|
if (!a) return 0;
|
|
|
|
|
return a->data.i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
chaoscount(const region * r) {
|
|
|
|
|
attrib * a = a_find(r->attribs, &at_chaoscount);
|
|
|
|
|
if (!a) return 0;
|
|
|
|
|
return a->data.i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
woodcount(const region * r) {
|
|
|
|
|
attrib * a = a_find(r->attribs, &at_woodcount);
|
|
|
|
|
if (!a) return 0;
|
|
|
|
|
return a->data.i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2001-02-02 09:40:49 +01:00
|
|
|
|
deathcounts (region * r, int fallen) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
attrib * a;
|
|
|
|
|
|
|
|
|
|
if (fallen==0) return;
|
2001-01-31 18:40:53 +01:00
|
|
|
|
if (is_cursed(r->attribs, C_HOLYGROUND,0)) return;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
a = a_find(r->attribs, &at_deathcount);
|
|
|
|
|
if (!a) a = a_add(&r->attribs, a_new(&at_deathcount));
|
|
|
|
|
a->data.i += fallen;
|
|
|
|
|
|
2001-02-02 09:40:49 +01:00
|
|
|
|
if (a->data.i<=0) a_remove(&r->attribs, a);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
chaoscounts(region * r, int fallen) {
|
|
|
|
|
attrib * a;
|
|
|
|
|
|
|
|
|
|
if (fallen==0) return;
|
|
|
|
|
|
|
|
|
|
a = a_find(r->attribs, &at_chaoscount);
|
|
|
|
|
if (!a) a = a_add(&r->attribs, a_new(&at_chaoscount));
|
|
|
|
|
a->data.i += fallen;
|
|
|
|
|
|
2001-02-02 09:40:49 +01:00
|
|
|
|
if (a->data.i<=0) a_remove(&r->attribs, a);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
woodcounts(region * r, int fallen) {
|
|
|
|
|
attrib * a;
|
|
|
|
|
|
|
|
|
|
if (fallen==0) return;
|
|
|
|
|
|
|
|
|
|
a = a_find(r->attribs, &at_woodcount);
|
|
|
|
|
if (!a) a = a_add(&r->attribs, a_new(&at_woodcount));
|
|
|
|
|
a->data.i += fallen;
|
|
|
|
|
|
2001-02-02 09:40:49 +01:00
|
|
|
|
if (a->data.i<=0) a_remove(&r->attribs, a);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/********************/
|
|
|
|
|
/* at_direction */
|
|
|
|
|
/********************/
|
|
|
|
|
void
|
|
|
|
|
a_initdirection(attrib *a)
|
|
|
|
|
{
|
|
|
|
|
a->data.v = calloc(1, sizeof(spec_direction));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
a_agedirection(attrib *a)
|
|
|
|
|
{
|
|
|
|
|
spec_direction *d = (spec_direction *)(a->data.v);
|
|
|
|
|
|
|
|
|
|
if(d->duration > 0) d->duration--;
|
|
|
|
|
else d->duration = 0;
|
|
|
|
|
|
|
|
|
|
return d->duration;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
a_readdirection(attrib *a, FILE *f)
|
|
|
|
|
{
|
|
|
|
|
spec_direction *d = (spec_direction *)(a->data.v);
|
|
|
|
|
fscanf(f, "%d %d %d", &d->x, &d->y, &d->duration);
|
|
|
|
|
fscanf(f, "%s ", buf);
|
|
|
|
|
d->desc = strdup(cstring(buf));
|
|
|
|
|
fscanf(f, "%s ", buf);
|
|
|
|
|
d->keyword = strdup(cstring(buf));
|
2002-04-07 02:44:01 +02:00
|
|
|
|
return AT_READ_OK;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
a_writedirection(const attrib *a, FILE *f)
|
|
|
|
|
{
|
|
|
|
|
spec_direction *d = (spec_direction *)(a->data.v);
|
|
|
|
|
|
|
|
|
|
fprintf(f, "%d %d %d %s %s ", d->x, d->y, d->duration,
|
|
|
|
|
estring(d->desc), estring(d->keyword));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
attrib_type at_direction = {
|
|
|
|
|
"direction",
|
|
|
|
|
a_initdirection,
|
|
|
|
|
NULL,
|
|
|
|
|
a_agedirection,
|
|
|
|
|
a_writedirection,
|
|
|
|
|
a_readdirection
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Moveblock wird zur Zeit nicht <20>ber Attribute, sondern ein Bitfeld
|
|
|
|
|
r->moveblock gemacht. Sollte umgestellt werden, wenn kompliziertere
|
|
|
|
|
Dinge gefragt werden. */
|
|
|
|
|
|
|
|
|
|
/********************/
|
|
|
|
|
/* at_moveblock */
|
|
|
|
|
/********************/
|
|
|
|
|
void
|
|
|
|
|
a_initmoveblock(attrib *a)
|
|
|
|
|
{
|
|
|
|
|
a->data.v = calloc(1, sizeof(moveblock));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
a_readmoveblock(attrib *a, FILE *f)
|
|
|
|
|
{
|
|
|
|
|
moveblock *m = (moveblock *)(a->data.v);
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
fscanf(f, "%d", &i);
|
|
|
|
|
m->dir = (direction_t)i;
|
2002-04-07 02:44:01 +02:00
|
|
|
|
return AT_READ_OK;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
a_writemoveblock(const attrib *a, FILE *f)
|
|
|
|
|
{
|
|
|
|
|
moveblock *m = (moveblock *)(a->data.v);
|
|
|
|
|
fprintf(f, "%d ", (int)m->dir);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
attrib_type at_moveblock = {
|
|
|
|
|
"moveblock", a_initmoveblock, NULL, NULL, a_writemoveblock, a_readmoveblock
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define RMAXHASH 65535
|
|
|
|
|
region *regionhash[RMAXHASH];
|
|
|
|
|
|
|
|
|
|
static region *
|
|
|
|
|
rfindhash(int x, int y)
|
|
|
|
|
{
|
|
|
|
|
region *old;
|
|
|
|
|
for (old = regionhash[abs(x + 0x100 * y) % RMAXHASH]; old; old = old->nexthash)
|
|
|
|
|
if (old->x == x && old->y == y)
|
|
|
|
|
return old;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
rhash(region * r)
|
|
|
|
|
{
|
|
|
|
|
region *old = regionhash[region_hashkey(r) % RMAXHASH];
|
|
|
|
|
regionhash[region_hashkey(r) % RMAXHASH] = r;
|
|
|
|
|
r->nexthash = old;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
runhash(region * r)
|
|
|
|
|
{
|
|
|
|
|
region **show;
|
|
|
|
|
for (show = ®ionhash[abs(r->x + 0x100 * r->y) % RMAXHASH]; *show; show = &(*show)->nexthash) {
|
|
|
|
|
if ((*show)->x == r->x && (*show)->y == r->y)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (*show) {
|
|
|
|
|
assert(*show == r);
|
|
|
|
|
*show = (*show)->nexthash;
|
|
|
|
|
r->nexthash = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
region *
|
|
|
|
|
rconnect(const region * r, direction_t dir) {
|
|
|
|
|
static int set = 0;
|
|
|
|
|
static region * buffer[MAXDIRECTIONS];
|
|
|
|
|
static const region * last = NULL;
|
|
|
|
|
assert(dir<MAXDIRECTIONS);
|
|
|
|
|
if (r != last) {
|
|
|
|
|
set = 0;
|
|
|
|
|
last = r;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
if (set & (1 << dir)) return buffer[dir];
|
|
|
|
|
buffer[dir] = rfindhash(r->x + delta_x[dir], r->y + delta_y[dir]);
|
|
|
|
|
set |= (1<<dir);
|
|
|
|
|
return buffer[dir];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
region *
|
|
|
|
|
findregion(int x, int y)
|
|
|
|
|
{
|
|
|
|
|
return rfindhash(x, y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
koor_distance(int x1, int y1, int x2, int y2)
|
|
|
|
|
{
|
|
|
|
|
/* Contributed by Hubert Mackenberg. Thanks.
|
|
|
|
|
* x und y Abstand zwischen x1 und x2 berechnen
|
|
|
|
|
*/
|
|
|
|
|
int dx = x1 - x2;
|
|
|
|
|
int dy = y1 - y2;
|
|
|
|
|
|
|
|
|
|
/* Bei negativem dy am Ursprung spiegeln, das veraendert
|
|
|
|
|
* den Abstand nicht
|
|
|
|
|
*/
|
|
|
|
|
if ( dy < 0 )
|
|
|
|
|
{
|
|
|
|
|
dy = -dy;
|
|
|
|
|
dx = -dx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* dy ist jetzt >=0, fuer dx sind 3 Faelle zu untescheiden
|
|
|
|
|
*/
|
|
|
|
|
if ( dx >= 0 ) return dx + dy;
|
|
|
|
|
else if (-dx >= dy) return -dx;
|
|
|
|
|
else return dy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
distance(const region * r1, const region * r2)
|
|
|
|
|
{
|
|
|
|
|
return koor_distance(r1->x, r1->y, r2->x, r2->y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
direction_t
|
|
|
|
|
koor_reldirection(int ax, int ay, int bx, int by)
|
|
|
|
|
{
|
|
|
|
|
direction_t i;
|
|
|
|
|
for (i=0;i!=MAXDIRECTIONS;++i) {
|
|
|
|
|
if (bx-ax == delta_x[i] &&
|
|
|
|
|
by-ay == delta_y[i]) return i;
|
|
|
|
|
}
|
|
|
|
|
return NODIRECTION;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
direction_t
|
|
|
|
|
reldirection(region * from, region * to)
|
|
|
|
|
{
|
|
|
|
|
return koor_reldirection(from->x, from->y, to->x, to->y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
free_regionlist(regionlist *rl)
|
|
|
|
|
{
|
2001-02-10 20:24:05 +01:00
|
|
|
|
while (rl) {
|
|
|
|
|
regionlist * rl2 = rl->next;
|
|
|
|
|
free(rl);
|
|
|
|
|
rl = rl2;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2002-01-09 09:20:33 +01:00
|
|
|
|
void
|
|
|
|
|
add_regionlist(regionlist **rl, region *r)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2002-01-09 09:20:33 +01:00
|
|
|
|
regionlist *rl2 = (regionlist*)malloc(sizeof(regionlist));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
rl2->region = r;
|
2002-01-09 09:20:33 +01:00
|
|
|
|
rl2->next = *rl;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2002-01-09 09:20:33 +01:00
|
|
|
|
*rl = rl2;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if AT_SALARY
|
|
|
|
|
/*****************/
|
|
|
|
|
/* at_salary */
|
|
|
|
|
/*****************/
|
|
|
|
|
attrib_type at_salary = {
|
|
|
|
|
"salary",
|
|
|
|
|
DEFAULT_INIT,
|
|
|
|
|
DEFAULT_FINALIZE,
|
|
|
|
|
DEFAULT_AGE,
|
|
|
|
|
NO_WRITE,
|
|
|
|
|
NO_READ,
|
|
|
|
|
ATF_UNIQUE
|
|
|
|
|
};
|
|
|
|
|
#endif
|
|
|
|
|
/********************/
|
|
|
|
|
/* at_horseluck */
|
|
|
|
|
/********************/
|
|
|
|
|
attrib_type at_horseluck = {
|
|
|
|
|
"horseluck",
|
|
|
|
|
DEFAULT_INIT,
|
|
|
|
|
DEFAULT_FINALIZE,
|
|
|
|
|
DEFAULT_AGE,
|
|
|
|
|
NO_WRITE,
|
2001-02-02 09:40:49 +01:00
|
|
|
|
NO_READ,
|
|
|
|
|
ATF_UNIQUE
|
2001-01-25 10:37:55 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**********************/
|
|
|
|
|
/* at_peasantluck */
|
|
|
|
|
/**********************/
|
|
|
|
|
attrib_type at_peasantluck = {
|
|
|
|
|
"peasantluck",
|
|
|
|
|
DEFAULT_INIT,
|
|
|
|
|
DEFAULT_FINALIZE,
|
|
|
|
|
DEFAULT_AGE,
|
|
|
|
|
NO_WRITE,
|
2001-02-02 09:40:49 +01:00
|
|
|
|
NO_READ,
|
|
|
|
|
ATF_UNIQUE
|
2001-01-25 10:37:55 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*********************/
|
|
|
|
|
/* at_chaoscount */
|
|
|
|
|
/*********************/
|
|
|
|
|
attrib_type at_chaoscount = {
|
|
|
|
|
"chaoscount",
|
|
|
|
|
DEFAULT_INIT,
|
|
|
|
|
DEFAULT_FINALIZE,
|
|
|
|
|
DEFAULT_AGE,
|
|
|
|
|
DEFAULT_WRITE,
|
2001-02-02 09:40:49 +01:00
|
|
|
|
DEFAULT_READ,
|
|
|
|
|
ATF_UNIQUE
|
2001-01-25 10:37:55 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*********************/
|
|
|
|
|
/* at_deathcount */
|
|
|
|
|
/*********************/
|
|
|
|
|
attrib_type at_deathcount = {
|
|
|
|
|
"deathcount",
|
|
|
|
|
DEFAULT_INIT,
|
|
|
|
|
DEFAULT_FINALIZE,
|
|
|
|
|
DEFAULT_AGE,
|
|
|
|
|
DEFAULT_WRITE,
|
2001-02-02 09:40:49 +01:00
|
|
|
|
DEFAULT_READ,
|
|
|
|
|
ATF_UNIQUE
|
2001-01-25 10:37:55 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*********************/
|
|
|
|
|
/* at_woodcount */
|
|
|
|
|
/*********************/
|
|
|
|
|
attrib_type at_woodcount = {
|
|
|
|
|
"woodcount",
|
|
|
|
|
DEFAULT_INIT,
|
|
|
|
|
DEFAULT_FINALIZE,
|
|
|
|
|
DEFAULT_AGE,
|
|
|
|
|
DEFAULT_WRITE,
|
2001-02-02 09:40:49 +01:00
|
|
|
|
DEFAULT_READ,
|
|
|
|
|
ATF_UNIQUE
|
2001-01-25 10:37:55 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*********************/
|
|
|
|
|
/* at_travelunit */
|
|
|
|
|
/*********************/
|
|
|
|
|
attrib_type at_travelunit = {
|
|
|
|
|
"travelunit",
|
|
|
|
|
DEFAULT_INIT,
|
|
|
|
|
DEFAULT_FINALIZE,
|
|
|
|
|
DEFAULT_AGE,
|
|
|
|
|
NO_WRITE,
|
|
|
|
|
NO_READ
|
|
|
|
|
};
|
|
|
|
|
|
2001-12-15 13:26:04 +01:00
|
|
|
|
#if NEW_RESOURCEGROWTH
|
2001-12-10 01:13:39 +01:00
|
|
|
|
extern int laen_read(attrib * a, FILE * F);
|
|
|
|
|
# define LAEN_READ laen_read
|
|
|
|
|
# define LAEN_WRITE NULL
|
|
|
|
|
#else
|
|
|
|
|
# define LAEN_READ DEFAULT_READ
|
|
|
|
|
# define LAEN_WRITE DEFAULT_WRITE
|
|
|
|
|
#endif
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/***************/
|
|
|
|
|
/* at_laen */
|
|
|
|
|
/***************/
|
|
|
|
|
attrib_type at_laen = {
|
|
|
|
|
"laen",
|
|
|
|
|
DEFAULT_INIT,
|
|
|
|
|
DEFAULT_FINALIZE,
|
|
|
|
|
DEFAULT_AGE,
|
2001-12-10 01:13:39 +01:00
|
|
|
|
LAEN_WRITE,
|
|
|
|
|
LAEN_READ,
|
2001-02-02 09:40:49 +01:00
|
|
|
|
ATF_UNIQUE
|
2001-01-25 10:37:55 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
rsetlaen(region * r, int val)
|
|
|
|
|
{
|
|
|
|
|
attrib * a = a_find(r->attribs, &at_laen);
|
|
|
|
|
if (!a && val>=0) a = a_add(&r->attribs, a_new(&at_laen));
|
|
|
|
|
else if (a && val<0) a_remove(&r->attribs, a);
|
|
|
|
|
if (val>=0) a->data.i = val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
rlaen(const region * r)
|
|
|
|
|
{
|
|
|
|
|
attrib * a = a_find(r->attribs, &at_laen);
|
|
|
|
|
if (!a) return -1;
|
|
|
|
|
return a->data.i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************/
|
|
|
|
|
/* at_road */
|
|
|
|
|
/***************/
|
|
|
|
|
attrib_type at_road = {
|
|
|
|
|
"road",
|
|
|
|
|
DEFAULT_INIT,
|
|
|
|
|
DEFAULT_FINALIZE,
|
|
|
|
|
DEFAULT_AGE,
|
|
|
|
|
#if RELEASE_VERSION<NEWROAD_VERSION
|
|
|
|
|
DEFAULT_WRITE,
|
|
|
|
|
#else
|
|
|
|
|
NULL,
|
|
|
|
|
#endif
|
|
|
|
|
DEFAULT_READ
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
rsetroad(region * r, direction_t d, int val)
|
|
|
|
|
{
|
|
|
|
|
int rval;
|
|
|
|
|
border * b;
|
|
|
|
|
region * r2 = rconnect(r, d);
|
|
|
|
|
|
|
|
|
|
if (!r2) return;
|
|
|
|
|
b = get_borders(r, r2);
|
|
|
|
|
while (b && b->type!=&bt_road) b = b->next;
|
|
|
|
|
if (!b) b = new_border(&bt_road, r, r2);
|
|
|
|
|
rval = (int)b->data;
|
|
|
|
|
if (b->from==r)
|
|
|
|
|
rval = (rval & 0xFFFF) | (val<<16);
|
|
|
|
|
else
|
|
|
|
|
rval = (rval & 0xFFFF0000) | val;
|
|
|
|
|
b->data = (void*)rval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
rroad(const region * r, direction_t d)
|
|
|
|
|
{
|
|
|
|
|
int rval;
|
|
|
|
|
border * b;
|
|
|
|
|
region * r2 = rconnect(r, d);
|
|
|
|
|
|
|
|
|
|
if (!r2) return 0;
|
|
|
|
|
b = get_borders(r, r2);
|
|
|
|
|
while (b && b->type!=&bt_road) b = b->next;
|
|
|
|
|
if (!b) return 0;
|
|
|
|
|
rval = (int)b->data;
|
|
|
|
|
if (b->to==r)
|
|
|
|
|
rval = (rval & 0xFFFF);
|
|
|
|
|
else
|
|
|
|
|
rval = (rval & 0xFFFF0000) >> 16;
|
|
|
|
|
return rval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boolean
|
|
|
|
|
r_isforest(const region * r)
|
|
|
|
|
{
|
2001-12-15 13:26:04 +01:00
|
|
|
|
#if GROWING_TREES
|
2001-12-10 01:13:39 +01:00
|
|
|
|
if (r->terrain==T_PLAIN && rtrees(r,2) + rtrees(r,1) >= 600) return true;
|
|
|
|
|
#else
|
|
|
|
|
if (r->terrain==T_PLAIN && rtrees(r) >= 600) return true;
|
|
|
|
|
#endif
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-15 12:54:33 +01:00
|
|
|
|
boolean
|
|
|
|
|
r_issea(const region * r)
|
|
|
|
|
{
|
|
|
|
|
direction_t d;
|
|
|
|
|
|
|
|
|
|
for(d=0; d < MAXDIRECTIONS; d++) {
|
|
|
|
|
region *rc = rconnect(r,d);
|
|
|
|
|
if(rc && rterrain(rc) == T_OCEAN) return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-09-05 21:40:40 +02:00
|
|
|
|
boolean
|
|
|
|
|
r_isglacier(const region * r)
|
|
|
|
|
{
|
|
|
|
|
if (r->terrain==T_GLACIER || r->terrain==T_ICEBERG_SLEEP) return true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
int
|
|
|
|
|
is_coastregion(region *r)
|
|
|
|
|
{
|
|
|
|
|
direction_t i;
|
|
|
|
|
int res = 0;
|
|
|
|
|
|
|
|
|
|
for(i=0;i<MAXDIRECTIONS;i++) {
|
|
|
|
|
if(rconnect(r,i) && rconnect(r,i)->terrain == T_OCEAN) res++;
|
|
|
|
|
}
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
rpeasants(const region * r)
|
|
|
|
|
{
|
|
|
|
|
return ((r)->land?(r)->land->peasants:0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
rsetpeasants(region * r, int value)
|
|
|
|
|
{
|
|
|
|
|
((r)->land?((r)->land->peasants=(value)):(assert((value)>=0), (value)),0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
rmoney(const region * r)
|
|
|
|
|
{
|
|
|
|
|
return ((r)->land?(r)->land->money:0);
|
|
|
|
|
}
|
|
|
|
|
|
2002-04-28 09:53:07 +02:00
|
|
|
|
void
|
2002-04-28 15:06:27 +02:00
|
|
|
|
rsethorses(const region *r, int value)
|
2002-04-28 09:53:07 +02:00
|
|
|
|
{
|
2002-04-28 10:10:17 +02:00
|
|
|
|
assert(value >= 0);
|
|
|
|
|
if(r->land)
|
|
|
|
|
r->land->horses = value;
|
2002-04-28 09:53:07 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
2002-04-28 15:06:27 +02:00
|
|
|
|
rhorses(const region *r)
|
2002-04-28 09:53:07 +02:00
|
|
|
|
{
|
|
|
|
|
return r->land?r->land->horses:0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
void
|
|
|
|
|
rsetmoney(region * r, int value)
|
|
|
|
|
{
|
|
|
|
|
((r)->land?((r)->land->money=(value)):(assert((value)>=0), (value)),0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
r_setdemand(region * r, const luxury_type * ltype, int value)
|
|
|
|
|
{
|
|
|
|
|
struct demand * d, ** dp = &r->land->demands;
|
|
|
|
|
while (*dp && (*dp)->type != ltype) dp = &(*dp)->next;
|
|
|
|
|
d = *dp;
|
|
|
|
|
if (!d) {
|
|
|
|
|
d = *dp = calloc(sizeof(struct demand), 1);
|
|
|
|
|
d->type = ltype;
|
|
|
|
|
}
|
|
|
|
|
d->value = value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
r_demand(const region * r, const luxury_type * ltype)
|
|
|
|
|
{
|
|
|
|
|
struct demand * d = r->land->demands;
|
|
|
|
|
while (d && d->type != ltype) d = d->next;
|
|
|
|
|
if (!d) return -1;
|
|
|
|
|
return d->value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *
|
2002-09-02 22:36:12 +02:00
|
|
|
|
rname(const region * r, const struct locale * lang) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (r->land)
|
|
|
|
|
return r->land->name;
|
|
|
|
|
return locale_string(lang, terrain[rterrain(r)].name);
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-15 13:26:04 +01:00
|
|
|
|
#if GROWING_TREES
|
2001-09-05 21:40:40 +02:00
|
|
|
|
int
|
|
|
|
|
rtrees(const region *r, int ageclass)
|
|
|
|
|
{
|
|
|
|
|
return ((r)->land?(r)->land->trees[ageclass]:0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
2001-12-10 01:13:39 +01:00
|
|
|
|
rsettrees(const region *r, int ageclass, int value)
|
2001-09-05 21:40:40 +02:00
|
|
|
|
{
|
|
|
|
|
if (!r->land) assert(value==0);
|
|
|
|
|
else {
|
|
|
|
|
assert(value>=0);
|
|
|
|
|
return r->land->trees[ageclass]=value;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
#else
|
2001-01-25 10:37:55 +01:00
|
|
|
|
int
|
|
|
|
|
rtrees(const region *r)
|
|
|
|
|
{
|
|
|
|
|
return ((r)->land?(r)->land->trees:0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
2001-12-10 01:13:39 +01:00
|
|
|
|
rsettrees(const region *r, int value)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
if (!r->land) assert(value==0);
|
|
|
|
|
else {
|
|
|
|
|
assert(value>=0);
|
|
|
|
|
return r->land->trees=value;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2001-09-05 21:40:40 +02:00
|
|
|
|
#endif
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
static region *last;
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
region *
|
|
|
|
|
new_region(int x, int y)
|
|
|
|
|
{
|
|
|
|
|
region *r = rfindhash(x, y);
|
|
|
|
|
|
|
|
|
|
if (r) {
|
2001-12-16 10:57:46 +01:00
|
|
|
|
fprintf(stderr, "\ndoppelte regionen entdeckt: %s(%d,%d)\n", regionname(r, NULL), x, y);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (r->units)
|
|
|
|
|
fprintf(stderr, "doppelte region enth<74>lt einheiten\n");
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
r = calloc(1, sizeof(region));
|
|
|
|
|
r->x = x;
|
|
|
|
|
r->y = y;
|
|
|
|
|
r->planep = findplane(x, y);
|
|
|
|
|
set_string(&r->display, "");
|
|
|
|
|
rhash(r);
|
|
|
|
|
if (last)
|
|
|
|
|
addlist(&last, r);
|
|
|
|
|
else
|
|
|
|
|
addlist(®ions, r);
|
|
|
|
|
last = r;
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
static void
|
2001-02-03 14:45:35 +01:00
|
|
|
|
freeland(land_region * lr)
|
|
|
|
|
{
|
|
|
|
|
while (lr->demands) {
|
|
|
|
|
struct demand * d = lr->demands;
|
|
|
|
|
lr->demands = d->next;
|
|
|
|
|
free(d);
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (lr->name) free(lr->name);
|
|
|
|
|
free(lr);
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
void
|
|
|
|
|
free_region(region * r)
|
|
|
|
|
{
|
|
|
|
|
runhash(r);
|
|
|
|
|
if (last == r) last = NULL;
|
|
|
|
|
free(r->display);
|
|
|
|
|
if (r->land) freeland(r->land);
|
|
|
|
|
while (r->attribs) a_remove (&r->attribs, r->attribs);
|
|
|
|
|
free(r);
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
static char *
|
|
|
|
|
makename(void)
|
|
|
|
|
{
|
|
|
|
|
int s, v, k, e, p = 0, x = 0;
|
|
|
|
|
int nk, ne, nv, ns;
|
|
|
|
|
static char name[16];
|
2001-05-27 16:02:12 +02:00
|
|
|
|
const char *kons = "bcdfghklmnprstvwz",
|
2001-01-25 10:37:55 +01:00
|
|
|
|
*end = "nlrdst",
|
2001-05-27 16:02:12 +02:00
|
|
|
|
*vokal = "aaaaaaaaa<EFBFBD><EFBFBD>eeeeeeeee<EFBFBD><EFBFBD><EFBFBD>iiiiiiiii<EFBFBD><EFBFBD>ooooooooo<EFBFBD><EFBFBD><EFBFBD>uuuuuuuuu<EFBFBD>yy",
|
|
|
|
|
*start = "bcdgtskpvfr";
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
nk = strlen(kons);
|
|
|
|
|
ne = strlen(end);
|
|
|
|
|
nv = strlen(vokal);
|
|
|
|
|
ns = strlen(start);
|
|
|
|
|
|
|
|
|
|
for (s = rand() % 3 + 2; s > 0; s--) {
|
2001-05-27 16:02:12 +02:00
|
|
|
|
if (x > 0) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
k = rand() % nk;
|
|
|
|
|
name[p] = kons[k];
|
|
|
|
|
p++;
|
|
|
|
|
} else {
|
|
|
|
|
k = rand() % ns;
|
|
|
|
|
name[p] = start[k];
|
|
|
|
|
p++;
|
|
|
|
|
}
|
|
|
|
|
v = rand() % nv;
|
|
|
|
|
name[p] = vokal[v];
|
|
|
|
|
p++;
|
|
|
|
|
if (rand() % 3 == 2 || s == 1) {
|
|
|
|
|
e = rand() % ne;
|
|
|
|
|
name[p] = end[e];
|
|
|
|
|
p++;
|
|
|
|
|
x = 1;
|
|
|
|
|
} else
|
|
|
|
|
x = 0;
|
|
|
|
|
}
|
|
|
|
|
name[p] = '\0';
|
|
|
|
|
name[0] = (char) toupper(name[0]);
|
|
|
|
|
return name;
|
|
|
|
|
}
|
2001-02-03 14:45:35 +01:00
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
setluxuries(region * r, const luxury_type * sale)
|
|
|
|
|
{
|
|
|
|
|
const luxury_type * ltype;
|
2001-02-11 09:55:48 +01:00
|
|
|
|
|
2001-02-03 14:45:35 +01:00
|
|
|
|
assert(r->land);
|
2001-02-11 09:55:48 +01:00
|
|
|
|
|
|
|
|
|
if(r->land->demands) freelist(r->land->demands);
|
|
|
|
|
|
2001-02-03 14:45:35 +01:00
|
|
|
|
for (ltype=luxurytypes; ltype; ltype=ltype->next) {
|
|
|
|
|
struct demand * dmd = calloc(sizeof(struct demand), 1);
|
|
|
|
|
dmd->type = ltype;
|
|
|
|
|
if (ltype!=sale) dmd->value = 1 + rand() % 5;
|
|
|
|
|
dmd->next = r->land->demands;
|
|
|
|
|
r->land->demands = dmd;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
void
|
|
|
|
|
terraform(region * r, terrain_t t)
|
|
|
|
|
{
|
2001-04-16 16:34:19 +02:00
|
|
|
|
const struct locale * locale_de = find_locale("de");
|
2001-12-15 13:26:04 +01:00
|
|
|
|
#if NEW_RESOURCEGROWTH
|
2001-12-10 01:13:39 +01:00
|
|
|
|
rawmaterial **lrm;
|
|
|
|
|
int i;
|
|
|
|
|
#endif
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2001-09-05 21:40:40 +02:00
|
|
|
|
/* defaults: */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
rsetterrain(r, t);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
|
2001-12-15 13:26:04 +01:00
|
|
|
|
#if NEW_RESOURCEGROWTH
|
2001-12-10 01:13:39 +01:00
|
|
|
|
/* Resourcen, die nicht mehr vorkommen k<>nnen, l<>schen */
|
|
|
|
|
lrm = &r->resources;
|
|
|
|
|
while (*lrm) {
|
|
|
|
|
rawmaterial *rm = *lrm;
|
|
|
|
|
for (i=0; i!=3; ++i) {
|
|
|
|
|
if(terrain[r->terrain].rawmaterials[i].type == rm->type) break;
|
|
|
|
|
}
|
|
|
|
|
if (i==3) {
|
|
|
|
|
*lrm = rm->next;
|
|
|
|
|
free(rm);
|
|
|
|
|
} else {
|
|
|
|
|
lrm = &rm->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2001-12-15 13:26:04 +01:00
|
|
|
|
#if NEW_RESOURCEGROWTH == 0
|
2001-01-25 10:37:55 +01:00
|
|
|
|
rsetlaen(r, -1);
|
2001-09-05 21:40:40 +02:00
|
|
|
|
rsetiron(r, 0);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
#endif
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (!landregion(t)) {
|
|
|
|
|
if (r->land) {
|
|
|
|
|
freeland(r->land);
|
|
|
|
|
r->land = NULL;
|
|
|
|
|
}
|
2001-12-15 13:26:04 +01:00
|
|
|
|
#if GROWING_TREES
|
2001-12-10 01:13:39 +01:00
|
|
|
|
rsettrees(r, 0, 0);
|
|
|
|
|
rsettrees(r, 1, 0);
|
|
|
|
|
rsettrees(r, 2, 0);
|
|
|
|
|
#else
|
2001-01-25 10:37:55 +01:00
|
|
|
|
rsettrees(r, 0);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
#endif
|
2001-01-25 10:37:55 +01:00
|
|
|
|
rsethorses(r, 0);
|
2001-12-15 13:26:04 +01:00
|
|
|
|
#if NEW_RESOURCEGROWTH == 0
|
2001-01-25 10:37:55 +01:00
|
|
|
|
rsetiron(r, 0);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
rsetlaen(r, -1);
|
|
|
|
|
#endif
|
2001-01-25 10:37:55 +01:00
|
|
|
|
rsetpeasants(r, 0);
|
|
|
|
|
rsetmoney(r, 0);
|
|
|
|
|
freset(r, RF_ENCOUNTER);
|
|
|
|
|
freset(r, RF_MALLORN);
|
2001-09-05 21:40:40 +02:00
|
|
|
|
/* Beschreibung und Namen l<>schen */
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!r->land) {
|
2001-02-03 14:45:35 +01:00
|
|
|
|
static struct surround {
|
|
|
|
|
struct surround * next;
|
|
|
|
|
const luxury_type * type;
|
|
|
|
|
int value;
|
|
|
|
|
} *trash =NULL, *nb = NULL;
|
|
|
|
|
const luxury_type * ltype;
|
|
|
|
|
direction_t d;
|
|
|
|
|
int mnr = 0;
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
r->land = calloc(1, sizeof(land_region));
|
|
|
|
|
rsetname(r, makename());
|
2001-02-03 14:45:35 +01:00
|
|
|
|
for (d=0;d!=MAXDIRECTIONS;++d) {
|
|
|
|
|
region * nr = rconnect(r, d);
|
|
|
|
|
if (nr && nr->land) {
|
|
|
|
|
struct demand * sale = r->land->demands;
|
|
|
|
|
while (sale && sale->value!=0) sale=sale->next;
|
|
|
|
|
if (sale) {
|
|
|
|
|
struct surround * sr = nb;
|
|
|
|
|
while (sr && sr->type!=sale->type) sr=sr->next;
|
|
|
|
|
if (!sr) {
|
|
|
|
|
if (trash) {
|
|
|
|
|
sr = trash;
|
|
|
|
|
trash = trash->next;
|
|
|
|
|
} else {
|
|
|
|
|
sr = calloc(1, sizeof(struct surround));
|
|
|
|
|
}
|
|
|
|
|
sr->next = nb;
|
|
|
|
|
sr->type = sale->type;
|
|
|
|
|
sr->value = 1;
|
|
|
|
|
nb = sr;
|
|
|
|
|
} else sr->value++;
|
|
|
|
|
++mnr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!nb) {
|
|
|
|
|
int i;
|
|
|
|
|
if (g_maxluxuries==0) {
|
|
|
|
|
for (ltype = luxurytypes;ltype;ltype=ltype->next) ++g_maxluxuries;
|
|
|
|
|
}
|
|
|
|
|
i = rand() % g_maxluxuries;
|
|
|
|
|
ltype = luxurytypes;
|
|
|
|
|
while (i--) ltype=ltype->next;
|
|
|
|
|
} else {
|
|
|
|
|
int i = rand() % mnr;
|
|
|
|
|
struct surround * srd = nb;
|
|
|
|
|
while (i>srd->value) {
|
|
|
|
|
i-=srd->value;
|
|
|
|
|
srd=srd->next;
|
|
|
|
|
}
|
|
|
|
|
setluxuries(r, srd->type);
|
|
|
|
|
while (srd->next!=NULL) srd=srd->next;
|
|
|
|
|
srd->next=trash;
|
|
|
|
|
trash = nb;
|
|
|
|
|
nb = NULL;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (landregion(t)) {
|
|
|
|
|
const char *name = NULL;
|
2002-04-03 01:42:07 +02:00
|
|
|
|
if (terrain[r->terrain].herbs) {
|
|
|
|
|
int len=0;
|
|
|
|
|
while (terrain[r->terrain].herbs[len]) ++len;
|
|
|
|
|
if (len) name = terrain[r->terrain].herbs[rand()%len];
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (name != NULL) {
|
2001-04-16 16:34:19 +02:00
|
|
|
|
const item_type * itype = finditemtype(name, locale_de);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
const herb_type * htype = resource2herb(itype->rtype);
|
|
|
|
|
rsetherbtype(r, htype);
|
|
|
|
|
rsetherbs(r, (short)(50+rand()%31));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
rsetherbtype(r, NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rand() % 100 < ENCCHANCE) {
|
|
|
|
|
fset(r, RF_ENCOUNTER);
|
|
|
|
|
}
|
|
|
|
|
if (rand() % 100 < 3)
|
|
|
|
|
fset(r, RF_MALLORN);
|
|
|
|
|
else
|
|
|
|
|
freset(r, RF_MALLORN);
|
|
|
|
|
|
|
|
|
|
switch (t) {
|
|
|
|
|
case T_PLAIN:
|
|
|
|
|
rsethorses(r, rand() % (terrain[t].production_max / 5));
|
|
|
|
|
if(rand()%100 < 40) {
|
2001-12-15 13:26:04 +01:00
|
|
|
|
#if GROWING_TREES
|
2001-12-10 01:13:39 +01:00
|
|
|
|
rsettrees(r, 2, terrain[t].production_max * (30+rand()%40)/100);
|
|
|
|
|
rsettrees(r, 1, rtrees(r, 2)/4);
|
|
|
|
|
rsettrees(r, 0, rtrees(r, 2)/2);
|
|
|
|
|
#else
|
|
|
|
|
rsettrees(r, terrain[t].production_max * (30+rand()%40)/100);
|
|
|
|
|
#endif
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case T_MOUNTAIN:
|
2001-12-15 13:26:04 +01:00
|
|
|
|
#if NEW_RESOURCEGROWTH == 0
|
2001-01-25 10:37:55 +01:00
|
|
|
|
rsetiron(r, IRONSTART);
|
|
|
|
|
if (rand() % 100 < 8) rsetlaen(r, 5 + rand() % 5);
|
2001-09-05 21:40:40 +02:00
|
|
|
|
#endif
|
2001-01-25 10:37:55 +01:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case T_GLACIER:
|
2001-12-15 13:26:04 +01:00
|
|
|
|
#if NEW_RESOURCEGROWTH == 0
|
2001-09-05 21:40:40 +02:00
|
|
|
|
if (riron(r) <= 0){
|
|
|
|
|
rsetiron(r, GLIRONSTART);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2001-01-25 10:37:55 +01:00
|
|
|
|
break;
|
2001-09-05 21:40:40 +02:00
|
|
|
|
|
|
|
|
|
case T_ICEBERG_SLEEP:
|
|
|
|
|
/* Kann aus Gletscher entstehen und sollte diesem gleichen */
|
2001-12-15 13:26:04 +01:00
|
|
|
|
#if NEW_RESOURCEGROWTH == 0
|
2001-09-05 21:40:40 +02:00
|
|
|
|
if (riron(r) <= 0){
|
|
|
|
|
rsetiron(r, GLIRONSTART);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
2001-09-05 21:40:40 +02:00
|
|
|
|
#endif
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case T_VOLCANO:
|
|
|
|
|
case T_VOLCANO_SMOKING:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-15 13:26:04 +01:00
|
|
|
|
#if GROWING_TREES
|
2001-12-10 01:13:39 +01:00
|
|
|
|
/* Initialisierung irgendwann <20>ber rm_-Mechamismus machen */
|
|
|
|
|
if(t != T_PLAIN && rand()%100 < 20) {
|
|
|
|
|
rsettrees(r, 2, terrain[t].production_max * (30 + rand() % 40) / 100);
|
|
|
|
|
rsettrees(r, 1, rtrees(r, 2)/4);
|
|
|
|
|
rsettrees(r, 0, rtrees(r, 2)/2);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2001-12-15 13:26:04 +01:00
|
|
|
|
#if NEW_RESOURCEGROWTH
|
2001-09-05 21:40:40 +02:00
|
|
|
|
terraform_resources(r);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (terrain[t].production_max && !fval(r, RF_CHAOTIC)) {
|
2002-01-27 18:22:04 +01:00
|
|
|
|
int peasants;
|
|
|
|
|
#if REDUCED_PEASANTGROWTH == 1
|
|
|
|
|
peasants = (maxworkingpeasants(r) * (20+dice_rand("6d10")))/100;
|
|
|
|
|
#else
|
|
|
|
|
peasants = MAXPEASANTS_PER_AREA * (rand() % (terrain[t].production_max / 2));
|
|
|
|
|
#endif
|
|
|
|
|
rsetpeasants(r, max(100, peasants));
|
2001-09-05 21:40:40 +02:00
|
|
|
|
rsetmoney(r, rpeasants(r) * ((wage(r, NULL, false)+1) + rand() % 5));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** ENNO:
|
|
|
|
|
* ich denke, das das hier nicht sein sollte.
|
|
|
|
|
* statt dessen sollte ein attribut an der region sein, das das erledigt,
|
|
|
|
|
* egal ob durch den spell oder anderes angelegt.
|
|
|
|
|
**/
|
|
|
|
|
#include "curse.h"
|
|
|
|
|
int
|
|
|
|
|
production(const region *r)
|
|
|
|
|
{
|
|
|
|
|
/* mu<6D> r->terrain sein, nicht rterrain() wegen rekursion */
|
|
|
|
|
int p = terrain[r->terrain].production_max;
|
2002-05-01 21:08:32 +02:00
|
|
|
|
if (curse_active(get_curse(r->attribs, ct_find("drought")))) p /= 2;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
|
2002-04-07 02:44:01 +02:00
|
|
|
|
int
|
2001-01-25 10:37:55 +01:00
|
|
|
|
read_region_reference(region ** r, FILE * F)
|
|
|
|
|
{
|
|
|
|
|
int x[2];
|
|
|
|
|
fscanf(F, "%d %d", &x[0], &x[1]);
|
2002-04-07 02:44:01 +02:00
|
|
|
|
if (x[0]==INT_MAX) {
|
|
|
|
|
*r = NULL;
|
|
|
|
|
return AT_READ_FAIL;
|
2001-01-28 09:01:52 +01:00
|
|
|
|
}
|
2002-04-07 02:44:01 +02:00
|
|
|
|
*r = findregion(x[0], x[1]);
|
|
|
|
|
if (*r==NULL) ur_add(memcpy(malloc(sizeof(x)), x, sizeof(x)), (void**)r, resolve_region);
|
|
|
|
|
return AT_READ_OK;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
write_region_reference(const region * r, FILE * F)
|
|
|
|
|
{
|
2001-01-28 09:01:52 +01:00
|
|
|
|
if (r) fprintf(F, "%d %d ", r->x, r->y);
|
|
|
|
|
else fprintf(F, "%d %d ", INT_MAX, INT_MAX);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void *
|
|
|
|
|
resolve_region(void * id) {
|
|
|
|
|
int * c = (int*)id;
|
|
|
|
|
int x = c[0], y = c[1];
|
|
|
|
|
free(c);
|
|
|
|
|
return findregion(x, y);
|
|
|
|
|
}
|
|
|
|
|
|
2001-05-20 09:46:13 +02:00
|
|
|
|
|
|
|
|
|
struct message_list *
|
2001-09-05 21:40:40 +02:00
|
|
|
|
r_getmessages(const struct region * r, const struct faction * viewer)
|
2001-05-20 09:46:13 +02:00
|
|
|
|
{
|
|
|
|
|
struct individual_message * imsg = r->individual_messages;
|
|
|
|
|
while (imsg && (imsg)->viewer!=viewer) imsg = imsg->next;
|
|
|
|
|
if (imsg) return imsg->msgs;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2001-05-20 23:47:56 +02:00
|
|
|
|
struct message *
|
2001-05-20 09:46:13 +02:00
|
|
|
|
r_addmessage(struct region * r, const struct faction * viewer, struct message * msg)
|
|
|
|
|
{
|
|
|
|
|
struct individual_message * imsg;
|
|
|
|
|
assert(r);
|
|
|
|
|
imsg = r->individual_messages;
|
|
|
|
|
while (imsg && imsg->viewer!=viewer) imsg = imsg->next;
|
|
|
|
|
if (imsg==NULL) {
|
|
|
|
|
imsg = malloc(sizeof(struct individual_message));
|
|
|
|
|
imsg->next = r->individual_messages;
|
2001-05-20 10:41:11 +02:00
|
|
|
|
imsg->msgs = NULL;
|
2001-05-20 09:46:13 +02:00
|
|
|
|
r->individual_messages = imsg;
|
|
|
|
|
imsg->viewer = viewer;
|
|
|
|
|
}
|
2001-05-20 23:47:56 +02:00
|
|
|
|
return add_message(&imsg->msgs, msg);
|
2001-05-27 16:02:12 +02:00
|
|
|
|
}
|
2001-09-05 21:40:40 +02:00
|
|
|
|
|
2002-12-18 01:34:19 +01:00
|
|
|
|
struct unit *
|
|
|
|
|
region_owner(const struct region * r)
|
|
|
|
|
{
|
|
|
|
|
#ifdef REGIONOWNERS
|
|
|
|
|
struct unit * owner = NULL;
|
|
|
|
|
int maxsize = 0;
|
|
|
|
|
building * b = r->buildings;
|
|
|
|
|
for (;b!=NULL;b=b->next) {
|
|
|
|
|
if (b->size>maxsize) {
|
|
|
|
|
unit * u = buildingowner(r, b);
|
|
|
|
|
if (u) {
|
|
|
|
|
owner = u;
|
|
|
|
|
maxsize=b->size;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return owner;
|
|
|
|
|
#else
|
|
|
|
|
return NULL;
|
|
|
|
|
#endif
|
|
|
|
|
}
|