2018-01-01 08:23:52 +01:00
|
|
|
#ifdef _MSC_VER
|
2010-08-08 10:06:34 +02:00
|
|
|
#include <platform.h>
|
2018-01-01 08:23:52 +01:00
|
|
|
#endif
|
2010-08-08 10:06:34 +02:00
|
|
|
#include <kernel/config.h>
|
|
|
|
#include "connection.h"
|
|
|
|
|
|
|
|
#include "region.h"
|
|
|
|
#include "terrain.h"
|
|
|
|
#include "unit.h"
|
|
|
|
|
2018-09-29 11:37:17 +02:00
|
|
|
#include <kernel/attrib.h>
|
2017-12-11 18:20:21 +01:00
|
|
|
#include <util/base36.h>
|
2018-09-29 13:21:46 +02:00
|
|
|
#include <kernel/gamedata.h>
|
2010-08-08 10:06:34 +02:00
|
|
|
#include <util/language.h>
|
|
|
|
#include <util/log.h>
|
2017-12-29 06:13:28 +01:00
|
|
|
#include <util/macros.h>
|
2010-08-08 10:06:34 +02:00
|
|
|
#include <util/rng.h>
|
2017-12-11 18:20:21 +01:00
|
|
|
#include <util/strings.h>
|
2013-12-31 10:06:28 +01:00
|
|
|
|
2017-12-11 18:20:21 +01:00
|
|
|
#include <selist.h>
|
2013-12-31 10:06:28 +01:00
|
|
|
#include <storage.h>
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
|
|
/* libc includes */
|
|
|
|
#include <assert.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <string.h>
|
2017-12-11 18:20:21 +01:00
|
|
|
#include <stdio.h>
|
2014-03-15 19:29:11 +01:00
|
|
|
#include <stdlib.h>
|
2010-08-08 10:06:34 +02:00
|
|
|
|
2014-05-10 18:57:04 +02:00
|
|
|
int nextborder = 0;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
|
|
#define BORDER_MAXHASH 8191
|
2011-03-07 08:02:35 +01:00
|
|
|
connection *borders[BORDER_MAXHASH];
|
|
|
|
border_type *bordertypes;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
2015-01-30 20:37:14 +01:00
|
|
|
void(*border_convert_cb) (struct connection * con, struct attrib * attr) = 0;
|
2011-03-07 08:02:35 +01:00
|
|
|
|
|
|
|
void free_borders(void)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2015-01-30 20:37:14 +01:00
|
|
|
int i;
|
|
|
|
for (i = 0; i != BORDER_MAXHASH; ++i) {
|
|
|
|
while (borders[i]) {
|
|
|
|
connection *b = borders[i];
|
|
|
|
borders[i] = b->nexthash;
|
|
|
|
while (b) {
|
|
|
|
connection *bf = b;
|
|
|
|
b = b->next;
|
|
|
|
assert(b == NULL || b->nexthash == NULL);
|
|
|
|
if (bf->type->destroy) {
|
|
|
|
bf->type->destroy(bf);
|
|
|
|
}
|
|
|
|
free(bf);
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-22 00:39:30 +02:00
|
|
|
static void walk_i(region *r, connection *b, void(*cb)(connection *, void *), void *data) {
|
|
|
|
for (; b; b = b->nexthash) {
|
|
|
|
if (b->from == r || b->to == r) {
|
|
|
|
connection *bn;
|
|
|
|
for (bn = b; bn; bn = bn->next) {
|
|
|
|
cb(b, data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void walk_connections(region *r, void(*cb)(connection *, void *), void *data) {
|
|
|
|
int key = reg_hashkey(r);
|
|
|
|
int d;
|
|
|
|
|
|
|
|
walk_i(r, borders[key], cb, data);
|
|
|
|
for (d = 0; d != MAXDIRECTIONS; ++d) {
|
|
|
|
region *rn = r_connect(r, d);
|
2015-10-30 12:57:07 +01:00
|
|
|
if (rn) {
|
|
|
|
int k = reg_hashkey(rn);
|
|
|
|
if (k < key) {
|
|
|
|
walk_i(r, borders[k], cb, data);
|
|
|
|
}
|
2014-07-22 00:39:30 +02:00
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
static connection **get_borders_i(const region * r1, const region * r2)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2015-01-30 20:37:14 +01:00
|
|
|
connection **bp;
|
|
|
|
int key = reg_hashkey(r1);
|
|
|
|
int k2 = reg_hashkey(r2);
|
|
|
|
|
2018-01-01 08:23:52 +01:00
|
|
|
if (key > k2) key = k2;
|
|
|
|
key = key % BORDER_MAXHASH;
|
2015-01-30 20:37:14 +01:00
|
|
|
bp = &borders[key];
|
|
|
|
while (*bp) {
|
|
|
|
connection *b = *bp;
|
|
|
|
if ((b->from == r1 && b->to == r2) || (b->from == r2 && b->to == r1))
|
|
|
|
break;
|
|
|
|
bp = &b->nexthash;
|
|
|
|
}
|
|
|
|
return bp;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
connection *get_borders(const region * r1, const region * r2)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2015-01-30 20:37:14 +01:00
|
|
|
connection **bp = get_borders_i(r1, r2);
|
|
|
|
return *bp;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
connection *new_border(border_type * type, region * from, region * to)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2018-02-25 17:58:45 +01:00
|
|
|
connection *b, **bp;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
2015-11-04 19:20:34 +01:00
|
|
|
assert(from && to);
|
2018-02-25 17:58:45 +01:00
|
|
|
bp = get_borders_i(from, to);
|
2015-11-04 19:20:34 +01:00
|
|
|
while (*bp) {
|
|
|
|
bp = &(*bp)->next;
|
2015-01-30 20:37:14 +01:00
|
|
|
}
|
2015-11-04 19:20:34 +01:00
|
|
|
*bp = b = calloc(1, sizeof(connection));
|
2018-12-15 20:01:51 +01:00
|
|
|
if (!b) abort();
|
2015-01-30 20:37:14 +01:00
|
|
|
b->type = type;
|
|
|
|
b->from = from;
|
|
|
|
b->to = to;
|
|
|
|
b->id = ++nextborder;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
2015-01-30 20:37:14 +01:00
|
|
|
if (type->init)
|
|
|
|
type->init(b);
|
|
|
|
return b;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
void erase_border(connection * b)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2015-01-30 20:37:14 +01:00
|
|
|
if (b->from && b->to) {
|
|
|
|
connection **bp = get_borders_i(b->from, b->to);
|
|
|
|
assert(*bp != NULL || !"error: connection is not registered");
|
|
|
|
if (*bp == b) {
|
|
|
|
/* it is the first in the list, so it is in the nexthash list */
|
|
|
|
if (b->next) {
|
|
|
|
*bp = b->next;
|
|
|
|
(*bp)->nexthash = b->nexthash;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
*bp = b->nexthash;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
while (*bp && *bp != b) {
|
|
|
|
bp = &(*bp)->next;
|
|
|
|
}
|
|
|
|
assert(*bp == b || !"error: connection is not registered");
|
|
|
|
*bp = b->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (b->type->destroy) {
|
|
|
|
b->type->destroy(b);
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
2015-01-30 20:37:14 +01:00
|
|
|
free(b);
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
void register_bordertype(border_type * type)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2015-01-30 20:37:14 +01:00
|
|
|
border_type **btp = &bordertypes;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
2015-01-30 20:37:14 +01:00
|
|
|
while (*btp && *btp != type)
|
|
|
|
btp = &(*btp)->next;
|
|
|
|
if (*btp)
|
|
|
|
return;
|
|
|
|
*btp = type;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
border_type *find_bordertype(const char *name)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2015-01-30 20:37:14 +01:00
|
|
|
border_type *bt = bordertypes;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
2018-06-11 20:42:28 +02:00
|
|
|
while (bt && strcmp(bt->_name, name)!=0)
|
2015-01-30 20:37:14 +01:00
|
|
|
bt = bt->next;
|
|
|
|
return bt;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
2016-02-13 14:29:44 +01:00
|
|
|
void b_read(connection * b, gamedata * data)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2016-02-13 14:29:44 +01:00
|
|
|
storage * store = data->store;
|
2018-02-11 15:43:24 +01:00
|
|
|
int n;
|
2015-01-30 20:37:14 +01:00
|
|
|
switch (b->type->datatype) {
|
2010-08-08 10:06:34 +02:00
|
|
|
case VAR_NONE:
|
|
|
|
case VAR_INT:
|
2015-01-30 20:37:14 +01:00
|
|
|
READ_INT(store, &b->data.i);
|
|
|
|
break;
|
2010-08-08 10:06:34 +02:00
|
|
|
case VAR_SHORTA:
|
2015-01-30 20:37:14 +01:00
|
|
|
READ_INT(store, &n);
|
|
|
|
b->data.sa[0] = (short)n;
|
|
|
|
READ_INT(store, &n);
|
|
|
|
b->data.sa[1] = (short)n;
|
|
|
|
break;
|
2010-08-08 10:06:34 +02:00
|
|
|
case VAR_VOIDPTR:
|
|
|
|
default:
|
2015-01-30 20:37:14 +01:00
|
|
|
assert(!"invalid variant type in connection");
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
void b_write(const connection * b, storage * store)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2015-01-30 20:37:14 +01:00
|
|
|
switch (b->type->datatype) {
|
2010-08-08 10:06:34 +02:00
|
|
|
case VAR_NONE:
|
|
|
|
case VAR_INT:
|
2015-01-30 20:37:14 +01:00
|
|
|
WRITE_INT(store, b->data.i);
|
|
|
|
break;
|
2010-08-08 10:06:34 +02:00
|
|
|
case VAR_SHORTA:
|
2015-01-30 20:37:14 +01:00
|
|
|
WRITE_INT(store, b->data.sa[0]);
|
|
|
|
WRITE_INT(store, b->data.sa[1]);
|
|
|
|
break;
|
2010-08-08 10:06:34 +02:00
|
|
|
case VAR_VOIDPTR:
|
|
|
|
default:
|
2015-01-30 20:37:14 +01:00
|
|
|
assert(!"invalid variant type in connection");
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
2012-06-24 07:41:07 +02:00
|
|
|
bool b_transparent(const connection * b, const struct faction *f)
|
2011-03-07 08:02:35 +01:00
|
|
|
{
|
2017-01-10 16:31:05 +01:00
|
|
|
UNUSED_ARG(b);
|
|
|
|
UNUSED_ARG(f);
|
2015-01-30 20:37:14 +01:00
|
|
|
return true;
|
2011-03-07 08:02:35 +01:00
|
|
|
}
|
|
|
|
|
2012-06-24 07:41:07 +02:00
|
|
|
bool b_opaque(const connection * b, const struct faction * f)
|
2011-03-07 08:02:35 +01:00
|
|
|
{
|
2017-01-10 16:31:05 +01:00
|
|
|
UNUSED_ARG(b);
|
|
|
|
UNUSED_ARG(f);
|
2015-01-30 20:37:14 +01:00
|
|
|
return false;
|
2011-03-07 08:02:35 +01:00
|
|
|
}
|
|
|
|
|
2012-06-24 07:41:07 +02:00
|
|
|
bool b_blockall(const connection * b, const unit * u, const region * r)
|
2011-03-07 08:02:35 +01:00
|
|
|
{
|
2017-01-10 16:31:05 +01:00
|
|
|
UNUSED_ARG(u);
|
|
|
|
UNUSED_ARG(r);
|
|
|
|
UNUSED_ARG(b);
|
2015-01-30 20:37:14 +01:00
|
|
|
return true;
|
2011-03-07 08:02:35 +01:00
|
|
|
}
|
|
|
|
|
2012-06-24 07:41:07 +02:00
|
|
|
bool b_blocknone(const connection * b, const unit * u, const region * r)
|
2011-03-07 08:02:35 +01:00
|
|
|
{
|
2017-01-10 16:31:05 +01:00
|
|
|
UNUSED_ARG(u);
|
|
|
|
UNUSED_ARG(r);
|
|
|
|
UNUSED_ARG(b);
|
2015-01-30 20:37:14 +01:00
|
|
|
return false;
|
2011-03-07 08:02:35 +01:00
|
|
|
}
|
|
|
|
|
2012-06-24 07:41:07 +02:00
|
|
|
bool b_rvisible(const connection * b, const region * r)
|
2011-03-07 08:02:35 +01:00
|
|
|
{
|
2018-11-03 19:30:30 +01:00
|
|
|
return (b->to == r || b->from == r);
|
2011-03-07 08:02:35 +01:00
|
|
|
}
|
|
|
|
|
2012-06-24 07:41:07 +02:00
|
|
|
bool b_fvisible(const connection * b, const struct faction * f,
|
2015-01-30 20:37:14 +01:00
|
|
|
const region * r)
|
2011-03-07 08:02:35 +01:00
|
|
|
{
|
2017-01-10 16:31:05 +01:00
|
|
|
UNUSED_ARG(r);
|
|
|
|
UNUSED_ARG(f);
|
|
|
|
UNUSED_ARG(b);
|
2015-01-30 20:37:14 +01:00
|
|
|
return true;
|
2011-03-07 08:02:35 +01:00
|
|
|
}
|
|
|
|
|
2012-06-24 07:41:07 +02:00
|
|
|
bool b_uvisible(const connection * b, const unit * u)
|
2011-03-07 08:02:35 +01:00
|
|
|
{
|
2017-01-10 16:31:05 +01:00
|
|
|
UNUSED_ARG(u);
|
|
|
|
UNUSED_ARG(b);
|
2015-01-30 20:37:14 +01:00
|
|
|
return true;
|
2011-03-07 08:02:35 +01:00
|
|
|
}
|
|
|
|
|
2012-06-24 07:41:07 +02:00
|
|
|
bool b_rinvisible(const connection * b, const region * r)
|
2011-03-07 08:02:35 +01:00
|
|
|
{
|
2017-01-10 16:31:05 +01:00
|
|
|
UNUSED_ARG(r);
|
|
|
|
UNUSED_ARG(b);
|
2015-01-30 20:37:14 +01:00
|
|
|
return false;
|
2011-03-07 08:02:35 +01:00
|
|
|
}
|
|
|
|
|
2012-06-24 07:41:07 +02:00
|
|
|
bool b_finvisible(const connection * b, const struct faction * f,
|
2015-01-30 20:37:14 +01:00
|
|
|
const region * r)
|
2011-03-07 08:02:35 +01:00
|
|
|
{
|
2017-01-10 16:31:05 +01:00
|
|
|
UNUSED_ARG(r);
|
|
|
|
UNUSED_ARG(f);
|
|
|
|
UNUSED_ARG(b);
|
2015-01-30 20:37:14 +01:00
|
|
|
return false;
|
2011-03-07 08:02:35 +01:00
|
|
|
}
|
|
|
|
|
2012-06-24 07:41:07 +02:00
|
|
|
bool b_uinvisible(const connection * b, const unit * u)
|
2011-03-07 08:02:35 +01:00
|
|
|
{
|
2017-01-10 16:31:05 +01:00
|
|
|
UNUSED_ARG(u);
|
|
|
|
UNUSED_ARG(b);
|
2015-01-30 20:37:14 +01:00
|
|
|
return false;
|
2011-03-07 08:02:35 +01:00
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
|
|
/**************************************/
|
|
|
|
/* at_countdown - legacy, do not use */
|
|
|
|
/**************************************/
|
|
|
|
|
|
|
|
attrib_type at_countdown = {
|
2015-01-30 20:37:14 +01:00
|
|
|
"countdown",
|
|
|
|
DEFAULT_INIT,
|
|
|
|
DEFAULT_FINALIZE,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
a_readint
|
2010-08-08 10:06:34 +02:00
|
|
|
};
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
void age_borders(void)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2017-01-26 17:41:21 +01:00
|
|
|
selist *deleted = NULL, *ql;
|
2015-01-30 20:37:14 +01:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i != BORDER_MAXHASH; ++i) {
|
|
|
|
connection *bhash = borders[i];
|
|
|
|
for (; bhash; bhash = bhash->nexthash) {
|
|
|
|
connection *b = bhash;
|
|
|
|
for (; b; b = b->next) {
|
|
|
|
if (b->type->age) {
|
|
|
|
if (b->type->age(b) == AT_AGE_REMOVE) {
|
2017-01-26 17:41:21 +01:00
|
|
|
selist_push(&deleted, b);
|
2015-01-30 20:37:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
}
|
2017-01-26 17:41:21 +01:00
|
|
|
for (ql = deleted, i = 0; ql; selist_advance(&ql, &i, 1)) {
|
|
|
|
connection *b = (connection *)selist_get(ql, i);
|
2015-01-30 20:37:14 +01:00
|
|
|
erase_border(b);
|
|
|
|
}
|
2017-01-26 17:41:21 +01:00
|
|
|
selist_free(deleted);
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/********
|
|
|
|
* 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"
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
static const char *b_namewall(const connection * b, const region * r,
|
2015-01-30 20:37:14 +01:00
|
|
|
const struct faction *f, int gflags)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2015-01-30 20:37:14 +01:00
|
|
|
const char *bname = "wall";
|
2010-08-08 10:06:34 +02:00
|
|
|
|
2017-01-10 16:31:05 +01:00
|
|
|
UNUSED_ARG(f);
|
|
|
|
UNUSED_ARG(r);
|
|
|
|
UNUSED_ARG(b);
|
2015-01-30 20:37:14 +01:00
|
|
|
if (gflags & GF_ARTICLE)
|
|
|
|
bname = "a_wall";
|
|
|
|
if (gflags & GF_PURE)
|
|
|
|
return bname;
|
|
|
|
return LOC(f->locale, mkname("border", bname));
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
border_type bt_wall = {
|
2015-01-30 20:37:14 +01:00
|
|
|
"wall", VAR_INT,
|
|
|
|
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 */
|
2010-08-08 10:06:34 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
border_type bt_noway = {
|
2015-01-30 20:37:14 +01:00
|
|
|
"noway", VAR_INT,
|
|
|
|
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 */
|
2010-08-08 10:06:34 +02:00
|
|
|
};
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
static const char *b_namefogwall(const connection * b, const region * r,
|
2015-01-30 20:37:14 +01:00
|
|
|
const struct faction *f, int gflags)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2017-01-10 16:31:05 +01:00
|
|
|
UNUSED_ARG(f);
|
|
|
|
UNUSED_ARG(b);
|
|
|
|
UNUSED_ARG(r);
|
2015-01-30 20:37:14 +01:00
|
|
|
if (gflags & GF_PURE)
|
|
|
|
return "fogwall";
|
|
|
|
if (gflags & GF_ARTICLE)
|
|
|
|
return LOC(f->locale, mkname("border", "a_fogwall"));
|
|
|
|
return LOC(f->locale, mkname("border", "fogwall"));
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
2012-06-24 07:41:07 +02:00
|
|
|
static bool
|
2010-08-08 10:06:34 +02:00
|
|
|
b_blockfogwall(const connection * b, const unit * u, const region * r)
|
|
|
|
{
|
2017-01-10 16:31:05 +01:00
|
|
|
UNUSED_ARG(b);
|
2015-01-30 20:37:14 +01:00
|
|
|
if (!u)
|
|
|
|
return true;
|
2018-11-03 19:30:30 +01:00
|
|
|
return (effskill(u, SK_PERCEPTION, r) > 4); /* Das ist die alte Nebelwand */
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Legacy type used in old Eressea games, no longer in use. */
|
|
|
|
border_type bt_fogwall = {
|
2015-01-30 20:37:14 +01:00
|
|
|
"fogwall", VAR_INT,
|
|
|
|
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 */
|
2010-08-08 10:06:34 +02:00
|
|
|
};
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
static const char *b_nameillusionwall(const connection * b, const region * r,
|
2015-01-30 20:37:14 +01:00
|
|
|
const struct faction *f, int gflags)
|
|
|
|
{
|
|
|
|
int fno = b->data.i;
|
2017-01-10 16:31:05 +01:00
|
|
|
UNUSED_ARG(b);
|
|
|
|
UNUSED_ARG(r);
|
2015-01-30 20:37:14 +01:00
|
|
|
if (gflags & GF_PURE)
|
|
|
|
return (f && fno == f->no) ? "illusionwall" : "wall";
|
|
|
|
if (gflags & GF_ARTICLE) {
|
|
|
|
return LOC(f->locale, mkname("border", (f
|
2018-09-24 20:18:21 +02:00
|
|
|
&& fno == f->uid) ? "an_illusionwall" : "a_wall"));
|
2015-01-30 20:37:14 +01:00
|
|
|
}
|
2011-03-07 08:02:35 +01:00
|
|
|
return LOC(f->locale, mkname("border", (f
|
|
|
|
&& fno == f->no) ? "illusionwall" : "wall"));
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
border_type bt_illusionwall = {
|
2015-01-30 20:37:14 +01:00
|
|
|
"illusionwall", VAR_INT,
|
|
|
|
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 */
|
2010-08-08 10:06:34 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/***
|
|
|
|
* roads. meant to replace the old at_road or r->road attribute
|
|
|
|
***/
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
static const char *b_nameroad(const connection * b, const region * r,
|
2015-01-30 20:37:14 +01:00
|
|
|
const struct faction *f, int gflags)
|
|
|
|
{
|
|
|
|
region *r2 = (r == b->to) ? b->from : b->to;
|
|
|
|
int local = (r == b->from) ? b->data.sa[0] : b->data.sa[1];
|
|
|
|
static char buffer[64];
|
|
|
|
|
2017-01-10 16:31:05 +01:00
|
|
|
UNUSED_ARG(f);
|
2015-01-30 20:37:14 +01:00
|
|
|
if (gflags & GF_PURE)
|
|
|
|
return "road";
|
|
|
|
if (gflags & GF_ARTICLE) {
|
|
|
|
if (!(gflags & GF_DETAILED))
|
|
|
|
return LOC(f->locale, mkname("border", "a_road"));
|
|
|
|
else if (r->terrain->max_road <= local) {
|
|
|
|
int remote = (r2 == b->from) ? b->data.sa[0] : b->data.sa[1];
|
|
|
|
if (r2->terrain->max_road <= remote) {
|
|
|
|
return LOC(f->locale, mkname("border", "a_road"));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return LOC(f->locale, mkname("border", "an_incomplete_road"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (local) {
|
2017-12-11 18:20:21 +01:00
|
|
|
const char *temp = LOC(f->locale, mkname("border", "a_road_percent"));
|
2018-01-01 08:23:52 +01:00
|
|
|
int percent = 100 * local / r->terrain->max_road;
|
|
|
|
if (percent < 1) percent = 1;
|
2017-12-11 18:20:21 +01:00
|
|
|
str_replace(buffer, sizeof(buffer), temp, "$percent", itoa10(percent));
|
2015-01-30 20:37:14 +01:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
return LOC(f->locale, mkname("border", "a_road_connection"));
|
|
|
|
}
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
2015-01-30 20:37:14 +01:00
|
|
|
else if (gflags & GF_PLURAL)
|
|
|
|
return LOC(f->locale, mkname("border", "roads"));
|
|
|
|
else
|
|
|
|
return LOC(f->locale, mkname("border", "road"));
|
|
|
|
return buffer;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
2016-02-13 14:29:44 +01:00
|
|
|
static void b_readroad(connection * b, gamedata * data)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2016-02-13 14:29:44 +01:00
|
|
|
storage * store = data->store;
|
2015-01-30 20:37:14 +01:00
|
|
|
int n;
|
|
|
|
READ_INT(store, &n);
|
|
|
|
b->data.sa[0] = (short)n;
|
|
|
|
READ_INT(store, &n);
|
|
|
|
b->data.sa[1] = (short)n;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
static void b_writeroad(const connection * b, storage * store)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2015-01-30 20:37:14 +01:00
|
|
|
WRITE_INT(store, b->data.sa[0]);
|
|
|
|
WRITE_INT(store, b->data.sa[1]);
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
2012-06-24 07:41:07 +02:00
|
|
|
static bool b_validroad(const connection * b)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2015-01-30 20:37:14 +01:00
|
|
|
return (b->data.sa[0] != SHRT_MAX);
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
2012-06-24 07:41:07 +02:00
|
|
|
static bool b_rvisibleroad(const connection * b, const region * r)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2018-02-25 17:58:45 +01:00
|
|
|
int x = (r == b->from) ? b->data.sa[0] : b->data.sa[1];
|
2015-01-30 20:37:14 +01:00
|
|
|
if (x == 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (b->to != r && b->from != r) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
border_type bt_road = {
|
2015-01-30 20:37:14 +01:00
|
|
|
"road", VAR_INT,
|
|
|
|
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 */
|
2010-08-08 10:06:34 +02:00
|
|
|
};
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
void write_borders(struct storage *store)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2015-01-30 20:37:14 +01:00
|
|
|
int i;
|
|
|
|
for (i = 0; i != BORDER_MAXHASH; ++i) {
|
|
|
|
connection *bhash;
|
|
|
|
for (bhash = borders[i]; bhash; bhash = bhash->nexthash) {
|
|
|
|
connection *b;
|
|
|
|
for (b = bhash; b != NULL; b = b->next) {
|
|
|
|
if (b->type->valid && !b->type->valid(b))
|
|
|
|
continue;
|
2018-06-11 20:42:28 +02:00
|
|
|
WRITE_TOK(store, b->type->_name);
|
2015-01-30 20:37:14 +01:00
|
|
|
WRITE_INT(store, b->id);
|
|
|
|
WRITE_INT(store, b->from->uid);
|
|
|
|
WRITE_INT(store, b->to->uid);
|
|
|
|
|
|
|
|
if (b->type->write)
|
|
|
|
b->type->write(b, store);
|
|
|
|
WRITE_SECTION(store);
|
|
|
|
}
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
2015-01-30 20:37:14 +01:00
|
|
|
WRITE_TOK(store, "end");
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
2016-02-13 13:42:02 +01:00
|
|
|
int read_borders(gamedata *data)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2016-02-13 13:42:02 +01:00
|
|
|
struct storage *store = data->store;
|
2015-01-30 20:37:14 +01:00
|
|
|
for (;;) {
|
2017-09-21 16:35:18 +02:00
|
|
|
int fid, tid, bid;
|
2015-01-30 20:37:14 +01:00
|
|
|
char zText[32];
|
|
|
|
region *from, *to;
|
|
|
|
border_type *type;
|
|
|
|
|
|
|
|
READ_TOK(store, zText, sizeof(zText));
|
2017-09-22 19:13:42 +02:00
|
|
|
if (!strcmp(zText, "end")) {
|
2015-01-30 20:37:14 +01:00
|
|
|
break;
|
2017-09-22 19:13:42 +02:00
|
|
|
}
|
|
|
|
READ_INT(store, &bid);
|
2016-08-14 16:51:25 +02:00
|
|
|
type = find_bordertype(zText);
|
|
|
|
if (type == NULL) {
|
|
|
|
log_error("[read_borders] connection %d type %s is not registered", bid, zText);
|
|
|
|
assert(type || !"connection type not registered");
|
|
|
|
}
|
|
|
|
|
2017-09-21 16:35:18 +02:00
|
|
|
READ_INT(store, &fid);
|
|
|
|
READ_INT(store, &tid);
|
|
|
|
from = findregionbyid(fid);
|
|
|
|
to = findregionbyid(tid);
|
2016-08-14 16:51:25 +02:00
|
|
|
if (!to || !from) {
|
2016-11-19 20:57:10 +01:00
|
|
|
log_error("%s connection %d has missing regions", zText, bid);
|
2016-08-14 16:51:25 +02:00
|
|
|
if (type->read) {
|
2017-02-18 21:15:14 +01:00
|
|
|
/* skip ahead */
|
2016-08-14 16:51:25 +02:00
|
|
|
connection dummy;
|
2016-08-14 19:56:20 +02:00
|
|
|
type->read(&dummy, data);
|
2016-08-14 16:51:25 +02:00
|
|
|
}
|
|
|
|
continue;
|
2015-01-30 20:37:14 +01:00
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
2016-11-19 20:57:10 +01:00
|
|
|
if (to == from && from) {
|
2015-01-30 20:37:14 +01:00
|
|
|
direction_t dir = (direction_t)(rng_int() % MAXDIRECTIONS);
|
|
|
|
region *r = rconnect(from, dir);
|
2018-06-11 20:42:28 +02:00
|
|
|
log_error("[read_borders] invalid %s in %s\n", type->_name, regionname(from, NULL));
|
2015-01-30 20:37:14 +01:00
|
|
|
if (r != NULL)
|
|
|
|
to = r;
|
|
|
|
}
|
2016-08-05 21:58:06 +02:00
|
|
|
if (type->read) {
|
2015-11-05 10:58:08 +01:00
|
|
|
connection *b = new_border(type, from, to);
|
2019-02-07 20:33:20 +01:00
|
|
|
nextborder--; /* new_border erhoeht den Wert */
|
2015-11-05 10:58:08 +01:00
|
|
|
b->id = bid;
|
|
|
|
assert(bid <= nextborder);
|
2016-08-05 21:58:06 +02:00
|
|
|
type->read(b, data);
|
|
|
|
if (!type->write) {
|
|
|
|
log_warning("invalid border '%s' between '%s' and '%s'\n", zText, regionname(from, 0), regionname(to, 0));
|
|
|
|
}
|
2015-01-30 20:37:14 +01:00
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
2015-01-30 20:37:14 +01:00
|
|
|
return 0;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
2016-08-06 14:36:54 +02:00
|
|
|
|
|
|
|
const char * border_name(const connection *co, const struct region * r, const struct faction * f, int flags) {
|
2018-06-11 20:42:28 +02:00
|
|
|
return (co->type->name) ? co->type->name(co, r, f, flags) : co->type->_name;
|
2016-08-06 14:36:54 +02:00
|
|
|
}
|