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)
|
|
|
|
|
*
|
|
|
|
|
* This program may not be used, modified or distributed without
|
|
|
|
|
* prior permission by the authors of Eressea.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#include "eressea.h"
|
|
|
|
|
#include "border.h"
|
|
|
|
|
|
|
|
|
|
#include "unit.h"
|
|
|
|
|
#include "region.h"
|
|
|
|
|
|
|
|
|
|
/* libc includes */
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
unsigned int nextborder = 0;
|
|
|
|
|
|
|
|
|
|
border * borders[BMAXHASH];
|
|
|
|
|
border_type * bordertypes;
|
|
|
|
|
|
|
|
|
|
|
2001-12-10 01:13:39 +01:00
|
|
|
|
void
|
|
|
|
|
free_borders(void)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
for (i=0;i!=BMAXHASH;++i) {
|
|
|
|
|
borders[i] = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
border *
|
|
|
|
|
find_border(unsigned int id)
|
|
|
|
|
{
|
|
|
|
|
int key;
|
|
|
|
|
for (key=0;key!=BMAXHASH;key++) {
|
|
|
|
|
border * b;
|
|
|
|
|
for (b=borders[key];b;b=b->next) {
|
|
|
|
|
if (b->id==id) return b;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void *
|
|
|
|
|
resolve_borderid(void * id) {
|
|
|
|
|
return (void*)find_border((unsigned int)id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
border *
|
|
|
|
|
get_borders(const region * r1, const region * r2)
|
|
|
|
|
{
|
|
|
|
|
border * b;
|
|
|
|
|
int key = region_hashkey(r1);
|
|
|
|
|
int k2 = region_hashkey(r2);
|
|
|
|
|
|
|
|
|
|
key = min(k2, key) % BMAXHASH;
|
|
|
|
|
b = borders[key];
|
|
|
|
|
while (b && !((b->from==r1 && b->to==r2) || (b->from==r2 && b->to==r1))) b = b->nexthash;
|
|
|
|
|
return b;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
write_borders(FILE * f)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
for (i=0;i!=BMAXHASH;++i) {
|
|
|
|
|
border * b;
|
|
|
|
|
for (b=borders[i];b;b=b->nexthash) {
|
|
|
|
|
if (b->type->valid && !b->type->valid(b)) continue;
|
|
|
|
|
fprintf(f, "%s %d %d %d %d %d ", b->type->__name, b->id, b->from->x, b->from->y, b->to->x, b->to->y);
|
|
|
|
|
if (b->type->write) b->type->write(b, f);
|
|
|
|
|
putc('\n', f);
|
|
|
|
|
#if RELEASE_VERSION>BORDER_VERSION
|
|
|
|
|
a_write(f, b->attribs);
|
2001-01-28 09:01:52 +01:00
|
|
|
|
putc('\n', f);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-28 09:01:52 +01:00
|
|
|
|
fputs("end", f);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
read_borders(FILE * f)
|
|
|
|
|
{
|
|
|
|
|
for (;;) {
|
|
|
|
|
int fx, fy, tx, ty;
|
|
|
|
|
unsigned int bid = 0;
|
2001-02-10 11:40:12 +01:00
|
|
|
|
char zText[32];
|
2001-01-25 10:37:55 +01:00
|
|
|
|
border * b;
|
|
|
|
|
region * from, * to;
|
|
|
|
|
border_type * type;
|
2001-02-10 11:40:12 +01:00
|
|
|
|
|
|
|
|
|
fscanf(f, "%s", zText);
|
|
|
|
|
if (!strcmp(zText, "end")) break;
|
2002-09-02 22:36:12 +02:00
|
|
|
|
fscanf(f, "%u %d %d %d %d", &bid, &fx, &fy, &tx, &ty);
|
2001-02-10 11:40:12 +01:00
|
|
|
|
type = find_bordertype(zText);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
assert(type || !"border type not registered");
|
|
|
|
|
from = findregion(fx, fy);
|
|
|
|
|
if (!from) {
|
2001-02-18 13:11:32 +01:00
|
|
|
|
log_error(("border for unknown region %d,%d\n", fx, fy));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
from = new_region(fx, fy);
|
|
|
|
|
}
|
|
|
|
|
to = findregion(tx, ty);
|
|
|
|
|
if (!to) {
|
2001-02-18 13:11:32 +01:00
|
|
|
|
log_error(("border for unknown region %d,%d\n", tx, ty));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
to = new_region(tx, ty);
|
|
|
|
|
}
|
|
|
|
|
if (to==from) {
|
|
|
|
|
direction_t dir = (direction_t) (rand() % MAXDIRECTIONS);
|
|
|
|
|
region * r = rconnect(from, dir);
|
- 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
|
|
|
|
log_error(("[read_borders] invalid %s in %s\n", type->__name, regionname(from, NULL)));
|
2001-01-25 10:37:55 +01:00
|
|
|
|
if (r!=NULL) to = r;
|
|
|
|
|
}
|
|
|
|
|
b = new_border(type, from, to);
|
|
|
|
|
nextborder--; /* new_border erh<72>ht den Wert */
|
|
|
|
|
b->id = bid;
|
|
|
|
|
assert(bid<=nextborder);
|
|
|
|
|
if (type->read) type->read(b, f);
|
2002-09-02 22:36:12 +02:00
|
|
|
|
a_read(f, &b->attribs);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
border *
|
|
|
|
|
new_border(border_type * type, region * from, region * to)
|
|
|
|
|
{
|
|
|
|
|
border ** bp, * b;
|
|
|
|
|
int key = region_hashkey(from);
|
|
|
|
|
int k2 = region_hashkey(to);
|
|
|
|
|
|
|
|
|
|
key = min(k2, key) % BMAXHASH;
|
|
|
|
|
bp = &borders[key];
|
|
|
|
|
while (*bp && !(((*bp)->from==from && (*bp)->to==to) || ((*bp)->from==to && (*bp)->to==from))) bp = &(*bp)->nexthash;
|
|
|
|
|
b = calloc(1, sizeof(struct border));
|
|
|
|
|
b->type = type;
|
|
|
|
|
b->nexthash = *bp;
|
|
|
|
|
b->next = *bp;
|
|
|
|
|
b->from = from;
|
|
|
|
|
b->to = to;
|
|
|
|
|
b->id = ++nextborder;
|
|
|
|
|
*bp = b;
|
|
|
|
|
if (type->init) type->init(b);
|
|
|
|
|
return b;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
erase_border(border * b)
|
|
|
|
|
{
|
|
|
|
|
border ** np, ** hp;
|
|
|
|
|
int key = region_hashkey(b->from);
|
|
|
|
|
int k2 = region_hashkey(b->to);
|
|
|
|
|
attrib ** ap = &b->attribs;
|
|
|
|
|
|
|
|
|
|
while (*ap) a_remove(ap, *ap);
|
|
|
|
|
key = min(k2, key) % BMAXHASH;
|
|
|
|
|
hp = np = &borders[key];
|
|
|
|
|
while (*np && *np != b) np = &(*np)->next;
|
|
|
|
|
while (*hp && *hp != b) hp = &(*hp)->nexthash;
|
|
|
|
|
assert((*np && *hp) || !"error: border is not registered");
|
|
|
|
|
*np = b->next;
|
|
|
|
|
*hp = b->nexthash;
|
|
|
|
|
if (b->type->destroy) b->type->destroy(b);
|
|
|
|
|
free(b);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
register_bordertype(border_type * type)
|
|
|
|
|
{
|
|
|
|
|
border_type ** btp = &bordertypes;
|
|
|
|
|
|
|
|
|
|
while (*btp && *btp!=type) btp = &(*btp)->next;
|
|
|
|
|
if (*btp) return;
|
|
|
|
|
*btp = type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
border_type *
|
|
|
|
|
find_bordertype(const char * name)
|
|
|
|
|
{
|
|
|
|
|
border_type * bt = bordertypes;
|
|
|
|
|
|
|
|
|
|
while (bt && strcmp(bt->__name, name)) bt = bt->next;
|
|
|
|
|
return bt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
b_read(border * b, FILE *f)
|
|
|
|
|
{
|
|
|
|
|
assert(sizeof(int)==sizeof(b->data));
|
2002-09-02 22:36:12 +02:00
|
|
|
|
fscanf(f, "%x ", (unsigned int*)&b->data);
|
2001-01-25 10:37:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
b_write(const border * b, FILE *f)
|
|
|
|
|
{
|
|
|
|
|
assert(sizeof(int)==sizeof(b->data));
|
|
|
|
|
fprintf(f, "%x ", (int)b->data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boolean b_transparent(const border * b, const struct faction * f) { unused(b); unused(f); return true; }
|
|
|
|
|
boolean b_opaque(const border * b, const struct faction * f) { unused(b); unused(f); return false; }
|
|
|
|
|
boolean b_blockall(const border * b, const unit * u, const region * r) { unused(u); unused(r); unused(b); return true; }
|
|
|
|
|
boolean b_blocknone(const border * b, const unit * u, const region * r) { unused(u); unused(r); unused(b); return false; }
|
|
|
|
|
boolean b_rvisible(const border * b, const region * r) { return (boolean)(b->to==r || b->from==r); }
|
|
|
|
|
boolean b_fvisible(const border * b, const struct faction * f, const region * r) { unused(r); unused(f); unused(b); return true; }
|
|
|
|
|
boolean b_uvisible(const border * b, const unit * u) { unused(u); unused(b); return true; }
|
|
|
|
|
boolean b_rinvisible(const border * b, const region * r) { unused(r); unused(b); return false; }
|
|
|
|
|
boolean b_finvisible(const border * b, const struct faction * f, const region * r) { unused(r); unused(f); unused(b); return false; }
|
|
|
|
|
boolean b_uinvisible(const border * b, const unit * u) { unused(u); unused(b); return false; }
|
|
|
|
|
|
|
|
|
|
/*********************/
|
|
|
|
|
/* at_countdown */
|
|
|
|
|
/*********************/
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
a_agecountdown(attrib * a)
|
|
|
|
|
{
|
|
|
|
|
a->data.i = max(a->data.i-1, 0);
|
|
|
|
|
return a->data.i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
attrib_type at_countdown = {
|
|
|
|
|
"countdown",
|
|
|
|
|
DEFAULT_INIT,
|
|
|
|
|
DEFAULT_FINALIZE,
|
|
|
|
|
a_agecountdown,
|
|
|
|
|
DEFAULT_WRITE,
|
|
|
|
|
DEFAULT_READ
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
age_borders(void)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i=0;i!=BMAXHASH;++i) {
|
|
|
|
|
border ** bp = &borders[i];
|
|
|
|
|
while (*bp) {
|
|
|
|
|
border * b = *bp;
|
|
|
|
|
attrib ** ap = &b->attribs;
|
|
|
|
|
while(*ap) {
|
|
|
|
|
attrib * a = *ap;
|
|
|
|
|
if(a->type->age && a->type->age(a)==0) {
|
|
|
|
|
if (a->type == &at_countdown) {
|
|
|
|
|
erase_border(b);
|
|
|
|
|
b = NULL;
|
|
|
|
|
/* bp bleibt, wie es ist, da der
|
|
|
|
|
* n<EFBFBD>chste border nun hier drin steht. */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
a_remove(ap, a);
|
|
|
|
|
}
|
|
|
|
|
else ap=&a->next;
|
|
|
|
|
}
|
|
|
|
|
if (!b) continue; /* bei l<>schung bp nicht vorziehen */
|
|
|
|
|
bp=&b->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/********
|
|
|
|
|
* implementation of a couple of borders. this shouldn't really be in here, so
|
|
|
|
|
* let's keep it separate from the more general stuff above
|
|
|
|
|
********/
|
|
|
|
|
|
|
|
|
|
#include "faction.h"
|
|
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
|
b_namewall(const border * b, const region * r, const struct faction * f, int gflags)
|
|
|
|
|
{
|
|
|
|
|
unused(f);
|
|
|
|
|
unused(r);
|
|
|
|
|
unused(b);
|
|
|
|
|
if (gflags & GF_ARTICLE) return "eine Wand";
|
|
|
|
|
return "Wand";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
border_type bt_wall = {
|
|
|
|
|
"wall",
|
|
|
|
|
b_opaque,
|
|
|
|
|
NULL, /* init */
|
|
|
|
|
NULL, /* destroy */
|
|
|
|
|
b_read, /* read */
|
|
|
|
|
b_write, /* write */
|
|
|
|
|
b_blockall, /* block */
|
|
|
|
|
b_namewall, /* name */
|
|
|
|
|
b_rvisible, /* rvisible */
|
|
|
|
|
b_fvisible, /* fvisible */
|
|
|
|
|
b_uvisible, /* uvisible */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
border_type bt_noway = {
|
|
|
|
|
"noway",
|
|
|
|
|
b_transparent,
|
|
|
|
|
NULL, /* init */
|
|
|
|
|
NULL, /* destroy */
|
|
|
|
|
b_read, /* read */
|
|
|
|
|
b_write, /* write */
|
|
|
|
|
b_blockall, /* block */
|
|
|
|
|
NULL, /* name */
|
|
|
|
|
b_rinvisible, /* rvisible */
|
|
|
|
|
b_finvisible, /* fvisible */
|
|
|
|
|
b_uinvisible, /* uvisible */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
|
b_namefogwall(const border * b, const region * r, const struct faction * f, int gflags)
|
|
|
|
|
{
|
|
|
|
|
unused(f);
|
|
|
|
|
unused(b);
|
|
|
|
|
unused(r);
|
|
|
|
|
if (gflags & GF_ARTICLE) return "eine Nebelwand";
|
|
|
|
|
return "Nebelwand";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static boolean
|
|
|
|
|
b_blockfogwall(const border * b, const unit * u, const region * r)
|
|
|
|
|
{
|
|
|
|
|
unused(b);
|
|
|
|
|
unused(r);
|
|
|
|
|
if (!u) return true;
|
|
|
|
|
return (boolean)(effskill(u, SK_OBSERVATION) > 4); /* Das ist die alte Nebelwand */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
border_type bt_fogwall = {
|
|
|
|
|
"fogwall",
|
|
|
|
|
b_transparent, /* transparent */
|
|
|
|
|
NULL, /* init */
|
|
|
|
|
NULL, /* destroy */
|
|
|
|
|
b_read, /* read */
|
|
|
|
|
b_write, /* write */
|
|
|
|
|
b_blockfogwall, /* block */
|
|
|
|
|
b_namefogwall, /* name */
|
|
|
|
|
b_rvisible, /* rvisible */
|
|
|
|
|
b_fvisible, /* fvisible */
|
|
|
|
|
b_uvisible, /* uvisible */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
|
b_nameillusionwall(const border * b, const region * r, const struct faction * f, int gflags)
|
|
|
|
|
{
|
|
|
|
|
/* TODO: f->locale bestimmt die Sprache */
|
|
|
|
|
int fno = (int)b->data;
|
|
|
|
|
unused(b);
|
|
|
|
|
unused(r);
|
|
|
|
|
if (gflags & GF_ARTICLE) return (f && fno==f->no)?"eine Illusionswand":"eine Wand";
|
|
|
|
|
return (f && fno==f->no)?"Illusionswand":"Wand";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
border_type bt_illusionwall = {
|
|
|
|
|
"illusionwall",
|
|
|
|
|
b_opaque,
|
|
|
|
|
NULL, /* init */
|
|
|
|
|
NULL, /* destroy */
|
|
|
|
|
b_read, /* read */
|
|
|
|
|
b_write, /* write */
|
|
|
|
|
b_blocknone, /* block */
|
|
|
|
|
b_nameillusionwall, /* name */
|
|
|
|
|
b_rvisible, /* rvisible */
|
|
|
|
|
b_fvisible, /* fvisible */
|
|
|
|
|
b_uvisible, /* uvisible */
|
|
|
|
|
};
|
|
|
|
|
|
2002-04-27 16:25:35 +02:00
|
|
|
|
/***
|
|
|
|
|
* special quest door
|
|
|
|
|
***/
|
|
|
|
|
|
|
|
|
|
boolean b_blockquestportal(const border * b, const unit * u, const region * r) {
|
|
|
|
|
if((int)b->data > 0) return true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
|
b_namequestportal(const border * b, const region * r, const struct faction * f, int gflags)
|
|
|
|
|
{
|
|
|
|
|
/* TODO: f->locale bestimmt die Sprache */
|
|
|
|
|
int lock = (int)b->data;
|
|
|
|
|
unused(b);
|
|
|
|
|
unused(r);
|
|
|
|
|
|
|
|
|
|
if (gflags & GF_ARTICLE) {
|
|
|
|
|
if(lock > 0) {
|
|
|
|
|
return "ein gewaltiges verschlossenes Tor";
|
|
|
|
|
} else {
|
|
|
|
|
return "ein gewaltiges offenes Tor";
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if(lock > 0) {
|
|
|
|
|
return "gewaltiges verschlossenes Tor";
|
|
|
|
|
} else {
|
|
|
|
|
return "gewaltiges offenes Tor";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
border_type bt_questportal = {
|
|
|
|
|
"questportal",
|
|
|
|
|
b_opaque,
|
|
|
|
|
NULL, /* init */
|
|
|
|
|
NULL, /* destroy */
|
|
|
|
|
b_read, /* read */
|
|
|
|
|
b_write, /* write */
|
|
|
|
|
b_blockquestportal, /* block */
|
|
|
|
|
b_namequestportal, /* name */
|
|
|
|
|
b_rvisible, /* rvisible */
|
|
|
|
|
b_fvisible, /* fvisible */
|
|
|
|
|
b_uvisible, /* uvisible */
|
|
|
|
|
};
|
|
|
|
|
|
2001-01-25 10:37:55 +01:00
|
|
|
|
/***
|
|
|
|
|
* roads. meant to replace the old at_road or r->road attribute
|
|
|
|
|
***/
|
|
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
|
b_nameroad(const border * b, const region * r, const struct faction * f, int gflags)
|
|
|
|
|
{
|
|
|
|
|
region * r2 = (r==b->to)?b->from:b->to;
|
|
|
|
|
int rval = (int)b->data;
|
|
|
|
|
int local = (r==b->to)?(rval & 0xFFFF):((rval>>16) & 0xFFFF);
|
|
|
|
|
static char buffer[64];
|
|
|
|
|
|
|
|
|
|
unused(f);
|
|
|
|
|
if (gflags & GF_ARTICLE) {
|
|
|
|
|
if (!(gflags & GF_DETAILED)) strcpy(buffer, "eine Stra<72>e");
|
2002-05-26 22:51:20 +02:00
|
|
|
|
else if (terrain[rterrain(r)].roadreq<=local) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
int remote = (r!=b->to)?(rval & 0xFFFF):((rval>>16) & 0xFFFF);
|
2002-05-26 22:51:20 +02:00
|
|
|
|
if (terrain[rterrain(r2)].roadreq<=remote) {
|
2001-01-25 10:37:55 +01:00
|
|
|
|
strcpy(buffer, "eine Stra<72>e");
|
|
|
|
|
} else {
|
|
|
|
|
strcpy(buffer, "eine unvollst<73>ndige Stra<72>e");
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
int percent = max(1, 100*local/terrain[rterrain(r)].roadreq);
|
|
|
|
|
if (local) {
|
|
|
|
|
sprintf(buffer, "eine zu %d%% vollendete Stra<72>e", percent);
|
|
|
|
|
} else {
|
|
|
|
|
strcpy(buffer, "ein Stra<72>enanschlu<6C>");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (gflags & GF_PLURAL) return "Stra<EFBFBD>en";
|
|
|
|
|
else return "Stra<EFBFBD>e";
|
|
|
|
|
return buffer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
b_readroad(border * b, FILE *f)
|
|
|
|
|
{
|
|
|
|
|
int x, y;
|
|
|
|
|
fscanf(f, "%d %d", &x, &y);
|
|
|
|
|
b->data=(void*)((x<<16) | y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
b_writeroad(const border * b, FILE *f)
|
|
|
|
|
{
|
|
|
|
|
int x, y;
|
|
|
|
|
x = (int)b->data;
|
|
|
|
|
y = x & 0xFFFF;
|
|
|
|
|
x = (x >> 16) & 0xFFFF;
|
|
|
|
|
fprintf(f, "%d %d", x, y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static boolean
|
|
|
|
|
b_validroad(const border * b)
|
|
|
|
|
{
|
|
|
|
|
int x = (int)b->data;
|
|
|
|
|
if (x==0) return false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static boolean
|
|
|
|
|
b_rvisibleroad(const border * b, const region * r)
|
|
|
|
|
{
|
|
|
|
|
int x = (int)b->data;
|
|
|
|
|
x = (r==b->to)?(x & 0xFFFF):((x>>16) & 0xFFFF);
|
|
|
|
|
if (x==0) return false;
|
|
|
|
|
return (boolean)(b->to==r || b->from==r);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
border_type bt_road = {
|
|
|
|
|
"road",
|
|
|
|
|
b_transparent,
|
|
|
|
|
NULL, /* init */
|
|
|
|
|
NULL, /* destroy */
|
|
|
|
|
b_readroad, /* read */
|
|
|
|
|
b_writeroad, /* write */
|
|
|
|
|
b_blocknone, /* block */
|
|
|
|
|
b_nameroad, /* name */
|
|
|
|
|
b_rvisibleroad, /* rvisible */
|
|
|
|
|
b_finvisible, /* fvisible */
|
|
|
|
|
b_uinvisible, /* uvisible */
|
|
|
|
|
b_validroad /* valid */
|
|
|
|
|
};
|
2001-04-22 20:14:07 +02:00
|
|
|
|
|