2001-01-25 10:37:55 +01:00
|
|
|
|
/* vi: set ts=2:
|
|
|
|
|
*
|
2001-04-14 13:39:14 +02:00
|
|
|
|
*
|
2003-07-29 11:48:03 +02:00
|
|
|
|
* Eressea PB(E)M host Copyright (C) 1998-2003
|
2001-01-25 10:37:55 +01:00
|
|
|
|
* Christian Schlittchen (corwin@amber.kn-bremen.de)
|
|
|
|
|
* Katja Zedel (katze@felidae.kn-bremen.de)
|
|
|
|
|
* Henning Peters (faroul@beyond.kn-bremen.de)
|
|
|
|
|
* Enno Rehling (enno@eressea-pbem.de)
|
|
|
|
|
* Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
|
|
|
|
|
*
|
|
|
|
|
* based on:
|
|
|
|
|
*
|
|
|
|
|
* Atlantis v1.0 13 September 1993 Copyright 1993 by Russell Wallace
|
|
|
|
|
* Atlantis v1.7 Copyright 1996 by Alex Schr<EFBFBD>der
|
|
|
|
|
*
|
|
|
|
|
* This program may not be used, modified or distributed without
|
|
|
|
|
* prior permission by the authors of Eressea.
|
|
|
|
|
* This program may not be sold or used commercially without prior written
|
|
|
|
|
* permission from the authors.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#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"
|
2005-12-11 10:58:17 +01:00
|
|
|
|
#include "equipment.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"
|
2005-10-25 14:38:01 +02:00
|
|
|
|
#include "terrain.h"
|
|
|
|
|
#include "terrainid.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>
|
2005-10-25 14:38:01 +02:00
|
|
|
|
#include <rand.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);
|
|
|
|
|
|
2005-11-26 01:08:47 +01:00
|
|
|
|
int
|
|
|
|
|
get_maxluxuries()
|
|
|
|
|
{
|
|
|
|
|
static int maxluxuries = -1;
|
|
|
|
|
if (maxluxuries==-1) {
|
|
|
|
|
const luxury_type * ltype;
|
|
|
|
|
maxluxuries = 0;
|
|
|
|
|
for (ltype = luxurytypes;ltype;ltype=ltype->next) ++maxluxuries;
|
|
|
|
|
}
|
|
|
|
|
return maxluxuries;
|
|
|
|
|
}
|
2005-06-10 00:10:35 +02:00
|
|
|
|
const short delta_x[MAXDIRECTIONS] =
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2004-04-12 18:21:23 +02:00
|
|
|
|
-1, 0, 1, 1, 0, -1
|
2001-01-25 10:37:55 +01:00
|
|
|
|
};
|
|
|
|
|
|
2005-06-10 00:10:35 +02:00
|
|
|
|
const short delta_y[MAXDIRECTIONS] =
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2004-04-12 18:21:23 +02:00
|
|
|
|
1, 1, 0, -1, -1, 0
|
2001-01-25 10:37:55 +01:00
|
|
|
|
};
|
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
static const direction_t back[MAXDIRECTIONS] =
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2004-04-12 18:21:23 +02:00
|
|
|
|
D_SOUTHEAST,
|
|
|
|
|
D_SOUTHWEST,
|
|
|
|
|
D_WEST,
|
|
|
|
|
D_NORTHWEST,
|
|
|
|
|
D_NORTHEAST,
|
|
|
|
|
D_EAST,
|
2001-01-25 10:37:55 +01:00
|
|
|
|
};
|
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
direction_t
|
|
|
|
|
dir_invert(direction_t dir)
|
|
|
|
|
{
|
|
|
|
|
switch (dir) {
|
|
|
|
|
case D_PAUSE:
|
|
|
|
|
case D_SPECIAL:
|
|
|
|
|
return dir;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
if (dir>=0 && dir<MAXDIRECTIONS) return back[dir];
|
|
|
|
|
}
|
|
|
|
|
assert(!"illegal direction");
|
|
|
|
|
return NODIRECTION;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
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];
|
2005-01-01 18:14:51 +01:00
|
|
|
|
const struct locale * lang = f ? f->locale : 0;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
plane *pl = getplane(r);
|
2003-06-22 12:13:22 +02:00
|
|
|
|
if (r==NULL) {
|
|
|
|
|
strcpy(buf, "(null)");
|
2001-01-25 10:37:55 +01:00
|
|
|
|
} else if (pl && fval(pl, PFL_NOCOORDS)) {
|
2005-01-01 18:14:51 +01:00
|
|
|
|
strncpy(buf, rname(r, lang), 65);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
} else {
|
2001-02-05 17:11:59 +01:00
|
|
|
|
#ifdef HAVE_SNPRINTF
|
2005-01-01 18:14:51 +01:00
|
|
|
|
snprintf(buf, 65, "%s (%d,%d)", rname(r, lang),
|
|
|
|
|
region_x(r, f), region_y(r, f));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#else
|
2005-01-01 18:14:51 +01:00
|
|
|
|
strncpy(buf, rname(r, lang), 50);
|
2001-02-05 17:11:59 +01:00
|
|
|
|
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);
|
|
|
|
|
|
2004-04-09 03:32:06 +02:00
|
|
|
|
if (d->duration > 0) d->duration--;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
else d->duration = 0;
|
|
|
|
|
|
|
|
|
|
return d->duration;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
a_readdirection(attrib *a, FILE *f)
|
|
|
|
|
{
|
|
|
|
|
spec_direction *d = (spec_direction *)(a->data.v);
|
2005-06-10 00:10:35 +02:00
|
|
|
|
fscanf(f, "%hd %hd %d", &d->x, &d->y, &d->duration);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
fscanf(f, "%s ", buf);
|
|
|
|
|
d->desc = strdup(cstring(buf));
|
|
|
|
|
fscanf(f, "%s ", buf);
|
|
|
|
|
d->keyword = strdup(cstring(buf));
|
2004-04-09 03:23:54 +02:00
|
|
|
|
d->active = true;
|
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
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2005-01-01 12:48:36 +01:00
|
|
|
|
attrib *
|
|
|
|
|
create_special_direction(region *r, region * rt, int duration,
|
|
|
|
|
const char *desc, const char *keyword)
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
attrib *a = a_add(&r->attribs, a_new(&at_direction));
|
|
|
|
|
spec_direction *d = (spec_direction *)(a->data.v);
|
|
|
|
|
|
|
|
|
|
d->active = false;
|
|
|
|
|
d->x = rt->x;
|
|
|
|
|
d->y = rt->y;
|
|
|
|
|
d->duration = duration;
|
|
|
|
|
d->desc = strdup(desc);
|
|
|
|
|
d->keyword = strdup(keyword);
|
|
|
|
|
|
|
|
|
|
return a;
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/* 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
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2004-05-26 08:42:58 +02:00
|
|
|
|
#define RMAXHASH 65521
|
2001-01-25 10:37:55 +01:00
|
|
|
|
region *regionhash[RMAXHASH];
|
|
|
|
|
|
|
|
|
|
static region *
|
2005-06-10 00:10:35 +02:00
|
|
|
|
rfindhash(short x, short y)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
region *old;
|
2005-06-10 00:10:35 +02:00
|
|
|
|
for (old = regionhash[coor_hashkey(x, y) % RMAXHASH]; old; old = old->nexthash)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (old->x == x && old->y == y)
|
|
|
|
|
return old;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
rhash(region * r)
|
|
|
|
|
{
|
2005-06-10 00:10:35 +02:00
|
|
|
|
int key = coor_hashkey(r->x, r->y) % RMAXHASH;
|
|
|
|
|
region *old = regionhash[key];
|
|
|
|
|
regionhash[key] = r;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
r->nexthash = old;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
runhash(region * r)
|
|
|
|
|
{
|
|
|
|
|
region **show;
|
2005-06-10 00:10:35 +02:00
|
|
|
|
for (show = ®ionhash[coor_hashkey(r->x, r->y) % RMAXHASH]; *show; show = &(*show)->nexthash) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if ((*show)->x == r->x && (*show)->y == r->y)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (*show) {
|
|
|
|
|
assert(*show == r);
|
|
|
|
|
*show = (*show)->nexthash;
|
|
|
|
|
r->nexthash = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
region *
|
2004-01-12 17:22:14 +01:00
|
|
|
|
r_connect(const region * r, direction_t dir)
|
2004-01-12 16:49:34 +01:00
|
|
|
|
{
|
2001-01-25 10:37:55 +01:00
|
|
|
|
static int set = 0;
|
|
|
|
|
static region * buffer[MAXDIRECTIONS];
|
|
|
|
|
static const region * last = NULL;
|
2004-01-12 16:49:34 +01:00
|
|
|
|
|
|
|
|
|
#ifdef FAST_CONNECT
|
2004-01-12 17:22:14 +01:00
|
|
|
|
region * rmodify = (region*)r;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
assert (dir>=0 && dir<MAXDIRECTIONS);
|
2004-01-12 17:22:14 +01:00
|
|
|
|
if (r->connect[dir]) return r->connect[dir];
|
2004-01-12 16:49:34 +01:00
|
|
|
|
#endif
|
2004-01-12 17:22:14 +01:00
|
|
|
|
assert(dir<MAXDIRECTIONS);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
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);
|
2004-01-12 16:49:34 +01:00
|
|
|
|
#ifdef FAST_CONNECT
|
2004-01-12 17:22:14 +01:00
|
|
|
|
rmodify->connect[dir] = buffer[dir];
|
2004-01-12 16:49:34 +01:00
|
|
|
|
#endif
|
2001-01-25 10:37:55 +01:00
|
|
|
|
return buffer[dir];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
region *
|
2005-06-10 00:10:35 +02:00
|
|
|
|
findregion(short x, short y)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2004-04-12 18:21:23 +02:00
|
|
|
|
static direction_t
|
2001-01-25 10:37:55 +01:00
|
|
|
|
koor_reldirection(int ax, int ay, int bx, int by)
|
|
|
|
|
{
|
2004-04-12 18:21:23 +02:00
|
|
|
|
direction_t dir;
|
|
|
|
|
for (dir=0;dir!=MAXDIRECTIONS;++dir) {
|
|
|
|
|
if (bx-ax == delta_x[dir] && by-ay == delta_y[dir]) return dir;
|
|
|
|
|
}
|
|
|
|
|
return NODIRECTION;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
spec_direction *
|
|
|
|
|
special_direction(const region * from, const region * to)
|
|
|
|
|
{
|
|
|
|
|
const attrib *a = a_findc(from->attribs, &at_direction);
|
|
|
|
|
|
|
|
|
|
while (a!=NULL) {
|
2005-01-01 12:48:36 +01:00
|
|
|
|
spec_direction * sd = (spec_direction *)a->data.v;
|
|
|
|
|
if (sd->x==to->x && sd->y==to->y) return sd;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
a = a->nexttype;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
direction_t
|
2004-04-12 18:21:23 +02:00
|
|
|
|
reldirection(const region * from, const region * to)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2004-04-12 18:21:23 +02:00
|
|
|
|
direction_t dir = koor_reldirection(from->x, from->y, to->x, to->y);
|
|
|
|
|
|
|
|
|
|
if (dir==NODIRECTION) {
|
|
|
|
|
spec_direction *sd = special_direction(from, to);
|
2005-01-01 12:48:36 +01:00
|
|
|
|
if (sd!=NULL && sd->active) return D_SPECIAL;
|
2004-04-12 18:21:23 +02:00
|
|
|
|
}
|
|
|
|
|
return dir;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2004-02-21 13:18:29 +01:00
|
|
|
|
free_regionlist(region_list *rl)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2001-02-10 20:24:05 +01:00
|
|
|
|
while (rl) {
|
2004-02-21 13:18:29 +01:00
|
|
|
|
region_list * rl2 = rl->next;
|
2001-02-10 20:24:05 +01:00
|
|
|
|
free(rl);
|
|
|
|
|
rl = rl2;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2002-01-09 09:20:33 +01:00
|
|
|
|
void
|
2004-02-21 13:18:29 +01:00
|
|
|
|
add_regionlist(region_list **rl, region *r)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
2004-02-21 13:18:29 +01:00
|
|
|
|
region_list *rl2 = (region_list*)malloc(sizeof(region_list));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2004-02-21 13:18:29 +01:00
|
|
|
|
rl2->data = r;
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/********************/
|
|
|
|
|
/* 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-10 01:13:39 +01:00
|
|
|
|
extern int laen_read(attrib * a, FILE * F);
|
2005-10-24 22:06:40 +02:00
|
|
|
|
#define LAEN_READ laen_read
|
|
|
|
|
#define LAEN_WRITE NULL
|
2001-12-10 01:13:39 +01:00
|
|
|
|
|
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 = {
|
2005-06-10 00:10:35 +02:00
|
|
|
|
"road",
|
2001-01-25 10:37:55 +01:00
|
|
|
|
DEFAULT_INIT,
|
|
|
|
|
DEFAULT_FINALIZE,
|
|
|
|
|
DEFAULT_AGE,
|
|
|
|
|
#if RELEASE_VERSION<NEWROAD_VERSION
|
|
|
|
|
DEFAULT_WRITE,
|
|
|
|
|
#else
|
|
|
|
|
NULL,
|
|
|
|
|
#endif
|
|
|
|
|
DEFAULT_READ
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void
|
2005-06-12 11:48:19 +02:00
|
|
|
|
rsetroad(region * r, direction_t d, short val)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
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);
|
2005-06-12 11:48:19 +02:00
|
|
|
|
if (r==b->from) b->data.sa[0] = val;
|
|
|
|
|
else b->data.sa[1] = val;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2005-06-12 11:48:19 +02:00
|
|
|
|
short
|
2001-01-25 10:37:55 +01:00
|
|
|
|
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;
|
2005-06-10 00:10:35 +02:00
|
|
|
|
rval = b->data.i;
|
2005-06-12 11:48:19 +02:00
|
|
|
|
if (r==b->from) return b->data.sa[0];
|
|
|
|
|
return b->data.sa[1];
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boolean
|
|
|
|
|
r_isforest(const region * r)
|
|
|
|
|
{
|
2005-10-25 14:38:01 +02:00
|
|
|
|
if (fval(r->terrain, FOREST_REGION)) {
|
|
|
|
|
/* needs to be covered with at leas 48% trees */
|
|
|
|
|
int mincover = (int)(r->terrain->size * 0.48);
|
|
|
|
|
int trees = rtrees(r, 2) + rtrees(r, 1);
|
|
|
|
|
return (trees*TREESIZE >= mincover);
|
|
|
|
|
}
|
2001-09-05 21:40:40 +02:00
|
|
|
|
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++) {
|
2005-10-25 14:38:01 +02:00
|
|
|
|
region * rn = rconnect(r,i);
|
|
|
|
|
if (rn && fval(rn->terrain, SEA_REGION)) res++;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
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;
|
2005-11-26 02:24:28 +01:00
|
|
|
|
|
|
|
|
|
if (ltype==NULL) return;
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
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;
|
2005-10-25 14:38:01 +02:00
|
|
|
|
return locale_string(lang, terrain_name(r));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
static region *last;
|
|
|
|
|
|
2005-04-27 23:03:08 +02:00
|
|
|
|
static unsigned int max_index = 0;
|
2006-01-21 09:34:01 +01:00
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
region *
|
2005-06-10 00:10:35 +02:00
|
|
|
|
new_region(short x, short y)
|
2001-01-25 10:37:55 +01:00
|
|
|
|
{
|
|
|
|
|
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;
|
2006-01-01 21:56:11 +01:00
|
|
|
|
r->age = 1;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
r->planep = findplane(x, y);
|
|
|
|
|
set_string(&r->display, "");
|
|
|
|
|
rhash(r);
|
|
|
|
|
if (last)
|
|
|
|
|
addlist(&last, r);
|
|
|
|
|
else
|
|
|
|
|
addlist(®ions, r);
|
|
|
|
|
last = r;
|
2005-04-27 23:03:08 +02:00
|
|
|
|
assert(r->next==NULL);
|
|
|
|
|
r->index = ++max_index;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
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)
|
|
|
|
|
{
|
2005-05-07 15:38:46 +02:00
|
|
|
|
runhash(r);
|
|
|
|
|
if (last == r) last = NULL;
|
|
|
|
|
free(r->display);
|
|
|
|
|
if (r->land) freeland(r->land);
|
|
|
|
|
|
|
|
|
|
if (r->msgs) {
|
|
|
|
|
free_messagelist(r->msgs);
|
|
|
|
|
r->msgs = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (r->individual_messages) {
|
|
|
|
|
struct individual_message * msg = r->individual_messages;
|
|
|
|
|
r->individual_messages = msg->next;
|
2005-06-04 03:43:38 +02:00
|
|
|
|
if (msg->msgs) free_messagelist(msg->msgs);
|
2005-05-07 15:38:46 +02:00
|
|
|
|
free(msg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (r->attribs) a_remove (&r->attribs, r->attribs);
|
|
|
|
|
while (r->resources) {
|
|
|
|
|
rawmaterial * res = r->resources;
|
|
|
|
|
r->resources = res->next;
|
|
|
|
|
free(res);
|
|
|
|
|
}
|
2005-06-11 10:09:55 +02:00
|
|
|
|
|
|
|
|
|
while (r->donations) {
|
|
|
|
|
donation * don = r->donations;
|
|
|
|
|
r->donations = don->next;
|
|
|
|
|
free(don);
|
|
|
|
|
}
|
|
|
|
|
|
2005-05-07 15:38:46 +02:00
|
|
|
|
free(r);
|
2001-12-10 01:13:39 +01:00
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
static char *
|
|
|
|
|
makename(void)
|
|
|
|
|
{
|
|
|
|
|
int s, v, k, e, p = 0, x = 0;
|
2005-06-10 00:10:35 +02:00
|
|
|
|
size_t nk, ne, nv, ns;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
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) {
|
2005-06-10 00:10:35 +02:00
|
|
|
|
k = rand() % (int)nk;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
name[p] = kons[k];
|
|
|
|
|
p++;
|
|
|
|
|
} else {
|
2005-06-10 00:10:35 +02:00
|
|
|
|
k = rand() % (int)ns;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
name[p] = start[k];
|
|
|
|
|
p++;
|
|
|
|
|
}
|
2005-06-10 00:10:35 +02:00
|
|
|
|
v = rand() % (int)nv;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
name[p] = vokal[v];
|
|
|
|
|
p++;
|
|
|
|
|
if (rand() % 3 == 2 || s == 1) {
|
2005-06-10 00:10:35 +02:00
|
|
|
|
e = rand() % (int)ne;
|
2001-01-25 10:37:55 +01:00
|
|
|
|
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)
|
|
|
|
|
{
|
2005-10-25 14:38:01 +02:00
|
|
|
|
terraform_region(r, newterrain(t));
|
|
|
|
|
}
|
2001-12-10 01:13:39 +01:00
|
|
|
|
|
2005-10-25 14:38:01 +02:00
|
|
|
|
void
|
|
|
|
|
terraform_region(region * r, const terrain_type * terrain)
|
|
|
|
|
{
|
2001-12-10 01:13:39 +01:00
|
|
|
|
/* Resourcen, die nicht mehr vorkommen k<>nnen, l<>schen */
|
2005-11-11 23:53:58 +01:00
|
|
|
|
const terrain_type * oldterrain = r->terrain;
|
|
|
|
|
|
2005-10-25 14:38:01 +02:00
|
|
|
|
rawmaterial **lrm = &r->resources;
|
|
|
|
|
while (*lrm) {
|
|
|
|
|
rawmaterial *rm = *lrm;
|
|
|
|
|
const resource_type * rtype = NULL;
|
|
|
|
|
|
|
|
|
|
if (terrain->production!=NULL) {
|
|
|
|
|
int i;
|
|
|
|
|
for (i=0;terrain->production[i].type;++i) {
|
|
|
|
|
if (rm->type->rtype == terrain->production[i].type) {
|
|
|
|
|
rtype = rm->type->rtype;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (rtype==NULL) {
|
|
|
|
|
*lrm = rm->next;
|
|
|
|
|
free(rm);
|
|
|
|
|
} else {
|
|
|
|
|
lrm = &rm->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-12-10 01:13:39 +01:00
|
|
|
|
|
2005-10-25 14:38:01 +02:00
|
|
|
|
r->terrain = terrain;
|
2005-12-19 18:31:27 +01:00
|
|
|
|
terraform_resources(r);
|
2005-10-25 14:38:01 +02:00
|
|
|
|
|
|
|
|
|
if (!fval(terrain, LAND_REGION)) {
|
2005-11-11 23:53:58 +01:00
|
|
|
|
if (r->land!=NULL) {
|
2005-12-11 10:58:17 +01:00
|
|
|
|
i_freeall(&r->land->items);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
freeland(r->land);
|
|
|
|
|
r->land = NULL;
|
|
|
|
|
}
|
2001-12-10 01:13:39 +01:00
|
|
|
|
rsettrees(r, 0, 0);
|
|
|
|
|
rsettrees(r, 1, 0);
|
|
|
|
|
rsettrees(r, 2, 0);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
rsethorses(r, 0);
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2005-12-11 10:58:17 +01:00
|
|
|
|
if (r->land) {
|
|
|
|
|
i_freeall(&r->land->items);
|
|
|
|
|
} else {
|
2001-02-03 14:45:35 +01:00
|
|
|
|
static struct surround {
|
|
|
|
|
struct surround * next;
|
|
|
|
|
const luxury_type * type;
|
|
|
|
|
int value;
|
|
|
|
|
} *trash =NULL, *nb = NULL;
|
2005-11-26 01:08:47 +01:00
|
|
|
|
const luxury_type * ltype = NULL;
|
2001-02-03 14:45:35 +01:00
|
|
|
|
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) {
|
2005-11-26 01:08:47 +01:00
|
|
|
|
int i = get_maxluxuries();
|
|
|
|
|
if (i>0) {
|
|
|
|
|
i = rand() % i;
|
|
|
|
|
ltype = luxurytypes;
|
|
|
|
|
while (i--) ltype=ltype->next;
|
|
|
|
|
}
|
2001-02-03 14:45:35 +01:00
|
|
|
|
} else {
|
|
|
|
|
int i = rand() % mnr;
|
|
|
|
|
struct surround * srd = nb;
|
|
|
|
|
while (i>srd->value) {
|
|
|
|
|
i-=srd->value;
|
|
|
|
|
srd=srd->next;
|
|
|
|
|
}
|
2005-11-26 02:16:55 +01:00
|
|
|
|
if (srd->type) setluxuries(r, srd->type);
|
2001-02-03 14:45:35 +01:00
|
|
|
|
while (srd->next!=NULL) srd=srd->next;
|
|
|
|
|
srd->next=trash;
|
|
|
|
|
trash = nb;
|
|
|
|
|
nb = NULL;
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2005-10-25 14:38:01 +02:00
|
|
|
|
if (fval(terrain, LAND_REGION)) {
|
|
|
|
|
const item_type * itype = NULL;
|
2005-12-11 10:58:17 +01:00
|
|
|
|
char equip_hash[64];
|
|
|
|
|
|
|
|
|
|
/* TODO: put the equipment in struct terrain, faster */
|
|
|
|
|
sprintf(equip_hash, "terrain_%s", terrain->_name);
|
|
|
|
|
equip_items(&r->land->items, get_equipment(equip_hash));
|
|
|
|
|
|
|
|
|
|
if (r->terrain->herbs) {
|
2002-04-03 01:42:07 +02:00
|
|
|
|
int len=0;
|
2005-10-25 14:38:01 +02:00
|
|
|
|
while (r->terrain->herbs[len]) ++len;
|
|
|
|
|
if (len) itype = r->terrain->herbs[rand()%len];
|
2002-04-03 01:42:07 +02:00
|
|
|
|
}
|
2005-10-25 14:38:01 +02:00
|
|
|
|
if (itype!=NULL) {
|
|
|
|
|
rsetherbtype(r, itype);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
rsetherbs(r, (short)(50+rand()%31));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
rsetherbtype(r, NULL);
|
|
|
|
|
}
|
2005-11-14 19:58:09 +01:00
|
|
|
|
if (oldterrain==NULL || !fval(oldterrain, LAND_REGION)) {
|
2005-11-11 23:53:58 +01:00
|
|
|
|
if (rand() % 100 < 3) fset(r, RF_MALLORN);
|
|
|
|
|
else freset(r, RF_MALLORN);
|
|
|
|
|
if (rand() % 100 < ENCCHANCE) {
|
|
|
|
|
fset(r, RF_ENCOUNTER);
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2005-11-14 19:58:09 +01:00
|
|
|
|
if (oldterrain==NULL || terrain->size!=oldterrain->size) {
|
2005-11-11 23:53:58 +01:00
|
|
|
|
if (terrain==newterrain(T_PLAIN)) {
|
|
|
|
|
rsethorses(r, rand() % (terrain->size / 50));
|
|
|
|
|
if(rand()%100 < 40) {
|
|
|
|
|
rsettrees(r, 2, terrain->size * (30+rand()%40)/1000);
|
|
|
|
|
rsettrees(r, 1, rtrees(r, 2)/4);
|
|
|
|
|
rsettrees(r, 0, rtrees(r, 2)/2);
|
|
|
|
|
}
|
|
|
|
|
} else if (chance(0.2)) {
|
|
|
|
|
rsettrees(r, 2, terrain->size * (30 + rand() % 40) / 1000);
|
2005-10-25 14:38:01 +02:00
|
|
|
|
rsettrees(r, 1, rtrees(r, 2)/4);
|
|
|
|
|
rsettrees(r, 0, rtrees(r, 2)/2);
|
|
|
|
|
}
|
2001-12-10 01:13:39 +01:00
|
|
|
|
|
2005-11-11 23:53:58 +01:00
|
|
|
|
if (!fval(r, RF_CHAOTIC)) {
|
|
|
|
|
int peasants;
|
|
|
|
|
peasants = (maxworkingpeasants(r) * (20+dice_rand("6d10")))/100;
|
|
|
|
|
rsetpeasants(r, max(100, peasants));
|
2005-11-20 13:58:59 +01:00
|
|
|
|
rsetmoney(r, rpeasants(r) * ((wage(r, NULL, NULL)+1) + rand() % 5));
|
2005-11-11 23:53:58 +01:00
|
|
|
|
}
|
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)
|
|
|
|
|
{
|
2005-10-25 14:38:01 +02:00
|
|
|
|
/* mu<6D> rterrain(r) sein, nicht rterrain() wegen rekursion */
|
|
|
|
|
int p = r->terrain->size / MAXPEASANTS_PER_AREA;
|
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)
|
|
|
|
|
{
|
2005-06-10 00:10:35 +02:00
|
|
|
|
variant coor;
|
|
|
|
|
fscanf(F, "%hd %hd", &coor.sa[0], &coor.sa[1]);
|
|
|
|
|
if (coor.sa[0]==SHRT_MAX) {
|
2002-04-07 02:44:01 +02:00
|
|
|
|
*r = NULL;
|
|
|
|
|
return AT_READ_FAIL;
|
2001-01-28 09:01:52 +01:00
|
|
|
|
}
|
2005-06-10 00:10:35 +02:00
|
|
|
|
*r = findregion(coor.sa[0], coor.sa[1]);
|
|
|
|
|
|
|
|
|
|
if (*r==NULL) {
|
|
|
|
|
ur_add(coor, (void**)r, resolve_region);
|
|
|
|
|
}
|
2002-04-07 02:44:01 +02:00
|
|
|
|
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);
|
2005-06-10 00:10:35 +02:00
|
|
|
|
else fprintf(F, "%d %d ", SHRT_MAX, SHRT_MAX);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void *
|
2005-06-10 00:10:35 +02:00
|
|
|
|
resolve_region(variant id) {
|
|
|
|
|
return findregion(id.sa[0], id.sa[1]);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
|
2005-11-20 13:58:59 +01:00
|
|
|
|
struct faction *
|
2002-12-18 01:34:19 +01:00
|
|
|
|
region_owner(const struct region * r)
|
|
|
|
|
{
|
|
|
|
|
#ifdef REGIONOWNERS
|
2005-11-20 13:58:59 +01:00
|
|
|
|
return r->owner;
|
2002-12-18 01:34:19 +01:00
|
|
|
|
#else
|
|
|
|
|
return NULL;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
2005-11-20 13:58:59 +01:00
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
region_setowner(struct region * r, struct faction * owner)
|
|
|
|
|
{
|
|
|
|
|
#ifdef REGIONOWNERS
|
|
|
|
|
r->owner = owner;
|
|
|
|
|
#else
|
2005-11-20 15:50:15 +01:00
|
|
|
|
unused(r);
|
|
|
|
|
unused(owner);
|
2005-11-20 13:58:59 +01:00
|
|
|
|
#endif
|
|
|
|
|
}
|