2010-08-08 10:06:34 +02:00
|
|
|
|
/*
|
2015-01-30 22:10:29 +01:00
|
|
|
|
Copyright (c) 1998-2015, Enno Rehling <enno@eressea.de>
|
2014-08-14 09:57:05 +02:00
|
|
|
|
Katja Zedel <katze@felidae.kn-bremen.de
|
|
|
|
|
Christian Schlittchen <corwin@amber.kn-bremen.de>
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
|
|
|
|
Permission to use, copy, modify, and/or distribute this software for any
|
|
|
|
|
purpose with or without fee is hereby granted, provided that the above
|
|
|
|
|
copyright notice and this permission notice appear in all copies.
|
|
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
|
**/
|
|
|
|
|
|
|
|
|
|
#include <platform.h>
|
|
|
|
|
#include <kernel/config.h>
|
|
|
|
|
#include "reports.h"
|
2014-11-01 12:09:56 +01:00
|
|
|
|
#include "laws.h"
|
2014-12-17 17:22:26 +01:00
|
|
|
|
#include "lighthouse.h"
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
|
|
|
|
/* kernel includes */
|
|
|
|
|
#include <kernel/alliance.h>
|
|
|
|
|
#include <kernel/connection.h>
|
|
|
|
|
#include <kernel/building.h>
|
|
|
|
|
#include <kernel/curse.h>
|
|
|
|
|
#include <kernel/faction.h>
|
|
|
|
|
#include <kernel/group.h>
|
|
|
|
|
#include <kernel/item.h>
|
2014-06-09 18:54:48 +02:00
|
|
|
|
#include <kernel/messages.h>
|
2010-08-08 10:06:34 +02:00
|
|
|
|
#include <kernel/order.h>
|
|
|
|
|
#include <kernel/plane.h>
|
|
|
|
|
#include <kernel/race.h>
|
|
|
|
|
#include <kernel/region.h>
|
|
|
|
|
#include <kernel/resources.h>
|
|
|
|
|
#include <kernel/ship.h>
|
2012-05-26 08:01:21 +02:00
|
|
|
|
#include <kernel/spell.h>
|
|
|
|
|
#include <kernel/spellbook.h>
|
2010-08-08 10:06:34 +02:00
|
|
|
|
#include <kernel/terrain.h>
|
|
|
|
|
#include <kernel/unit.h>
|
|
|
|
|
|
|
|
|
|
/* util includes */
|
|
|
|
|
#include <util/attrib.h>
|
|
|
|
|
#include <util/bsdstring.h>
|
|
|
|
|
#include <util/base36.h>
|
|
|
|
|
#include <util/functions.h>
|
|
|
|
|
#include <util/translation.h>
|
|
|
|
|
#include <util/goodies.h>
|
|
|
|
|
#include <util/language.h>
|
|
|
|
|
#include <util/lists.h>
|
|
|
|
|
#include <util/log.h>
|
2012-05-31 04:55:17 +02:00
|
|
|
|
#include <quicklist.h>
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
|
|
|
|
/* libc includes */
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <time.h>
|
|
|
|
|
|
|
|
|
|
/* attributes includes */
|
|
|
|
|
#include <attributes/follow.h>
|
|
|
|
|
#include <attributes/otherfaction.h>
|
|
|
|
|
#include <attributes/racename.h>
|
2014-11-01 12:09:56 +01:00
|
|
|
|
#include <attributes/stealth.h>
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-27 06:40:18 +02:00
|
|
|
|
#include "move.h"
|
|
|
|
|
|
2012-06-24 07:41:07 +02:00
|
|
|
|
bool nocr = false;
|
|
|
|
|
bool nonr = false;
|
|
|
|
|
bool noreports = false;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
const char *visibility[] = {
|
2014-08-14 09:57:05 +02:00
|
|
|
|
"none",
|
|
|
|
|
"neighbour",
|
|
|
|
|
"lighthouse",
|
|
|
|
|
"travel",
|
|
|
|
|
"far",
|
|
|
|
|
"unit",
|
|
|
|
|
"battle"
|
2010-08-08 10:06:34 +02:00
|
|
|
|
};
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
const char *coasts[MAXDIRECTIONS] = {
|
2014-08-14 09:57:05 +02:00
|
|
|
|
"coast::nw",
|
|
|
|
|
"coast::ne",
|
|
|
|
|
"coast::e",
|
|
|
|
|
"coast::se",
|
|
|
|
|
"coast::sw",
|
|
|
|
|
"coast::w"
|
2010-08-08 10:06:34 +02:00
|
|
|
|
};
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static char *groupid(const struct group *g, const struct faction *f)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
typedef char name[OBJECTIDSIZE + 1];
|
|
|
|
|
static name idbuf[8];
|
|
|
|
|
static int nextbuf = 0;
|
|
|
|
|
char *buf = idbuf[(++nextbuf) % 8];
|
|
|
|
|
sprintf(buf, "%s (%s)", g->name, factionid(f));
|
|
|
|
|
return buf;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
const char *combatstatus[] = {
|
2014-08-14 09:57:05 +02:00
|
|
|
|
"status_aggressive", "status_front",
|
|
|
|
|
"status_rear", "status_defensive",
|
|
|
|
|
"status_avoid", "status_flee"
|
2010-08-08 10:06:34 +02:00
|
|
|
|
};
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
const char *report_kampfstatus(const unit * u, const struct locale *lang)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-24 22:54:40 +02:00
|
|
|
|
static char fsbuf[64]; // FIXME: static return value
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
strlcpy(fsbuf, LOC(lang, combatstatus[u->status]), sizeof(fsbuf));
|
|
|
|
|
if (fval(u, UFL_NOAID)) {
|
|
|
|
|
strcat(fsbuf, ", ");
|
|
|
|
|
strcat(fsbuf, LOC(lang, "status_noaid"));
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
return fsbuf;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
const char *hp_status(const unit * u)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
double p = (double)((double)u->hp / (double)(u->number * unit_max_hp(u)));
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (p > 2.00)
|
|
|
|
|
return mkname("damage", "critical");
|
|
|
|
|
if (p > 1.50)
|
|
|
|
|
return mkname("damage", "heavily");
|
|
|
|
|
if (p < 0.50)
|
|
|
|
|
return mkname("damage", "badly");
|
|
|
|
|
if (p < 0.75)
|
|
|
|
|
return mkname("damage", "wounded");
|
|
|
|
|
if (p < 0.99)
|
|
|
|
|
return mkname("damage", "exhausted");
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
return NULL;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2011-03-07 08:02:35 +01:00
|
|
|
|
report_item(const unit * owner, const item * i, const faction * viewer,
|
2014-08-14 09:57:05 +02:00
|
|
|
|
const char **name, const char **basename, int *number, bool singular)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-06-24 16:42:45 +02:00
|
|
|
|
const resource_type *rsilver = get_resourcetype(R_SILVER);
|
|
|
|
|
|
|
|
|
|
assert(!owner || owner->number);
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (owner && owner->faction == viewer) {
|
|
|
|
|
if (name)
|
|
|
|
|
*name =
|
2015-01-08 20:55:29 +01:00
|
|
|
|
LOC(viewer->locale, resourcename(i->type->rtype,
|
2014-08-14 09:57:05 +02:00
|
|
|
|
((i->number != 1 && !singular) ? GR_PLURAL : 0)));
|
|
|
|
|
if (basename)
|
|
|
|
|
*basename = resourcename(i->type->rtype, 0);
|
|
|
|
|
if (number)
|
|
|
|
|
*number = i->number;
|
|
|
|
|
}
|
|
|
|
|
else if (owner && i->type->rtype == rsilver) {
|
|
|
|
|
int pp = i->number / owner->number;
|
|
|
|
|
if (number)
|
|
|
|
|
*number = 1;
|
|
|
|
|
if (pp > 50000 && dragonrace(u_race(owner))) {
|
|
|
|
|
if (name)
|
2015-01-08 20:55:29 +01:00
|
|
|
|
*name = LOC(viewer->locale, "dragonhoard");
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (basename)
|
|
|
|
|
*basename = "dragonhoard";
|
|
|
|
|
}
|
|
|
|
|
else if (pp > 5000) {
|
|
|
|
|
if (name)
|
2015-01-08 20:55:29 +01:00
|
|
|
|
*name = LOC(viewer->locale, "moneychest");
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (basename)
|
|
|
|
|
*basename = "moneychest";
|
|
|
|
|
}
|
|
|
|
|
else if (pp > 500) {
|
|
|
|
|
if (name)
|
2015-01-08 20:55:29 +01:00
|
|
|
|
*name = LOC(viewer->locale, "moneybag");
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (basename)
|
|
|
|
|
*basename = "moneybag";
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (number)
|
|
|
|
|
*number = 0;
|
|
|
|
|
if (name)
|
|
|
|
|
*name = NULL;
|
|
|
|
|
if (basename)
|
|
|
|
|
*basename = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (name)
|
|
|
|
|
*name =
|
2015-01-08 20:55:29 +01:00
|
|
|
|
LOC(viewer->locale, resourcename(i->type->rtype,
|
2014-08-14 09:57:05 +02:00
|
|
|
|
NMF_APPEARANCE | ((i->number != 1 && !singular) ? GR_PLURAL : 0)));
|
|
|
|
|
if (basename)
|
|
|
|
|
*basename = resourcename(i->type->rtype, NMF_APPEARANCE);
|
|
|
|
|
if (number) {
|
|
|
|
|
if (fval(i->type, ITF_HERB))
|
|
|
|
|
*number = 1;
|
|
|
|
|
else
|
|
|
|
|
*number = i->number;
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define ORDERS_IN_NR 1
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static size_t buforder(char *bufp, size_t size, const order * ord, int mode)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
size_t tsize = 0;
|
|
|
|
|
int bytes;
|
|
|
|
|
|
|
|
|
|
bytes = (int)strlcpy(bufp, ", \"", size);
|
|
|
|
|
tsize += bytes;
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
if (mode < ORDERS_IN_NR) {
|
|
|
|
|
char cmd[ORDERSIZE];
|
|
|
|
|
get_command(ord, cmd, sizeof(cmd));
|
|
|
|
|
bytes = (int)strlcpy(bufp, cmd, size);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
bytes = (int)strlcpy(bufp, "...", size);
|
|
|
|
|
}
|
|
|
|
|
tsize += bytes;
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
|
|
|
|
|
if (size > 1) {
|
|
|
|
|
*bufp++ = '\"';
|
|
|
|
|
--size;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
}
|
|
|
|
|
++tsize;
|
|
|
|
|
|
|
|
|
|
return tsize;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** create a report of a list of items to a non-owner.
|
|
|
|
|
* \param result: an array of size items.
|
|
|
|
|
* \param size: maximum number of items to return
|
|
|
|
|
* \param owner: the owner of the items, or NULL for faction::items etc.
|
|
|
|
|
* \param viewer: the faction looking at the items
|
|
|
|
|
*/
|
|
|
|
|
int
|
2011-03-07 08:02:35 +01:00
|
|
|
|
report_items(const item * items, item * result, int size, const unit * owner,
|
2014-08-14 09:57:05 +02:00
|
|
|
|
const faction * viewer)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
const item *itm;
|
|
|
|
|
int n = 0; /* number of results */
|
|
|
|
|
|
|
|
|
|
assert(owner == NULL || viewer != owner->faction
|
|
|
|
|
|| !"not required for owner=viewer!");
|
|
|
|
|
assert(size);
|
|
|
|
|
|
|
|
|
|
for (itm = items; itm; itm = itm->next) {
|
|
|
|
|
item *ishow;
|
|
|
|
|
const char *ic;
|
|
|
|
|
|
|
|
|
|
report_item(owner, itm, viewer, NULL, &ic, NULL, false);
|
|
|
|
|
if (ic && *ic) {
|
|
|
|
|
for (ishow = result; ishow != result + n; ++ishow) {
|
|
|
|
|
const char *sc;
|
|
|
|
|
|
|
|
|
|
if (ishow->type == itm->type)
|
|
|
|
|
sc = ic;
|
|
|
|
|
else
|
|
|
|
|
report_item(owner, ishow, viewer, NULL, &sc, NULL, false);
|
|
|
|
|
if (sc == ic || strcmp(sc, ic) == 0) {
|
|
|
|
|
ishow->number += itm->number;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (ishow == result + n) {
|
|
|
|
|
if (n == size) {
|
|
|
|
|
log_error("too many items to report, increase buffer size.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
result[n].number = itm->number;
|
|
|
|
|
result[n].type = itm->type;
|
|
|
|
|
result[n].next = (n + 1 == size) ? NULL : result + n + 1;
|
|
|
|
|
++n;
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (n > 0)
|
|
|
|
|
result[n - 1].next = NULL;
|
|
|
|
|
return n;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2011-03-07 08:02:35 +01:00
|
|
|
|
report_resource(resource_report * result, const char *name, int number,
|
2014-08-14 09:57:05 +02:00
|
|
|
|
int level)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
result->name = name;
|
|
|
|
|
result->number = number;
|
|
|
|
|
result->level = level;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
void report_race(const struct unit *u, const char **name, const char **illusion)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (illusion) {
|
|
|
|
|
const race *irace = u_irace(u);
|
|
|
|
|
if (irace && irace != u_race(u)) {
|
2014-08-24 21:49:55 +02:00
|
|
|
|
*illusion = irace->_name;
|
2014-08-14 09:57:05 +02:00
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
*illusion = NULL;
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (name) {
|
2014-08-24 21:49:55 +02:00
|
|
|
|
*name = u_race(u)->_name;
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (fval(u_race(u), RCF_SHAPESHIFTANY)) {
|
|
|
|
|
const char *str = get_racename(u->attribs);
|
|
|
|
|
if (str)
|
|
|
|
|
*name = str;
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2011-03-07 08:02:35 +01:00
|
|
|
|
report_building(const struct building *b, const char **name,
|
2014-08-14 09:57:05 +02:00
|
|
|
|
const char **illusion)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-06-18 08:10:55 +02:00
|
|
|
|
const struct building_type *bt_illusion;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-06-18 08:10:55 +02:00
|
|
|
|
if (name) {
|
|
|
|
|
*name = buildingtype(b->type, b, b->size);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
2014-06-18 08:10:55 +02:00
|
|
|
|
if (illusion) {
|
|
|
|
|
*illusion = NULL;
|
2014-08-14 09:57:05 +02:00
|
|
|
|
|
2014-06-18 08:10:55 +02:00
|
|
|
|
bt_illusion = bt_find("illusioncastle");
|
|
|
|
|
if (bt_illusion && b->type == bt_illusion) {
|
|
|
|
|
const attrib *a = a_findc(b->attribs, &at_icastle);
|
|
|
|
|
if (a != NULL) {
|
2014-08-14 09:57:05 +02:00
|
|
|
|
icastle_data *icastle = (icastle_data *)a->data.v;
|
2014-06-18 08:10:55 +02:00
|
|
|
|
*illusion = buildingtype(icastle->type, b, b->size);
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
2011-03-07 08:02:35 +01:00
|
|
|
|
report_resources(const seen_region * sr, resource_report * result, int size,
|
2014-08-14 09:57:05 +02:00
|
|
|
|
const faction * viewer)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
const region *r = sr->r;
|
|
|
|
|
int n = 0;
|
|
|
|
|
|
|
|
|
|
if (r->land) {
|
|
|
|
|
int peasants = rpeasants(r);
|
|
|
|
|
int money = rmoney(r);
|
|
|
|
|
int horses = rhorses(r);
|
|
|
|
|
int trees = rtrees(r, 2);
|
|
|
|
|
int saplings = rtrees(r, 1);
|
|
|
|
|
bool mallorn = fval(r, RF_MALLORN) != 0;
|
|
|
|
|
|
|
|
|
|
if (money) {
|
|
|
|
|
if (n >= size)
|
|
|
|
|
return -1;
|
|
|
|
|
report_resource(result + n, "rm_money", money, -1);
|
|
|
|
|
++n;
|
|
|
|
|
}
|
|
|
|
|
if (peasants) {
|
|
|
|
|
if (n >= size)
|
|
|
|
|
return -1;
|
|
|
|
|
report_resource(result + n, "rm_peasant", peasants, -1);
|
|
|
|
|
++n;
|
|
|
|
|
}
|
|
|
|
|
if (horses) {
|
|
|
|
|
if (n >= size)
|
|
|
|
|
return -1;
|
|
|
|
|
report_resource(result + n, "rm_horse", horses, -1);
|
|
|
|
|
++n;
|
|
|
|
|
}
|
|
|
|
|
if (saplings) {
|
|
|
|
|
if (n >= size)
|
|
|
|
|
return -1;
|
|
|
|
|
report_resource(result + n, mallorn ? "rm_mallornsapling" : "rm_sapling",
|
|
|
|
|
saplings, -1);
|
|
|
|
|
++n;
|
|
|
|
|
}
|
|
|
|
|
if (trees) {
|
|
|
|
|
if (n >= size)
|
|
|
|
|
return -1;
|
|
|
|
|
report_resource(result + n, mallorn ? "rm_mallorn" : "rm_tree", trees,
|
|
|
|
|
-1);
|
|
|
|
|
++n;
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
2014-08-14 09:57:05 +02:00
|
|
|
|
|
|
|
|
|
if (sr->mode >= see_unit) {
|
|
|
|
|
rawmaterial *res = r->resources;
|
|
|
|
|
while (res) {
|
|
|
|
|
int maxskill = 0;
|
|
|
|
|
const item_type *itype = resource2item(res->type->rtype);
|
|
|
|
|
int level = res->level + itype->construction->minskill - 1;
|
|
|
|
|
int visible = -1;
|
|
|
|
|
if (res->type->visible == NULL) {
|
|
|
|
|
visible = res->amount;
|
|
|
|
|
level = res->level + itype->construction->minskill - 1;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
2014-08-14 09:57:05 +02:00
|
|
|
|
else {
|
|
|
|
|
const unit *u;
|
|
|
|
|
for (u = r->units; visible != res->amount && u != NULL; u = u->next) {
|
|
|
|
|
if (u->faction == viewer) {
|
|
|
|
|
int s = eff_skill(u, itype->construction->skill, r);
|
|
|
|
|
if (s > maxskill) {
|
|
|
|
|
maxskill = s;
|
|
|
|
|
visible = res->type->visible(res, maxskill);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (level >= 0 && visible >= 0) {
|
|
|
|
|
if (n >= size)
|
|
|
|
|
return -1;
|
|
|
|
|
report_resource(result + n, res->type->name, visible, level);
|
|
|
|
|
n++;
|
|
|
|
|
}
|
|
|
|
|
res = res->next;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-08-14 09:57:05 +02:00
|
|
|
|
return n;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
2011-03-07 08:02:35 +01:00
|
|
|
|
bufunit(const faction * f, const unit * u, int indent, int mode, char *buf,
|
2014-08-14 09:57:05 +02:00
|
|
|
|
size_t size)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
int i, dh;
|
|
|
|
|
int getarnt = fval(u, UFL_ANON_FACTION);
|
|
|
|
|
const char *pzTmp, *str;
|
|
|
|
|
building *b;
|
|
|
|
|
bool isbattle = (bool)(mode == see_battle);
|
|
|
|
|
int telepath_see = 0;
|
|
|
|
|
attrib *a_fshidden = NULL;
|
|
|
|
|
item *itm;
|
|
|
|
|
item *show;
|
|
|
|
|
faction *fv = visible_faction(f, u);
|
|
|
|
|
char *bufp = buf;
|
|
|
|
|
bool itemcloak = false;
|
|
|
|
|
const curse_type *itemcloak_ct = 0;
|
|
|
|
|
int bytes;
|
|
|
|
|
item result[MAX_INVENTORY];
|
|
|
|
|
|
|
|
|
|
itemcloak_ct = ct_find("itemcloak");
|
|
|
|
|
if (itemcloak_ct) {
|
|
|
|
|
itemcloak = curse_active(get_curse(u->attribs, itemcloak_ct));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bytes = (int)strlcpy(bufp, unitname(u), size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
|
|
|
|
|
if (!isbattle) {
|
|
|
|
|
attrib *a_otherfaction = a_find(u->attribs, &at_otherfaction);
|
|
|
|
|
if (u->faction == f) {
|
|
|
|
|
if (fval(u, UFL_GROUP)) {
|
|
|
|
|
attrib *a = a_find(u->attribs, &at_group);
|
|
|
|
|
if (a) {
|
|
|
|
|
group *g = (group *)a->data.v;
|
|
|
|
|
bytes = (int)strlcpy(bufp, ", ", size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
bytes = (int)strlcpy(bufp, groupid(g, f), size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (getarnt) {
|
|
|
|
|
bytes = (int)strlcpy(bufp, ", ", size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
bytes = (int)strlcpy(bufp, LOC(f->locale, "anonymous"), size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
}
|
|
|
|
|
else if (a_otherfaction) {
|
|
|
|
|
faction *otherfaction = get_otherfaction(a_otherfaction);
|
|
|
|
|
if (otherfaction) {
|
|
|
|
|
bytes = (int)strlcpy(bufp, ", ", size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
bytes = (int)strlcpy(bufp, factionname(otherfaction), size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
2014-08-14 09:57:05 +02:00
|
|
|
|
else {
|
|
|
|
|
if (getarnt) {
|
|
|
|
|
bytes = (int)strlcpy(bufp, ", ", size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
bytes = (int)strlcpy(bufp, LOC(f->locale, "anonymous"), size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (a_otherfaction && alliedunit(u, f, HELP_FSTEALTH)) {
|
|
|
|
|
faction *f = get_otherfaction(a_otherfaction);
|
|
|
|
|
bytes =
|
|
|
|
|
_snprintf(bufp, size, ", %s (%s)", factionname(f),
|
|
|
|
|
factionname(u->faction));
|
|
|
|
|
if (bytes < 0 || wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
bytes = (int)strlcpy(bufp, ", ", size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
bytes = (int)strlcpy(bufp, factionname(fv), size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bytes = (int)strlcpy(bufp, ", ", size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
|
|
|
|
|
if (u->faction != f && a_fshidden && a_fshidden->data.ca[0] == 1
|
|
|
|
|
&& effskill(u, SK_STEALTH) >= 6) {
|
|
|
|
|
bytes = (int)strlcpy(bufp, "? ", size);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
bytes = _snprintf(bufp, size, "%d ", u->number);
|
|
|
|
|
}
|
|
|
|
|
if (bytes < 0 || wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
|
|
|
|
|
pzTmp = get_racename(u->attribs);
|
|
|
|
|
if (pzTmp) {
|
|
|
|
|
bytes = (int)strlcpy(bufp, pzTmp, size);
|
2011-03-07 08:02:35 +01:00
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (u->faction == f && fval(u_race(u), RCF_SHAPESHIFTANY)) {
|
|
|
|
|
bytes = (int)strlcpy(bufp, " (", size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
bytes = (int)strlcpy(bufp, racename(f->locale, u, u_race(u)), size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
if (size > 1) {
|
|
|
|
|
strcpy(bufp++, ")");
|
|
|
|
|
--size;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
const race *irace = u_irace(u);
|
|
|
|
|
bytes = (int)strlcpy(bufp, racename(f->locale, u, irace), size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
2011-03-07 08:02:35 +01:00
|
|
|
|
WARN_STATIC_BUFFER();
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (u->faction == f && irace != u_race(u)) {
|
|
|
|
|
bytes = (int)strlcpy(bufp, " (", size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
bytes = (int)strlcpy(bufp, racename(f->locale, u, u_race(u)), size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
if (size > 1) {
|
|
|
|
|
strcpy(bufp++, ")");
|
|
|
|
|
--size;
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
2014-08-14 09:57:05 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fval(u, UFL_HERO) && (u->faction == f || omniscient(f))) {
|
2010-08-08 10:06:34 +02:00
|
|
|
|
bytes = (int)strlcpy(bufp, ", ", size);
|
2011-03-07 08:02:35 +01:00
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
2014-08-14 09:57:05 +02:00
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
bytes = (int)strlcpy(bufp, LOC(f->locale, "hero"), size);
|
2011-03-07 08:02:35 +01:00
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
2014-08-14 09:57:05 +02:00
|
|
|
|
}
|
|
|
|
|
/* status */
|
|
|
|
|
|
|
|
|
|
if (u->number && (u->faction == f || telepath_see || isbattle)) {
|
|
|
|
|
const char *c = hp_status(u);
|
2015-01-08 20:55:29 +01:00
|
|
|
|
c = c ? LOC(f->locale, c) : 0;
|
2014-08-14 09:57:05 +02:00
|
|
|
|
bytes = (int)strlcpy(bufp, ", ", size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
2011-03-07 08:02:35 +01:00
|
|
|
|
WARN_STATIC_BUFFER();
|
2014-08-14 09:57:05 +02:00
|
|
|
|
bytes = (int)strlcpy(bufp, report_kampfstatus(u, f->locale), size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
2011-03-07 08:02:35 +01:00
|
|
|
|
WARN_STATIC_BUFFER();
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (c || fval(u, UFL_HUNGER)) {
|
|
|
|
|
bytes = (int)strlcpy(bufp, " (", size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
if (c) {
|
|
|
|
|
bytes = (int)strlcpy(bufp, c, size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
}
|
|
|
|
|
if (fval(u, UFL_HUNGER)) {
|
|
|
|
|
if (c) {
|
|
|
|
|
bytes = (int)strlcpy(bufp, ", ", size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
}
|
|
|
|
|
bytes = (int)strlcpy(bufp, LOC(f->locale, "unit_hungers"), size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
}
|
|
|
|
|
if (size > 1) {
|
|
|
|
|
strcpy(bufp++, ")");
|
|
|
|
|
--size;
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (is_guard(u, GUARD_ALL) != 0) {
|
|
|
|
|
bytes = (int)strlcpy(bufp, ", ", size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
bytes = (int)strlcpy(bufp, LOC(f->locale, "unit_guards"), size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if ((b = usiege(u)) != NULL) {
|
|
|
|
|
bytes = (int)strlcpy(bufp, ", belagert ", size);
|
2011-03-07 08:02:35 +01:00
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
2012-07-08 20:37:19 +02:00
|
|
|
|
WARN_STATIC_BUFFER();
|
2014-08-14 09:57:05 +02:00
|
|
|
|
bytes = (int)strlcpy(bufp, buildingname(b), size);
|
2011-03-07 08:02:35 +01:00
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
2014-08-14 09:57:05 +02:00
|
|
|
|
WARN_STATIC_BUFFER();
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
dh = 0;
|
|
|
|
|
if (u->faction == f || telepath_see) {
|
|
|
|
|
skill *sv;
|
|
|
|
|
for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) {
|
|
|
|
|
bytes = (int)spskill(bufp, size, f->locale, u, sv, &dh, 1);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
dh = 0;
|
|
|
|
|
if (f == u->faction || telepath_see || omniscient(f)) {
|
|
|
|
|
show = u->items;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
2014-08-14 09:57:05 +02:00
|
|
|
|
else if (!itemcloak && mode >= see_unit && !(a_fshidden
|
|
|
|
|
&& a_fshidden->data.ca[1] == 1 && effskill(u, SK_STEALTH) >= 3)) {
|
|
|
|
|
int n = report_items(u->items, result, MAX_INVENTORY, u, f);
|
|
|
|
|
assert(n >= 0);
|
|
|
|
|
if (n > 0)
|
|
|
|
|
show = result;
|
|
|
|
|
else
|
|
|
|
|
show = NULL;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
2014-08-14 09:57:05 +02:00
|
|
|
|
else {
|
|
|
|
|
show = NULL;
|
|
|
|
|
}
|
|
|
|
|
for (itm = show; itm; itm = itm->next) {
|
|
|
|
|
const char *ic;
|
|
|
|
|
int in, bytes;
|
|
|
|
|
report_item(u, itm, f, &ic, NULL, &in, false);
|
|
|
|
|
if (in == 0 || ic == NULL)
|
|
|
|
|
continue;
|
|
|
|
|
bytes = (int)strlcpy(bufp, ", ", size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
2012-05-26 08:01:21 +02:00
|
|
|
|
WARN_STATIC_BUFFER();
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (!dh) {
|
|
|
|
|
bytes = _snprintf(bufp, size, "%s: ", LOC(f->locale, "nr_inventory"));
|
|
|
|
|
if (bytes < 0 || wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
dh = 1;
|
|
|
|
|
}
|
|
|
|
|
if (in == 1) {
|
|
|
|
|
bytes = (int)strlcpy(bufp, ic, size);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
bytes = _snprintf(bufp, size, "%d %s", in, ic);
|
|
|
|
|
}
|
2011-03-07 08:02:35 +01:00
|
|
|
|
if (bytes < 0 || wrptr(&bufp, &size, bytes) != 0)
|
2014-08-14 09:57:05 +02:00
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (u->faction == f || telepath_see) {
|
|
|
|
|
spellbook *book = unit_get_spellbook(u);
|
|
|
|
|
|
|
|
|
|
if (book) {
|
|
|
|
|
quicklist *ql = book->spells;
|
|
|
|
|
int qi, header, maxlevel = effskill(u, SK_MAGIC);
|
|
|
|
|
int bytes = _snprintf(bufp, size, ". Aura %d/%d", get_spellpoints(u), max_spellpoints(u->region, u));
|
|
|
|
|
if (bytes < 0 || wrptr(&bufp, &size, bytes) != 0) {
|
|
|
|
|
WARN_STATIC_BUFFER();
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
2014-08-14 09:57:05 +02:00
|
|
|
|
|
|
|
|
|
for (header = 0, qi = 0; ql; ql_advance(&ql, &qi, 1)) {
|
|
|
|
|
spellbook_entry * sbe = (spellbook_entry *)ql_get(ql, qi);
|
|
|
|
|
if (sbe->level <= maxlevel) {
|
|
|
|
|
if (!header) {
|
|
|
|
|
bytes = _snprintf(bufp, size, ", %s: ", LOC(f->locale, "nr_spells"));
|
|
|
|
|
header = 1;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
bytes = (int)strlcpy(bufp, ", ", size);
|
|
|
|
|
}
|
|
|
|
|
if (bytes < 0 || wrptr(&bufp, &size, bytes) != 0) {
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
}
|
|
|
|
|
bytes = (int)strlcpy(bufp, spell_name(sbe->sp, f->locale), size);
|
|
|
|
|
if (bytes < 0 || wrptr(&bufp, &size, bytes) != 0) {
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
for (i = 0; i != MAXCOMBATSPELLS; ++i) {
|
|
|
|
|
if (get_combatspell(u, i))
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (i != MAXCOMBATSPELLS) {
|
|
|
|
|
bytes =
|
|
|
|
|
_snprintf(bufp, size, ", %s: ", LOC(f->locale, "nr_combatspells"));
|
|
|
|
|
if (bytes < 0 || wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
|
|
|
|
|
dh = 0;
|
|
|
|
|
for (i = 0; i < MAXCOMBATSPELLS; i++) {
|
|
|
|
|
const spell *sp;
|
|
|
|
|
if (!dh) {
|
|
|
|
|
dh = 1;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
bytes = (int)strlcpy(bufp, ", ", size);
|
|
|
|
|
if (bytes && wrptr(&bufp, &size, bytes) != 0) {
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
sp = get_combatspell(u, i);
|
|
|
|
|
if (sp) {
|
|
|
|
|
int sl = get_combatspelllevel(u, i);
|
|
|
|
|
bytes =
|
|
|
|
|
(int)strlcpy(bufp, spell_name(sp, u->faction->locale), size);
|
|
|
|
|
if (bytes && wrptr(&bufp, &size, bytes) != 0) {
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sl > 0) {
|
|
|
|
|
bytes = _snprintf(bufp, size, " (%d)", sl);
|
|
|
|
|
if (bytes < 0 || wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_nospells"), size);
|
|
|
|
|
if (bytes && wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (!isbattle) {
|
|
|
|
|
bool printed = 0;
|
|
|
|
|
order *ord;;
|
|
|
|
|
for (ord = u->old_orders; ord; ord = ord->next) {
|
|
|
|
|
if (is_repeated(ord)) {
|
|
|
|
|
if (printed < ORDERS_IN_NR) {
|
|
|
|
|
bytes = (int)buforder(bufp, size, ord, printed++);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (printed < ORDERS_IN_NR)
|
|
|
|
|
for (ord = u->orders; ord; ord = ord->next) {
|
2015-01-30 20:37:14 +01:00
|
|
|
|
if (is_repeated(ord)) {
|
|
|
|
|
if (printed < ORDERS_IN_NR) {
|
|
|
|
|
bytes = (int)buforder(bufp, size, ord, printed++);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
break;
|
2014-08-14 09:57:05 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-08-14 09:57:05 +02:00
|
|
|
|
i = 0;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
str = u_description(u, f->locale);
|
|
|
|
|
if (str) {
|
|
|
|
|
bytes = (int)strlcpy(bufp, "; ", size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
bytes = (int)strlcpy(bufp, str, size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
i = str[strlen(str) - 1];
|
|
|
|
|
}
|
|
|
|
|
if (i != '!' && i != '?' && i != '.') {
|
|
|
|
|
if (size > 1) {
|
|
|
|
|
strcpy(bufp++, ".");
|
|
|
|
|
--size;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pzTmp = uprivate(u);
|
|
|
|
|
if (u->faction == f && pzTmp) {
|
|
|
|
|
bytes = (int)strlcpy(bufp, " (Bem: ", size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
bytes = (int)strlcpy(bufp, pzTmp, size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
bytes = (int)strlcpy(bufp, ")", size);
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
dh = 0;
|
|
|
|
|
if (!getarnt && f) {
|
|
|
|
|
if (alliedfaction(rplane(u->region), f, fv, HELP_ALL)) {
|
|
|
|
|
dh = 1;
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (size <= 1) {
|
|
|
|
|
log_warning("bufunit ran out of space after writing %u bytes.\n", (bufp - buf));
|
|
|
|
|
}
|
|
|
|
|
return dh;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* TODO: telepath_see wird nicht ber<65>cksichtigt: Parteien mit
|
|
|
|
|
* telepath_see sollten immer einzelne Einheiten zu sehen
|
|
|
|
|
* bekommen, alles andere ist darstellungsteschnisch kompliziert.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
size_t
|
2011-03-07 08:02:35 +01:00
|
|
|
|
spskill(char *buffer, size_t size, const struct locale * lang,
|
2014-08-14 09:57:05 +02:00
|
|
|
|
const struct unit * u, struct skill * sv, int *dh, int days)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
char *bufp = buffer;
|
|
|
|
|
int i, effsk;
|
|
|
|
|
int bytes;
|
|
|
|
|
size_t tsize = 0;
|
|
|
|
|
|
|
|
|
|
if (!u->number)
|
|
|
|
|
return 0;
|
|
|
|
|
if (sv->level <= 0) {
|
|
|
|
|
if (sv->old <= 0 || (u->faction->options & want(O_SHOWSKCHANGE)) == 0) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
bytes = (int)strlcpy(bufp, ", ", size);
|
|
|
|
|
tsize += bytes;
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
|
|
|
|
|
if (!*dh) {
|
|
|
|
|
bytes = (int)strlcpy(bufp, LOC(lang, "nr_skills"), size);
|
|
|
|
|
tsize += bytes;
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
|
|
|
|
|
bytes = (int)strlcpy(bufp, ": ", size);
|
|
|
|
|
tsize += bytes;
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
*dh = 1;
|
|
|
|
|
}
|
|
|
|
|
bytes = (int)strlcpy(bufp, skillname(sv->id, lang), size);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
tsize += bytes;
|
2011-03-07 08:02:35 +01:00
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
2014-08-14 09:57:05 +02:00
|
|
|
|
WARN_STATIC_BUFFER();
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
bytes = (int)strlcpy(bufp, " ", size);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
tsize += bytes;
|
2011-03-07 08:02:35 +01:00
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (sv->id == SK_MAGIC) {
|
|
|
|
|
sc_mage *mage = get_mage(u);
|
|
|
|
|
if (mage && mage->magietyp != M_GRAY) {
|
|
|
|
|
bytes =
|
|
|
|
|
(int)strlcpy(bufp, LOC(lang, mkname("school",
|
|
|
|
|
magic_school[mage->magietyp])), size);
|
|
|
|
|
tsize += bytes;
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
|
|
|
|
|
bytes = (int)strlcpy(bufp, " ", size);
|
|
|
|
|
tsize += bytes;
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
2011-03-07 08:02:35 +01:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (sv->id == SK_STEALTH && fval(u, UFL_STEALTH)) {
|
|
|
|
|
i = u_geteffstealth(u);
|
|
|
|
|
if (i >= 0) {
|
|
|
|
|
bytes = slprintf(bufp, size, "%d/", i);
|
|
|
|
|
tsize += bytes;
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
2011-03-07 08:02:35 +01:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
effsk = effskill(u, sv->id);
|
|
|
|
|
bytes = slprintf(bufp, size, "%d", effsk);
|
|
|
|
|
tsize += bytes;
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
2011-03-07 08:02:35 +01:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (u->faction->options & want(O_SHOWSKCHANGE)) {
|
|
|
|
|
int oldeff = 0;
|
|
|
|
|
int diff;
|
2011-03-07 08:02:35 +01:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (sv->old > 0) {
|
|
|
|
|
oldeff = sv->old + get_modifier(u, sv->id, sv->old, u->region, false);
|
|
|
|
|
}
|
2011-03-07 08:02:35 +01:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
oldeff = _max(0, oldeff);
|
|
|
|
|
diff = effsk - oldeff;
|
2011-03-07 08:02:35 +01:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (diff != 0) {
|
|
|
|
|
bytes = slprintf(bufp, size, " (%s%d)", (diff > 0) ? "+" : "", diff);
|
|
|
|
|
tsize += bytes;
|
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
2014-08-14 09:57:05 +02:00
|
|
|
|
return tsize;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
void lparagraph(struct strlist **SP, char *s, int indent, char mark)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
/* Die Liste SP wird mit dem String s aufgefuellt, mit indent und einer
|
|
|
|
|
* mark, falls angegeben. SP wurde also auf 0 gesetzt vor dem Aufruf.
|
|
|
|
|
* Vgl. spunit (). */
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
char *buflocal = calloc(strlen(s) + indent + 1, sizeof(char));
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (indent) {
|
|
|
|
|
memset(buflocal, ' ', indent);
|
|
|
|
|
if (mark)
|
|
|
|
|
buflocal[indent - 2] = mark;
|
|
|
|
|
}
|
|
|
|
|
strcpy(buflocal + indent, s);
|
|
|
|
|
addstrlist(SP, buflocal);
|
|
|
|
|
free(buflocal);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2011-03-07 08:02:35 +01:00
|
|
|
|
spunit(struct strlist **SP, const struct faction *f, const unit * u, int indent,
|
2014-08-14 09:57:05 +02:00
|
|
|
|
int mode)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
char buf[DISPLAYSIZE];
|
|
|
|
|
int dh = bufunit(f, u, indent, mode, buf, sizeof(buf));
|
|
|
|
|
lparagraph(SP, buf, indent,
|
|
|
|
|
(char)((u->faction == f) ? '*' : (dh ? '+' : '-')));
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2012-05-17 09:13:30 +02:00
|
|
|
|
struct message *msg_curse(const struct curse *c, const void *obj, objtype_t typ,
|
2014-08-14 09:57:05 +02:00
|
|
|
|
int self)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (c->type->curseinfo) {
|
|
|
|
|
/* if curseinfo returns NULL, then we don't want to tell the viewer anything. */
|
|
|
|
|
return c->type->curseinfo(obj, typ, c, self);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
message *msg = cinfo_simple(obj, typ, c, self);
|
|
|
|
|
if (msg == NULL) {
|
|
|
|
|
const char *unknown[] =
|
|
|
|
|
{ "unit_unknown", "region_unknown", "building_unknown",
|
|
|
|
|
"ship_unknown" };
|
|
|
|
|
msg = msg_message(mkname("curseinfo", unknown[typ]), "id", c->no);
|
|
|
|
|
log_error("no curseinfo function for %s and no fallback either.\n", c->type->cname);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
log_error("no curseinfo function for %s, using cinfo_simple fallback.\n", c->type->cname);
|
|
|
|
|
}
|
|
|
|
|
return msg;
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
const struct unit *ucansee(const struct faction *f, const struct unit *u,
|
2014-08-14 09:57:05 +02:00
|
|
|
|
const struct unit *x)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (cansee(f, u->region, u, 0))
|
|
|
|
|
return u;
|
|
|
|
|
return x;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
int stealth_modifier(int seen_mode)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
switch (seen_mode) {
|
2011-03-07 08:02:35 +01:00
|
|
|
|
case see_unit:
|
2014-08-14 09:57:05 +02:00
|
|
|
|
return 0;
|
2011-03-07 08:02:35 +01:00
|
|
|
|
case see_far:
|
|
|
|
|
case see_lighthouse:
|
2014-08-14 09:57:05 +02:00
|
|
|
|
return -2;
|
2011-03-07 08:02:35 +01:00
|
|
|
|
case see_travel:
|
2014-08-14 09:57:05 +02:00
|
|
|
|
return -1;
|
2011-03-07 08:02:35 +01:00
|
|
|
|
default:
|
2014-08-14 09:57:05 +02:00
|
|
|
|
return INT_MIN;
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-02-25 16:27:44 +01:00
|
|
|
|
void transfer_seen(quicklist ** dst, quicklist ** src)
|
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
assert(!*dst);
|
|
|
|
|
*dst = *src;
|
|
|
|
|
*src = NULL;
|
2011-02-25 07:29:21 +01:00
|
|
|
|
}
|
|
|
|
|
|
2014-08-24 23:36:06 +02:00
|
|
|
|
int cmp_faction(const void *lhs, const void *rhs) {
|
|
|
|
|
const faction *lhf = (const faction *)lhs;
|
|
|
|
|
const faction *rhf = (const faction *)rhs;
|
|
|
|
|
if (lhf->no == rhf->no) return 0;
|
|
|
|
|
if (lhf->no > rhf->no) return 1;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void add_seen_faction_i(struct quicklist **flist, faction *f) {
|
|
|
|
|
ql_set_insert_ex(flist, f, cmp_faction);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void add_seen_faction(faction *self, faction *seen) {
|
|
|
|
|
add_seen_faction_i(&self->seen_factions, seen);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void get_addresses(report_context * ctx)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
/* "TODO: travelthru" */
|
|
|
|
|
seen_region *sr = NULL;
|
|
|
|
|
region *r;
|
|
|
|
|
const faction *lastf = NULL;
|
|
|
|
|
quicklist *flist = 0;
|
|
|
|
|
|
|
|
|
|
transfer_seen(&flist, &ctx->f->seen_factions);
|
|
|
|
|
|
|
|
|
|
ctx->f->seen_factions = NULL; /* do not delete it twice */
|
|
|
|
|
ql_push(&flist, ctx->f);
|
|
|
|
|
|
|
|
|
|
if (f_get_alliance(ctx->f)) {
|
|
|
|
|
quicklist *ql = ctx->f->alliance->members;
|
|
|
|
|
int qi;
|
|
|
|
|
for (qi = 0; ql; ql_advance(&ql, &qi, 1)) {
|
2014-08-24 23:36:06 +02:00
|
|
|
|
add_seen_faction_i(&flist, (faction *)ql_get(ql, qi));
|
2014-08-14 09:57:05 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2011-03-07 08:02:35 +01:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
/* find the first region that this faction can see */
|
|
|
|
|
for (r = ctx->first; sr == NULL && r != ctx->last; r = r->next) {
|
|
|
|
|
sr = find_seen(ctx->seen, r);
|
|
|
|
|
}
|
2010-10-13 08:17:35 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
for (; sr != NULL; sr = sr->next) {
|
|
|
|
|
int stealthmod = stealth_modifier(sr->mode);
|
|
|
|
|
r = sr->r;
|
|
|
|
|
if (sr->mode == see_lighthouse) {
|
|
|
|
|
unit *u = r->units;
|
|
|
|
|
for (; u; u = u->next) {
|
|
|
|
|
faction *sf = visible_faction(ctx->f, u);
|
|
|
|
|
if (lastf != sf) {
|
|
|
|
|
if (u->building || u->ship || (stealthmod > INT_MIN
|
|
|
|
|
&& cansee(ctx->f, r, u, stealthmod))) {
|
2014-08-24 23:36:06 +02:00
|
|
|
|
add_seen_faction_i(&flist, sf);
|
2014-08-14 09:57:05 +02:00
|
|
|
|
lastf = sf;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (sr->mode == see_travel) {
|
|
|
|
|
unit *u = r->units;
|
|
|
|
|
while (u) {
|
|
|
|
|
faction *sf = visible_faction(ctx->f, u);
|
|
|
|
|
assert(u->faction != ctx->f); /* if this is see_travel only, then I shouldn't be here. */
|
|
|
|
|
if (lastf != sf) {
|
|
|
|
|
attrib *a = a_find(r->attribs, &at_travelunit);
|
|
|
|
|
while (a && a->type == &at_travelunit) {
|
|
|
|
|
unit *u2 = (unit *)a->data.v;
|
|
|
|
|
if (u2->faction == ctx->f) {
|
|
|
|
|
if (cansee_unit(u2, u, stealthmod)) {
|
2014-08-24 23:36:06 +02:00
|
|
|
|
add_seen_faction_i(&flist, sf);
|
2014-08-14 09:57:05 +02:00
|
|
|
|
lastf = sf;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
a = a->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
u = u->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (sr->mode > see_travel) {
|
|
|
|
|
const unit *u = r->units;
|
|
|
|
|
while (u != NULL) {
|
|
|
|
|
if (u->faction != ctx->f) {
|
|
|
|
|
faction *sf = visible_faction(ctx->f, u);
|
|
|
|
|
bool ballied = sf && sf != ctx->f && sf != lastf
|
|
|
|
|
&& !fval(u, UFL_ANON_FACTION) && cansee(ctx->f, r, u, stealthmod);
|
2014-12-09 14:14:35 +01:00
|
|
|
|
if (ballied || is_allied(ctx->f, sf)) {
|
2014-08-24 23:36:06 +02:00
|
|
|
|
add_seen_faction_i(&flist, sf);
|
2014-08-14 09:57:05 +02:00
|
|
|
|
lastf = sf;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
u = u->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (f_get_alliance(ctx->f)) {
|
|
|
|
|
faction *f2;
|
|
|
|
|
for (f2 = factions; f2; f2 = f2->next) {
|
|
|
|
|
if (f2->alliance == ctx->f->alliance) {
|
2014-08-24 23:36:06 +02:00
|
|
|
|
add_seen_faction_i(&flist, f2);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
2014-08-14 09:57:05 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ctx->addresses = flist;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define MAXSEEHASH 0x1000
|
2011-03-07 08:02:35 +01:00
|
|
|
|
seen_region *reuse;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
seen_region **seen_init(void)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
return (seen_region **)calloc(MAXSEEHASH, sizeof(seen_region *));
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
void seen_done(seen_region * seehash[])
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
int i;
|
|
|
|
|
for (i = 0; i != MAXSEEHASH; ++i) {
|
|
|
|
|
seen_region *sd = seehash[i];
|
|
|
|
|
if (sd == NULL)
|
|
|
|
|
continue;
|
|
|
|
|
while (sd->nextHash != NULL)
|
|
|
|
|
sd = sd->nextHash;
|
|
|
|
|
sd->nextHash = reuse;
|
|
|
|
|
reuse = seehash[i];
|
|
|
|
|
seehash[i] = NULL;
|
|
|
|
|
}
|
|
|
|
|
/* free(seehash); */
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
void free_seen(void)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
while (reuse) {
|
|
|
|
|
seen_region *r = reuse;
|
|
|
|
|
reuse = reuse->nextHash;
|
|
|
|
|
free(r);
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
link_seen(seen_region * seehash[], const region * first, const region * last)
|
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
const region *r = first;
|
|
|
|
|
seen_region *sr = NULL;
|
|
|
|
|
|
|
|
|
|
if (first == last)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
sr = find_seen(seehash, r);
|
|
|
|
|
r = r->next;
|
|
|
|
|
} while (sr == NULL && r != last);
|
|
|
|
|
|
|
|
|
|
while (r != last) {
|
|
|
|
|
seen_region *sn = find_seen(seehash, r);
|
|
|
|
|
if (sn != NULL) {
|
|
|
|
|
sr->next = sn;
|
|
|
|
|
sr = sn;
|
|
|
|
|
}
|
|
|
|
|
r = r->next;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
2014-10-31 15:52:40 +01:00
|
|
|
|
if (sr) sr->next = 0;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
seen_region *find_seen(struct seen_region *seehash[], const region * r)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
unsigned int index = reg_hashkey(r) & (MAXSEEHASH - 1);
|
|
|
|
|
seen_region *find = seehash[index];
|
|
|
|
|
while (find) {
|
|
|
|
|
if (find->r == r)
|
|
|
|
|
return find;
|
|
|
|
|
find = find->nextHash;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void get_seen_interval(report_context * ctx)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
/* this is required to find the neighbour regions of the ones we are in,
|
|
|
|
|
* which may well be outside of [firstregion, lastregion) */
|
|
|
|
|
int i;
|
2014-11-23 15:50:22 +01:00
|
|
|
|
|
|
|
|
|
assert(ctx->seen);
|
2014-08-14 09:57:05 +02:00
|
|
|
|
for (i = 0; i != MAXSEEHASH; ++i) {
|
|
|
|
|
seen_region *sr = ctx->seen[i];
|
|
|
|
|
while (sr != NULL) {
|
|
|
|
|
if (ctx->first == NULL || sr->r->index < ctx->first->index) {
|
|
|
|
|
ctx->first = sr->r;
|
|
|
|
|
}
|
|
|
|
|
if (ctx->last != NULL && sr->r->index >= ctx->last->index) {
|
|
|
|
|
ctx->last = sr->r->next;
|
|
|
|
|
}
|
|
|
|
|
sr = sr->nextHash;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
link_seen(ctx->seen, ctx->first, ctx->last);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2012-06-24 07:41:07 +02:00
|
|
|
|
bool
|
2011-03-07 08:02:35 +01:00
|
|
|
|
add_seen(struct seen_region *seehash[], struct region *r, unsigned char mode,
|
2014-08-14 09:57:05 +02:00
|
|
|
|
bool dis)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
seen_region *find = find_seen(seehash, r);
|
|
|
|
|
if (find == NULL) {
|
|
|
|
|
unsigned int index = reg_hashkey(r) & (MAXSEEHASH - 1);
|
|
|
|
|
if (!reuse)
|
|
|
|
|
reuse = (seen_region *)calloc(1, sizeof(struct seen_region));
|
|
|
|
|
find = reuse;
|
|
|
|
|
reuse = reuse->nextHash;
|
|
|
|
|
find->nextHash = seehash[index];
|
|
|
|
|
seehash[index] = find;
|
|
|
|
|
find->r = r;
|
|
|
|
|
}
|
|
|
|
|
else if (find->mode >= mode) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
find->mode = mode;
|
|
|
|
|
find->disbelieves |= dis;
|
|
|
|
|
return true;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef struct report_type {
|
2014-08-14 09:57:05 +02:00
|
|
|
|
struct report_type *next;
|
|
|
|
|
report_fun write;
|
|
|
|
|
const char *extension;
|
|
|
|
|
int flag;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
} report_type;
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static report_type *report_types;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
void register_reporttype(const char *extension, report_fun write, int flag)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
report_type *type = (report_type *)malloc(sizeof(report_type));
|
|
|
|
|
type->extension = extension;
|
|
|
|
|
type->write = write;
|
|
|
|
|
type->flag = flag;
|
|
|
|
|
type->next = report_types;
|
|
|
|
|
report_types = type;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-04-26 07:30:54 +02:00
|
|
|
|
static quicklist *get_regions_distance(region * root, int radius)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
quicklist *ql, *rlist = NULL;
|
|
|
|
|
int qi = 0;
|
|
|
|
|
|
|
|
|
|
ql_push(&rlist, root);
|
|
|
|
|
fset(root, RF_MARK);
|
|
|
|
|
ql = rlist;
|
|
|
|
|
|
|
|
|
|
while (ql) {
|
|
|
|
|
region *r = (region *)ql_get(ql, qi);
|
|
|
|
|
region * next[MAXDIRECTIONS];
|
|
|
|
|
int d;
|
|
|
|
|
get_neighbours(r, next);
|
|
|
|
|
|
|
|
|
|
for (d = 0; d != MAXDIRECTIONS; ++d) {
|
|
|
|
|
if (next[d] && !fval(next[d], RF_MARK) && distance(next[d], root) <= radius) {
|
|
|
|
|
ql_push(&rlist, next[d]);
|
|
|
|
|
fset(next[d], RF_MARK);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ql_advance(&ql, &qi, 1);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
2014-08-14 09:57:05 +02:00
|
|
|
|
for (ql = rlist, qi = 0; ql; ql_advance(&ql, &qi, 1)) {
|
|
|
|
|
region *r = (region *)ql_get(ql, qi);
|
|
|
|
|
freset(r, RF_MARK);
|
|
|
|
|
}
|
|
|
|
|
return rlist;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void view_default(struct seen_region **seen, region * r, faction * f)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
int dir;
|
|
|
|
|
for (dir = 0; dir != MAXDIRECTIONS; ++dir) {
|
|
|
|
|
region *r2 = rconnect(r, dir);
|
|
|
|
|
if (r2) {
|
|
|
|
|
connection *b = get_borders(r, r2);
|
|
|
|
|
while (b) {
|
|
|
|
|
if (!b->type->transparent(b, f))
|
|
|
|
|
break;
|
|
|
|
|
b = b->next;
|
|
|
|
|
}
|
|
|
|
|
if (!b)
|
|
|
|
|
add_seen(seen, r2, see_neighbour, false);
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void view_neighbours(struct seen_region **seen, region * r, faction * f)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
int d;
|
|
|
|
|
region * nb[MAXDIRECTIONS];
|
|
|
|
|
|
|
|
|
|
get_neighbours(r, nb);
|
|
|
|
|
for (d = 0; d != MAXDIRECTIONS; ++d) {
|
|
|
|
|
region *r2 = nb[d];
|
|
|
|
|
if (r2) {
|
|
|
|
|
connection *b = get_borders(r, r2);
|
|
|
|
|
while (b) {
|
|
|
|
|
if (!b->type->transparent(b, f))
|
2011-03-07 08:02:35 +01:00
|
|
|
|
break;
|
2014-08-14 09:57:05 +02:00
|
|
|
|
b = b->next;
|
|
|
|
|
}
|
|
|
|
|
if (!b) {
|
|
|
|
|
if (add_seen(seen, r2, see_far, false)) {
|
|
|
|
|
if (!(fval(r2->terrain, FORBIDDEN_REGION))) {
|
|
|
|
|
int dir;
|
|
|
|
|
for (dir = 0; dir != MAXDIRECTIONS; ++dir) {
|
|
|
|
|
region *r3 = rconnect(r2, dir);
|
|
|
|
|
if (r3) {
|
|
|
|
|
connection *b = get_borders(r2, r3);
|
|
|
|
|
while (b) {
|
|
|
|
|
if (!b->type->transparent(b, f))
|
|
|
|
|
break;
|
|
|
|
|
b = b->next;
|
|
|
|
|
}
|
|
|
|
|
if (!b)
|
|
|
|
|
add_seen(seen, r3, see_neighbour, false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2011-03-07 08:02:35 +01:00
|
|
|
|
recurse_regatta(struct seen_region **seen, region * center, region * r,
|
2014-08-14 09:57:05 +02:00
|
|
|
|
faction * f, int maxdist)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
int d;
|
|
|
|
|
int dist = distance(center, r);
|
|
|
|
|
region * nb[MAXDIRECTIONS];
|
|
|
|
|
|
|
|
|
|
get_neighbours(r, nb);
|
|
|
|
|
for (d = 0; d != MAXDIRECTIONS; ++d) {
|
|
|
|
|
region *r2 = nb[d];
|
|
|
|
|
if (r2) {
|
|
|
|
|
int ndist = distance(center, r2);
|
|
|
|
|
if (ndist > dist && fval(r2->terrain, SEA_REGION)) {
|
|
|
|
|
connection *b = get_borders(r, r2);
|
|
|
|
|
while (b) {
|
|
|
|
|
if (!b->type->transparent(b, f))
|
|
|
|
|
break;
|
|
|
|
|
b = b->next;
|
|
|
|
|
}
|
|
|
|
|
if (!b) {
|
|
|
|
|
if (ndist < maxdist) {
|
|
|
|
|
if (add_seen(seen, r2, see_far, false)) {
|
|
|
|
|
recurse_regatta(seen, center, r2, f, maxdist);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
add_seen(seen, r2, see_neighbour, false);
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void view_regatta(struct seen_region **seen, region * r, faction * f)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
unit *u;
|
|
|
|
|
int skill = 0;
|
|
|
|
|
for (u = r->units; u; u = u->next) {
|
|
|
|
|
if (u->faction == f) {
|
|
|
|
|
int es = effskill(u, SK_PERCEPTION);
|
|
|
|
|
if (es > skill)
|
|
|
|
|
skill = es;
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
2014-08-14 09:57:05 +02:00
|
|
|
|
recurse_regatta(seen, r, r, f, skill / 2);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-04-24 21:19:34 +02:00
|
|
|
|
static void prepare_lighthouse(building * b, faction * f)
|
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
int range = lighthouse_range(b, f);
|
|
|
|
|
quicklist *ql, *rlist = get_regions_distance(b->region, range);
|
|
|
|
|
int qi;
|
2011-04-26 07:30:54 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
for (ql = rlist, qi = 0; ql; ql_advance(&ql, &qi, 1)) {
|
|
|
|
|
region *rl = (region *)ql_get(ql, qi);
|
|
|
|
|
if (!fval(rl->terrain, FORBIDDEN_REGION)) {
|
|
|
|
|
region * next[MAXDIRECTIONS];
|
|
|
|
|
int d;
|
|
|
|
|
|
|
|
|
|
get_neighbours(rl, next);
|
|
|
|
|
add_seen(f->seen, rl, see_lighthouse, false);
|
|
|
|
|
for (d = 0; d != MAXDIRECTIONS; ++d) {
|
|
|
|
|
if (next[d]) {
|
|
|
|
|
add_seen(f->seen, next[d], see_neighbour, false);
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-04-24 21:19:34 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-08-14 09:57:05 +02:00
|
|
|
|
ql_free(rlist);
|
2011-04-24 21:19:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2012-05-17 21:23:25 +02:00
|
|
|
|
void reorder_units(region * r)
|
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
unit **unext = &r->units;
|
|
|
|
|
|
|
|
|
|
if (r->buildings) {
|
|
|
|
|
building *b = r->buildings;
|
|
|
|
|
while (*unext && b) {
|
|
|
|
|
unit **ufirst = unext; /* where the first unit in the building should go */
|
|
|
|
|
unit **umove = unext; /* a unit we consider moving */
|
|
|
|
|
unit *owner = building_owner(b);
|
|
|
|
|
while (owner && *umove) {
|
|
|
|
|
unit *u = *umove;
|
|
|
|
|
if (u->building == b) {
|
|
|
|
|
unit **uinsert = unext;
|
|
|
|
|
if (u == owner) {
|
|
|
|
|
uinsert = ufirst;
|
|
|
|
|
}
|
|
|
|
|
if (umove != uinsert) {
|
|
|
|
|
*umove = u->next;
|
|
|
|
|
u->next = *uinsert;
|
|
|
|
|
*uinsert = u;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* no need to move, skip ahead */
|
|
|
|
|
umove = &u->next;
|
|
|
|
|
}
|
|
|
|
|
if (unext == uinsert) {
|
|
|
|
|
/* we have a new well-placed unit. jump over it */
|
|
|
|
|
unext = &u->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
umove = &u->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
b = b->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (r->ships) {
|
|
|
|
|
ship *sh = r->ships;
|
|
|
|
|
/* first, move all units up that are not on ships */
|
|
|
|
|
unit **umove = unext; /* a unit we consider moving */
|
|
|
|
|
while (*umove) {
|
|
|
|
|
unit *u = *umove;
|
|
|
|
|
if (u->number && !u->ship) {
|
|
|
|
|
if (umove != unext) {
|
|
|
|
|
*umove = u->next;
|
|
|
|
|
u->next = *unext;
|
|
|
|
|
*unext = u;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* no need to move, skip ahead */
|
|
|
|
|
umove = &u->next;
|
|
|
|
|
}
|
|
|
|
|
/* we have a new well-placed unit. jump over it */
|
|
|
|
|
unext = &u->next;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
umove = &u->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (*unext && sh) {
|
|
|
|
|
unit **ufirst = unext; /* where the first unit in the building should go */
|
|
|
|
|
unit **umove = unext; /* a unit we consider moving */
|
|
|
|
|
unit *owner = ship_owner(sh);
|
|
|
|
|
while (owner && *umove) {
|
|
|
|
|
unit *u = *umove;
|
|
|
|
|
if (u->number && u->ship == sh) {
|
|
|
|
|
unit **uinsert = unext;
|
|
|
|
|
if (u == owner) {
|
|
|
|
|
uinsert = ufirst;
|
|
|
|
|
owner = u;
|
|
|
|
|
}
|
|
|
|
|
if (umove != uinsert) {
|
|
|
|
|
*umove = u->next;
|
|
|
|
|
u->next = *uinsert;
|
|
|
|
|
*uinsert = u;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* no need to move, skip ahead */
|
|
|
|
|
umove = &u->next;
|
|
|
|
|
}
|
|
|
|
|
if (unext == uinsert) {
|
|
|
|
|
/* we have a new well-placed unit. jump over it */
|
|
|
|
|
unext = &u->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
umove = &u->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
sh = sh->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-05-17 21:23:25 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void prepare_reports(void)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
region *r;
|
|
|
|
|
faction *f;
|
|
|
|
|
building *b;
|
|
|
|
|
const struct building_type *bt_lighthouse = bt_find("lighthouse");
|
|
|
|
|
|
|
|
|
|
for (f = factions; f; f = f->next) {
|
|
|
|
|
if (f->seen) seen_done(f->seen);
|
|
|
|
|
f->seen = seen_init();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (r = regions; r; r = r->next) {
|
|
|
|
|
attrib *ru;
|
|
|
|
|
unit *u;
|
|
|
|
|
plane *p = rplane(r);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
reorder_units(r);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (p) {
|
|
|
|
|
watcher *w = p->watchers;
|
|
|
|
|
for (; w; w = w->next) {
|
|
|
|
|
add_seen(w->faction->seen, r, w->mode, false);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
#ifdef SMART_INTERVALS
|
2014-08-14 09:57:05 +02:00
|
|
|
|
update_interval(w->faction, r);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
#endif
|
2014-08-14 09:57:05 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-08 13:29:26 +02:00
|
|
|
|
/* Region owner get always the Lighthouse report */
|
|
|
|
|
if (check_param(global.parameters, "rules.region_owner_pay_building", bt_lighthouse->_name)) {
|
|
|
|
|
for (b = rbuildings(r); b; b = b->next) {
|
|
|
|
|
if (b && b->type == bt_lighthouse) {
|
2014-08-08 17:15:12 +02:00
|
|
|
|
u = building_owner(b);
|
2014-08-08 13:29:26 +02:00
|
|
|
|
if (u) {
|
|
|
|
|
prepare_lighthouse(b, u->faction);
|
|
|
|
|
if (u_race(u) != get_race(RC_SPELL) || u->number == RS_FARVISION) {
|
|
|
|
|
if (fval(u, UFL_DISBELIEVES)) {
|
|
|
|
|
add_seen(u->faction->seen, r, see_unit, true);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
add_seen(u->faction->seen, r, see_unit, false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-08 13:29:26 +02:00
|
|
|
|
for (u = r->units; u; u = u->next) {
|
|
|
|
|
if (u->building && u->building->type == bt_lighthouse) {
|
|
|
|
|
/* we are in a lighthouse. add the regions we can see from here! */
|
|
|
|
|
prepare_lighthouse(u->building, u->faction);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (u_race(u) != get_race(RC_SPELL) || u->number == RS_FARVISION) {
|
|
|
|
|
if (fval(u, UFL_DISBELIEVES)) {
|
|
|
|
|
add_seen(u->faction->seen, r, see_unit, true);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
add_seen(u->faction->seen, r, see_unit, false);
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
2014-08-08 13:29:26 +02:00
|
|
|
|
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (fval(r, RF_TRAVELUNIT)) {
|
|
|
|
|
for (ru = a_find(r->attribs, &at_travelunit);
|
|
|
|
|
ru && ru->type == &at_travelunit; ru = ru->next) {
|
|
|
|
|
unit *u = (unit *)ru->data.v;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
/* make sure the faction has not been removed this turn: */
|
|
|
|
|
if (u->faction) {
|
|
|
|
|
add_seen(u->faction->seen, r, see_travel, false);
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-17 17:22:26 +01:00
|
|
|
|
static region *lastregion(faction * f)
|
|
|
|
|
{
|
|
|
|
|
#ifdef SMART_INTERVALS
|
|
|
|
|
unit *u = f->units;
|
|
|
|
|
region *r = f->last;
|
|
|
|
|
|
|
|
|
|
if (u == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
if (r != NULL)
|
|
|
|
|
return r->next;
|
|
|
|
|
|
|
|
|
|
/* it is safe to start in the region of the first unit. */
|
|
|
|
|
f->last = u->region;
|
|
|
|
|
/* if regions have indices, we can skip ahead: */
|
|
|
|
|
for (u = u->nextF; u != NULL; u = u->nextF) {
|
|
|
|
|
r = u->region;
|
|
|
|
|
if (r->index > f->last->index)
|
|
|
|
|
f->last = r;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* we continue from the best region and look for travelthru etc. */
|
|
|
|
|
for (r = f->last->next; r; r = r->next) {
|
|
|
|
|
plane *p = rplane(r);
|
|
|
|
|
|
|
|
|
|
/* search the region for travelthru-attributes: */
|
|
|
|
|
if (fval(r, RF_TRAVELUNIT)) {
|
|
|
|
|
attrib *ru = a_find(r->attribs, &at_travelunit);
|
|
|
|
|
while (ru && ru->type == &at_travelunit) {
|
|
|
|
|
u = (unit *)ru->data.v;
|
|
|
|
|
if (u->faction == f) {
|
|
|
|
|
f->last = r;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
ru = ru->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (f->last == r)
|
|
|
|
|
continue;
|
|
|
|
|
if (check_leuchtturm(r, f))
|
|
|
|
|
f->last = r;
|
|
|
|
|
if (p && is_watcher(p, f)) {
|
|
|
|
|
f->last = r;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return f->last->next;
|
|
|
|
|
#else
|
|
|
|
|
return NULL;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static region *firstregion(faction * f)
|
|
|
|
|
{
|
|
|
|
|
#ifdef SMART_INTERVALS
|
|
|
|
|
region *r = f->first;
|
|
|
|
|
|
|
|
|
|
if (f->units == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
if (r != NULL)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
return f->first = regions;
|
|
|
|
|
#else
|
|
|
|
|
return regions;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static seen_region **prepare_report(faction * f)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
struct seen_region *sr;
|
|
|
|
|
region *r = firstregion(f);
|
|
|
|
|
region *last = lastregion(f);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
link_seen(f->seen, r, last);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
for (sr = NULL; sr == NULL && r != last; r = r->next) {
|
|
|
|
|
sr = find_seen(f->seen, r);
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
for (; sr != NULL; sr = sr->next) {
|
|
|
|
|
if (sr->mode > see_neighbour) {
|
|
|
|
|
region *r = sr->r;
|
|
|
|
|
plane *p = rplane(r);
|
|
|
|
|
void(*view) (struct seen_region **, region *, faction *) = view_default;
|
2012-05-14 23:16:02 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (p && fval(p, PFL_SEESPECIAL)) {
|
|
|
|
|
/* TODO: this is not very customizable */
|
|
|
|
|
view = (strcmp(p->name, "Regatta") == 0) ? view_regatta : view_neighbours;
|
|
|
|
|
}
|
|
|
|
|
view(f->seen, r, f);
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
2014-08-14 09:57:05 +02:00
|
|
|
|
return f->seen;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
int write_reports(faction * f, time_t ltime)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
int backup = 1, maxbackup = 128 * 1000;
|
|
|
|
|
bool gotit = false;
|
|
|
|
|
struct report_context ctx;
|
|
|
|
|
const char *encoding = "UTF-8";
|
|
|
|
|
|
|
|
|
|
if (noreports) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
ctx.f = f;
|
|
|
|
|
ctx.report_time = time(NULL);
|
|
|
|
|
ctx.seen = prepare_report(f);
|
|
|
|
|
ctx.first = firstregion(f);
|
|
|
|
|
ctx.last = lastregion(f);
|
|
|
|
|
ctx.addresses = NULL;
|
|
|
|
|
ctx.userdata = NULL;
|
2014-11-23 15:50:22 +01:00
|
|
|
|
if (ctx.seen) {
|
|
|
|
|
get_seen_interval(&ctx);
|
|
|
|
|
}
|
2014-08-14 09:57:05 +02:00
|
|
|
|
get_addresses(&ctx);
|
|
|
|
|
_mkdir(reportpath());
|
|
|
|
|
do {
|
|
|
|
|
report_type *rtype = report_types;
|
|
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
|
if (verbosity >= 2) {
|
|
|
|
|
log_printf(stdout, "Reports for %s:", factionname(f));
|
|
|
|
|
}
|
|
|
|
|
for (; rtype != NULL; rtype = rtype->next) {
|
|
|
|
|
if (f->options & rtype->flag) {
|
|
|
|
|
char filename[MAX_PATH];
|
|
|
|
|
sprintf(filename, "%s/%d-%s.%s", reportpath(), turn, factionid(f),
|
|
|
|
|
rtype->extension);
|
|
|
|
|
if (rtype->write(filename, &ctx, encoding) == 0) {
|
|
|
|
|
gotit = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (errno) {
|
|
|
|
|
char zText[64];
|
|
|
|
|
log_warning("retrying, error %d during reports for faction %s", errno, factionname(f));
|
|
|
|
|
sprintf(zText, "waiting %u seconds before we retry", backup / 1000);
|
|
|
|
|
perror(zText);
|
|
|
|
|
_sleep(backup);
|
|
|
|
|
if (backup < maxbackup) {
|
|
|
|
|
backup *= 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} while (errno);
|
|
|
|
|
if (!gotit) {
|
|
|
|
|
log_warning("No report for faction %s!", factionid(f));
|
|
|
|
|
}
|
|
|
|
|
ql_free(ctx.addresses);
|
2014-11-23 15:50:22 +01:00
|
|
|
|
if (ctx.seen) {
|
|
|
|
|
seen_done(ctx.seen);
|
|
|
|
|
}
|
2014-08-14 09:57:05 +02:00
|
|
|
|
return 0;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void nmr_warnings(void)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
faction *f, *fa;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
#define FRIEND (HELP_GUARD|HELP_MONEY)
|
2014-08-14 09:57:05 +02:00
|
|
|
|
for (f = factions; f; f = f->next) {
|
2014-11-11 16:53:56 +01:00
|
|
|
|
if (!fval(f, FFL_NOIDLEOUT) && (turn - f->lastorders) >= 2) {
|
2014-08-14 09:57:05 +02:00
|
|
|
|
message *msg = NULL;
|
|
|
|
|
for (fa = factions; fa; fa = fa->next) {
|
|
|
|
|
int warn = 0;
|
|
|
|
|
if (get_param_int(global.parameters, "rules.alliances", 0) != 0) {
|
|
|
|
|
if (f->alliance && f->alliance == fa->alliance) {
|
|
|
|
|
warn = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (alliedfaction(NULL, f, fa, FRIEND)
|
|
|
|
|
&& alliedfaction(NULL, fa, f, FRIEND)) {
|
|
|
|
|
warn = 1;
|
|
|
|
|
}
|
|
|
|
|
if (warn) {
|
|
|
|
|
if (msg == NULL) {
|
|
|
|
|
msg =
|
|
|
|
|
msg_message("warn_dropout", "faction turns", f,
|
|
|
|
|
turn - f->lastorders);
|
|
|
|
|
}
|
|
|
|
|
add_message(&fa->msgs, msg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (msg != NULL)
|
|
|
|
|
msg_release(msg);
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void report_donations(void)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
region *r;
|
|
|
|
|
for (r = regions; r; r = r->next) {
|
|
|
|
|
while (r->donations) {
|
|
|
|
|
donation *sp = r->donations;
|
|
|
|
|
if (sp->amount > 0) {
|
|
|
|
|
struct message *msg = msg_message("donation",
|
|
|
|
|
"from to amount", sp->f1, sp->f2, sp->amount);
|
|
|
|
|
r_addmessage(r, sp->f1, msg);
|
|
|
|
|
r_addmessage(r, sp->f2, msg);
|
|
|
|
|
msg_release(msg);
|
|
|
|
|
}
|
|
|
|
|
r->donations = sp->next;
|
|
|
|
|
free(sp);
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void write_script(FILE * F, const faction * f)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
report_type *rtype;
|
|
|
|
|
char buf[1024];
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
fprintf(F, "faction=%s:email=%s:lang=%s", factionid(f), f->email,
|
|
|
|
|
locale_name(f->locale));
|
|
|
|
|
if (f->options & (1 << O_BZIP2))
|
|
|
|
|
fputs(":compression=bz2", F);
|
|
|
|
|
else
|
|
|
|
|
fputs(":compression=zip", F);
|
|
|
|
|
|
|
|
|
|
fputs(":reports=", F);
|
|
|
|
|
buf[0] = 0;
|
|
|
|
|
for (rtype = report_types; rtype != NULL; rtype = rtype->next) {
|
|
|
|
|
if (f->options & rtype->flag) {
|
|
|
|
|
if (buf[0])
|
|
|
|
|
strcat(buf, ",");
|
|
|
|
|
strcat(buf, rtype->extension);
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
2014-08-14 09:57:05 +02:00
|
|
|
|
fputs(buf, F);
|
|
|
|
|
fputc('\n', F);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
int init_reports(void)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
prepare_reports();
|
|
|
|
|
{
|
|
|
|
|
if (_access(reportpath(), 0) != 0) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2014-03-16 04:41:58 +01:00
|
|
|
|
}
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (_mkdir(reportpath()) != 0) {
|
|
|
|
|
if (errno != EEXIST) {
|
|
|
|
|
perror("could not create reportpath");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
2014-08-14 09:57:05 +02:00
|
|
|
|
return 0;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
int reports(void)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
faction *f;
|
|
|
|
|
FILE *mailit;
|
|
|
|
|
time_t ltime = time(NULL);
|
|
|
|
|
int retval = 0;
|
|
|
|
|
char path[MAX_PATH];
|
|
|
|
|
|
|
|
|
|
if (verbosity >= 1) {
|
|
|
|
|
log_printf(stdout, "Writing reports for turn %d:", turn);
|
|
|
|
|
}
|
|
|
|
|
nmr_warnings();
|
|
|
|
|
report_donations();
|
|
|
|
|
remove_empty_units();
|
|
|
|
|
|
|
|
|
|
_mkdir(reportpath());
|
|
|
|
|
sprintf(path, "%s/reports.txt", reportpath());
|
|
|
|
|
mailit = fopen(path, "w");
|
|
|
|
|
if (mailit == NULL) {
|
|
|
|
|
log_error("%s could not be opened!\n", path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (f = factions; f; f = f->next) {
|
|
|
|
|
int error = write_reports(f, ltime);
|
|
|
|
|
if (error)
|
|
|
|
|
retval = error;
|
|
|
|
|
if (mailit)
|
|
|
|
|
write_script(mailit, f);
|
|
|
|
|
}
|
2011-03-07 08:02:35 +01:00
|
|
|
|
if (mailit)
|
2014-08-14 09:57:05 +02:00
|
|
|
|
fclose(mailit);
|
|
|
|
|
free_seen();
|
2010-08-08 10:06:34 +02:00
|
|
|
|
#ifdef GLOBAL_REPORT
|
2014-08-14 09:57:05 +02:00
|
|
|
|
{
|
|
|
|
|
const char *str = get_param(global.parameters, "globalreport");
|
|
|
|
|
if (str != NULL) {
|
|
|
|
|
sprintf(path, "%s/%s.%u.cr", reportpath(), str, turn);
|
|
|
|
|
global_report(path);
|
|
|
|
|
}
|
2012-05-20 09:16:12 +02:00
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
#endif
|
2014-08-14 09:57:05 +02:00
|
|
|
|
return retval;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static variant var_copy_string(variant x)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
x.v = x.v ? _strdup((const char *)x.v) : 0;
|
|
|
|
|
return x;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void var_free_string(variant x)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
free(x.v);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static variant var_copy_order(variant x)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
x.v = copy_order((order *)x.v);
|
|
|
|
|
return x;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void var_free_order(variant x)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
free_order(x.v);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static variant var_copy_items(variant x)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
item *isrc;
|
|
|
|
|
resource *rdst = NULL, **rptr = &rdst;
|
2011-03-07 08:02:35 +01:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
for (isrc = (item *)x.v; isrc != NULL; isrc = isrc->next) {
|
|
|
|
|
resource *res = malloc(sizeof(resource));
|
|
|
|
|
res->number = isrc->number;
|
|
|
|
|
res->type = isrc->type->rtype;
|
|
|
|
|
*rptr = res;
|
|
|
|
|
rptr = &res->next;
|
|
|
|
|
}
|
|
|
|
|
*rptr = NULL;
|
|
|
|
|
x.v = rdst;
|
|
|
|
|
return x;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void var_free_resources(variant x)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
resource *rsrc = (resource *)x.v;
|
|
|
|
|
while (rsrc) {
|
|
|
|
|
resource *res = rsrc->next;
|
|
|
|
|
free(rsrc);
|
|
|
|
|
rsrc = res;
|
|
|
|
|
}
|
|
|
|
|
x.v = 0;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void var_free_regions(variant x)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
free(x.v);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
const char *trailinto(const region * r, const struct locale *lang)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
char ref[32];
|
|
|
|
|
const char *s;
|
|
|
|
|
if (r) {
|
|
|
|
|
const char *tname = terrain_name(r);
|
|
|
|
|
strcat(strcpy(ref, tname), "_trail");
|
2015-01-08 20:55:29 +01:00
|
|
|
|
s = LOC(lang, ref);
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (s && *s) {
|
|
|
|
|
if (strstr(s, "%s"))
|
|
|
|
|
return s;
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
2014-08-14 09:57:05 +02:00
|
|
|
|
return "%s";
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t
|
2011-03-07 08:02:35 +01:00
|
|
|
|
f_regionid(const region * r, const faction * f, char *buffer, size_t size)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
size_t len;
|
|
|
|
|
if (!r) {
|
|
|
|
|
len = strlcpy(buffer, "(Chaos)", size);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
plane *pl = rplane(r);
|
|
|
|
|
const char *name = pl ? pl->name : 0;
|
|
|
|
|
int nx = r->x, ny = r->y;
|
|
|
|
|
int named = (name && name[0]);
|
|
|
|
|
pnormalize(&nx, &ny, pl);
|
|
|
|
|
adjust_coordinates(f, &nx, &ny, pl, r);
|
|
|
|
|
len = strlcpy(buffer, rname(r, f ? f->locale : 0), size);
|
|
|
|
|
_snprintf(buffer + len, size - len, " (%d,%d%s%s)", nx, ny, named ? "," : "", (named) ? name : "");
|
|
|
|
|
buffer[size - 1] = 0;
|
|
|
|
|
len = strlen(buffer);
|
|
|
|
|
}
|
|
|
|
|
return len;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static char *f_regionid_s(const region * r, const faction * f)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
static int i = 0;
|
2014-08-24 22:54:40 +02:00
|
|
|
|
static char bufs[4][NAMESIZE + 20]; // FIXME: static return value
|
2014-08-14 09:57:05 +02:00
|
|
|
|
char *buf = bufs[(++i) % 4];
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
f_regionid(r, f, buf, NAMESIZE + 20);
|
|
|
|
|
return buf;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** BEGIN MESSAGE RENDERING ***/
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void eval_localize(struct opstack **stack, const void *userdata)
|
|
|
|
|
{ /* (string, locale) -> string */
|
2014-08-14 09:57:05 +02:00
|
|
|
|
const struct faction *f = (const struct faction *)userdata;
|
|
|
|
|
const struct locale *lang = f ? f->locale : default_locale;
|
|
|
|
|
const char *c = (const char *)opop_v(stack);
|
2015-01-08 20:55:29 +01:00
|
|
|
|
c = LOC(lang, c);
|
2014-08-14 09:57:05 +02:00
|
|
|
|
opush_v(stack, strcpy(balloc(strlen(c) + 1), c));
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void eval_trailto(struct opstack **stack, const void *userdata)
|
|
|
|
|
{ /* (int, int) -> int */
|
2014-08-14 09:57:05 +02:00
|
|
|
|
const struct faction *f = (const struct faction *)userdata;
|
|
|
|
|
const struct locale *lang = f ? f->locale : default_locale;
|
|
|
|
|
const struct region *r = (const struct region *)opop(stack).v;
|
|
|
|
|
const char *trail = trailinto(r, lang);
|
|
|
|
|
const char *rn = f_regionid_s(r, f);
|
|
|
|
|
variant var;
|
|
|
|
|
char *x = var.v = balloc(strlen(trail) + strlen(rn));
|
|
|
|
|
sprintf(x, trail, rn);
|
|
|
|
|
opush(stack, var);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void eval_unit(struct opstack **stack, const void *userdata)
|
|
|
|
|
{ /* unit -> string */
|
2014-08-14 09:57:05 +02:00
|
|
|
|
const struct faction *f = (const struct faction *)userdata;
|
|
|
|
|
const struct unit *u = (const struct unit *)opop(stack).v;
|
|
|
|
|
const char *c = u ? unitname(u) : LOC(f->locale, "an_unknown_unit");
|
|
|
|
|
size_t len = strlen(c);
|
|
|
|
|
variant var;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
var.v = strcpy(balloc(len + 1), c);
|
|
|
|
|
opush(stack, var);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void eval_unit_dative(struct opstack **stack, const void *userdata)
|
|
|
|
|
{ /* unit -> string */
|
2014-08-14 09:57:05 +02:00
|
|
|
|
const struct faction *f = (const struct faction *)userdata;
|
|
|
|
|
const struct unit *u = (const struct unit *)opop(stack).v;
|
|
|
|
|
const char *c = u ? unitname(u) : LOC(f->locale, "unknown_unit_dative");
|
|
|
|
|
size_t len = strlen(c);
|
|
|
|
|
variant var;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
var.v = strcpy(balloc(len + 1), c);
|
|
|
|
|
opush(stack, var);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void eval_spell(struct opstack **stack, const void *userdata)
|
|
|
|
|
{ /* unit -> string */
|
2014-08-14 09:57:05 +02:00
|
|
|
|
const struct faction *f = (const struct faction *)userdata;
|
|
|
|
|
const struct spell *sp = (const struct spell *)opop(stack).v;
|
|
|
|
|
const char *c =
|
|
|
|
|
sp ? spell_name(sp, f->locale) : LOC(f->locale, "an_unknown_spell");
|
|
|
|
|
size_t len = strlen(c);
|
|
|
|
|
variant var;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
var.v = strcpy(balloc(len + 1), c);
|
|
|
|
|
opush(stack, var);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void eval_curse(struct opstack **stack, const void *userdata)
|
|
|
|
|
{ /* unit -> string */
|
2014-08-14 09:57:05 +02:00
|
|
|
|
const struct faction *f = (const struct faction *)userdata;
|
|
|
|
|
const struct curse_type *sp = (const struct curse_type *)opop(stack).v;
|
|
|
|
|
const char *c =
|
|
|
|
|
sp ? curse_name(sp, f->locale) : LOC(f->locale, "an_unknown_curse");
|
|
|
|
|
size_t len = strlen(c);
|
|
|
|
|
variant var;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
var.v = strcpy(balloc(len + 1), c);
|
|
|
|
|
opush(stack, var);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void eval_unitname(struct opstack **stack, const void *userdata)
|
|
|
|
|
{ /* unit -> string */
|
2014-08-14 09:57:05 +02:00
|
|
|
|
const struct faction *f = (const struct faction *)userdata;
|
|
|
|
|
const struct unit *u = (const struct unit *)opop(stack).v;
|
2015-02-11 07:55:35 +01:00
|
|
|
|
const char *c = u ? unit_getname(u) : LOC(f->locale, "an_unknown_unit");
|
2014-08-14 09:57:05 +02:00
|
|
|
|
size_t len = strlen(c);
|
|
|
|
|
variant var;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
var.v = strcpy(balloc(len + 1), c);
|
|
|
|
|
opush(stack, var);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void eval_unitid(struct opstack **stack, const void *userdata)
|
|
|
|
|
{ /* unit -> int */
|
2014-08-14 09:57:05 +02:00
|
|
|
|
const struct faction *f = (const struct faction *)userdata;
|
|
|
|
|
const struct unit *u = (const struct unit *)opop(stack).v;
|
2015-02-11 07:55:35 +01:00
|
|
|
|
const char *c = u ? unit_getname(u) : LOC(f->locale, "an_unknown_unit");
|
2014-08-14 09:57:05 +02:00
|
|
|
|
size_t len = strlen(c);
|
|
|
|
|
variant var;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
var.v = strcpy(balloc(len + 1), c);
|
|
|
|
|
opush(stack, var);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void eval_unitsize(struct opstack **stack, const void *userdata)
|
|
|
|
|
{ /* unit -> int */
|
2014-08-14 09:57:05 +02:00
|
|
|
|
const struct unit *u = (const struct unit *)opop(stack).v;
|
|
|
|
|
variant var;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
var.i = u->number;
|
|
|
|
|
opush(stack, var);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void eval_faction(struct opstack **stack, const void *userdata)
|
|
|
|
|
{ /* faction -> string */
|
2014-08-14 09:57:05 +02:00
|
|
|
|
const struct faction *f = (const struct faction *)opop(stack).v;
|
|
|
|
|
const char *c = factionname(f);
|
|
|
|
|
size_t len = strlen(c);
|
|
|
|
|
variant var;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
var.v = strcpy(balloc(len + 1), c);
|
|
|
|
|
opush(stack, var);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void eval_alliance(struct opstack **stack, const void *userdata)
|
|
|
|
|
{ /* faction -> string */
|
2014-08-14 09:57:05 +02:00
|
|
|
|
const struct alliance *al = (const struct alliance *)opop(stack).v;
|
|
|
|
|
const char *c = alliancename(al);
|
|
|
|
|
variant var;
|
|
|
|
|
if (c != NULL) {
|
|
|
|
|
size_t len = strlen(c);
|
|
|
|
|
var.v = strcpy(balloc(len + 1), c);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
var.v = NULL;
|
|
|
|
|
opush(stack, var);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void eval_region(struct opstack **stack, const void *userdata)
|
|
|
|
|
{ /* region -> string */
|
2014-08-14 09:57:05 +02:00
|
|
|
|
char name[NAMESIZE + 32];
|
|
|
|
|
const struct faction *f = (const struct faction *)userdata;
|
|
|
|
|
const struct region *r = (const struct region *)opop(stack).v;
|
|
|
|
|
const char *c = write_regionname(r, f, name, sizeof(name));
|
|
|
|
|
size_t len = strlen(c);
|
|
|
|
|
variant var;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
var.v = strcpy(balloc(len + 1), c);
|
|
|
|
|
opush(stack, var);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void eval_terrain(struct opstack **stack, const void *userdata)
|
|
|
|
|
{ /* region -> string */
|
2014-08-14 09:57:05 +02:00
|
|
|
|
const struct faction *f = (const struct faction *)userdata;
|
|
|
|
|
const struct region *r = (const struct region *)opop(stack).v;
|
|
|
|
|
const char *c = LOC(f->locale, terrain_name(r));
|
|
|
|
|
size_t len = strlen(c);
|
|
|
|
|
variant var;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
var.v = strcpy(balloc(len + 1), c);
|
|
|
|
|
opush(stack, var);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void eval_ship(struct opstack **stack, const void *userdata)
|
|
|
|
|
{ /* ship -> string */
|
2014-08-14 09:57:05 +02:00
|
|
|
|
const struct faction *f = (const struct faction *)userdata;
|
|
|
|
|
const struct ship *u = (const struct ship *)opop(stack).v;
|
|
|
|
|
const char *c = u ? shipname(u) : LOC(f->locale, "an_unknown_ship");
|
|
|
|
|
size_t len = strlen(c);
|
|
|
|
|
variant var;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
var.v = strcpy(balloc(len + 1), c);
|
|
|
|
|
opush(stack, var);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void eval_building(struct opstack **stack, const void *userdata)
|
|
|
|
|
{ /* building -> string */
|
2014-08-14 09:57:05 +02:00
|
|
|
|
const struct faction *f = (const struct faction *)userdata;
|
|
|
|
|
const struct building *u = (const struct building *)opop(stack).v;
|
|
|
|
|
const char *c = u ? buildingname(u) : LOC(f->locale, "an_unknown_building");
|
|
|
|
|
size_t len = strlen(c);
|
|
|
|
|
variant var;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
var.v = strcpy(balloc(len + 1), c);
|
|
|
|
|
opush(stack, var);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void eval_weight(struct opstack **stack, const void *userdata)
|
|
|
|
|
{ /* region -> string */
|
2014-08-14 09:57:05 +02:00
|
|
|
|
char buffer[32];
|
|
|
|
|
const struct faction *f = (const struct faction *)userdata;
|
|
|
|
|
const struct locale *lang = f->locale;
|
|
|
|
|
int weight = opop_i(stack);
|
|
|
|
|
variant var;
|
|
|
|
|
|
|
|
|
|
if (weight % SCALEWEIGHT == 0) {
|
|
|
|
|
if (weight == SCALEWEIGHT) {
|
|
|
|
|
sprintf(buffer, "1 %s", LOC(lang, "weight_unit"));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
sprintf(buffer, "%u %s", weight / SCALEWEIGHT, LOC(lang,
|
|
|
|
|
"weight_unit_p"));
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
2014-08-14 09:57:05 +02:00
|
|
|
|
else {
|
|
|
|
|
if (weight == 1) {
|
|
|
|
|
sprintf(buffer, "1 %s %u", LOC(lang, "weight_per"), SCALEWEIGHT);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
sprintf(buffer, "%u %s %u", weight, LOC(lang, "weight_per_p"),
|
|
|
|
|
SCALEWEIGHT);
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
var.v = strcpy(balloc(strlen(buffer) + 1), buffer);
|
|
|
|
|
opush(stack, var);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void eval_resource(struct opstack **stack, const void *userdata)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
const faction *report = (const faction *)userdata;
|
|
|
|
|
const struct locale *lang = report ? report->locale : default_locale;
|
|
|
|
|
int j = opop(stack).i;
|
|
|
|
|
const struct resource_type *res = (const struct resource_type *)opop(stack).v;
|
|
|
|
|
const char *c = LOC(lang, resourcename(res, j != 1));
|
|
|
|
|
size_t len = strlen(c);
|
|
|
|
|
variant var;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
var.v = strcpy(balloc(len + 1), c);
|
|
|
|
|
opush(stack, var);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void eval_race(struct opstack **stack, const void *userdata)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
const faction *report = (const faction *)userdata;
|
|
|
|
|
const struct locale *lang = report ? report->locale : default_locale;
|
|
|
|
|
int j = opop(stack).i;
|
|
|
|
|
const race *r = (const race *)opop(stack).v;
|
2014-12-09 07:20:36 +01:00
|
|
|
|
const char *c = LOC(lang, rc_name_s(r, (j == 1) ? NAME_SINGULAR : NAME_PLURAL));
|
2014-08-14 09:57:05 +02:00
|
|
|
|
size_t len = strlen(c);
|
|
|
|
|
variant var;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
var.v = strcpy(balloc(len + 1), c);
|
|
|
|
|
opush(stack, var);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void eval_order(struct opstack **stack, const void *userdata)
|
|
|
|
|
{ /* order -> string */
|
2014-08-14 09:57:05 +02:00
|
|
|
|
const struct order *ord = (const struct order *)opop(stack).v;
|
2014-08-24 22:54:40 +02:00
|
|
|
|
char buf[512];
|
2014-08-14 09:57:05 +02:00
|
|
|
|
size_t len;
|
|
|
|
|
variant var;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
unused_arg(userdata);
|
|
|
|
|
write_order(ord, buf, sizeof(buf));
|
|
|
|
|
len = strlen(buf);
|
|
|
|
|
var.v = strcpy(balloc(len + 1), buf);
|
|
|
|
|
opush(stack, var);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void eval_resources(struct opstack **stack, const void *userdata)
|
|
|
|
|
{ /* order -> string */
|
2014-08-14 09:57:05 +02:00
|
|
|
|
const faction *report = (const faction *)userdata;
|
|
|
|
|
const struct locale *lang = report ? report->locale : default_locale;
|
|
|
|
|
const struct resource *res = (const struct resource *)opop(stack).v;
|
2014-08-24 22:54:40 +02:00
|
|
|
|
char buf[1024]; /* but we only use about half of this */
|
2014-08-14 09:57:05 +02:00
|
|
|
|
size_t size = sizeof(buf) - 1;
|
|
|
|
|
variant var;
|
|
|
|
|
|
|
|
|
|
char *bufp = buf;
|
|
|
|
|
while (res != NULL && size > 4) {
|
|
|
|
|
const char *rname =
|
|
|
|
|
resourcename(res->type, (res->number != 1) ? NMF_PLURAL : 0);
|
|
|
|
|
int bytes = _snprintf(bufp, size, "%d %s", res->number, LOC(lang, rname));
|
|
|
|
|
if (bytes < 0 || wrptr(&bufp, &size, bytes) != 0 || size < sizeof(buf) / 2) {
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res = res->next;
|
|
|
|
|
if (res != NULL && size > 2) {
|
|
|
|
|
strcat(bufp, ", ");
|
|
|
|
|
bufp += 2;
|
|
|
|
|
size -= 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
*bufp = 0;
|
|
|
|
|
var.v = strcpy(balloc(bufp - buf + 1), buf);
|
|
|
|
|
opush(stack, var);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void eval_regions(struct opstack **stack, const void *userdata)
|
|
|
|
|
{ /* order -> string */
|
2014-08-14 09:57:05 +02:00
|
|
|
|
const faction *report = (const faction *)userdata;
|
|
|
|
|
int i = opop(stack).i;
|
|
|
|
|
int end, begin = opop(stack).i;
|
|
|
|
|
const arg_regions *regions = (const arg_regions *)opop(stack).v;
|
2014-08-24 22:54:40 +02:00
|
|
|
|
char buf[256];
|
2014-08-14 09:57:05 +02:00
|
|
|
|
size_t size = sizeof(buf) - 1;
|
|
|
|
|
variant var;
|
|
|
|
|
char *bufp = buf;
|
|
|
|
|
|
|
|
|
|
if (regions == NULL) {
|
|
|
|
|
end = begin;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (i >= 0)
|
|
|
|
|
end = begin + i;
|
|
|
|
|
else
|
|
|
|
|
end = regions->nregions + i;
|
|
|
|
|
}
|
|
|
|
|
for (i = begin; i < end; ++i) {
|
|
|
|
|
const char *rname = (const char *)regionname(regions->regions[i], report);
|
|
|
|
|
int bytes = (int)strlcpy(bufp, rname, size);
|
|
|
|
|
if (bytes && wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
2011-03-07 08:02:35 +01:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (i + 1 < end && size > 2) {
|
|
|
|
|
strcat(bufp, ", ");
|
|
|
|
|
bufp += 2;
|
|
|
|
|
size -= 2;
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
2014-08-14 09:57:05 +02:00
|
|
|
|
*bufp = 0;
|
|
|
|
|
var.v = strcpy(balloc(bufp - buf + 1), buf);
|
|
|
|
|
opush(stack, var);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void eval_trail(struct opstack **stack, const void *userdata)
|
|
|
|
|
{ /* order -> string */
|
2014-08-14 09:57:05 +02:00
|
|
|
|
const faction *report = (const faction *)userdata;
|
|
|
|
|
const struct locale *lang = report ? report->locale : default_locale;
|
|
|
|
|
int i, end = 0, begin = 0;
|
|
|
|
|
const arg_regions *regions = (const arg_regions *)opop(stack).v;
|
2014-08-24 22:54:40 +02:00
|
|
|
|
char buf[512];
|
2014-08-14 09:57:05 +02:00
|
|
|
|
size_t size = sizeof(buf) - 1;
|
|
|
|
|
variant var;
|
|
|
|
|
char *bufp = buf;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
#ifdef _SECURECRT_ERRCODE_VALUES_DEFINED
|
2014-08-14 09:57:05 +02:00
|
|
|
|
/* stupid MS broke _snprintf */
|
|
|
|
|
int eold = errno;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
#endif
|
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (regions != NULL) {
|
|
|
|
|
end = regions->nregions;
|
|
|
|
|
for (i = begin; i < end; ++i) {
|
|
|
|
|
region *r = regions->regions[i];
|
|
|
|
|
const char *trail = trailinto(r, lang);
|
|
|
|
|
const char *rn = f_regionid_s(r, report);
|
|
|
|
|
int bytes = _snprintf(bufp, size, trail, rn);
|
|
|
|
|
if (bytes < 0 || wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
2011-03-07 08:02:35 +01:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (i + 2 < end) {
|
|
|
|
|
bytes = (int)strlcpy(bufp, ", ", size);
|
|
|
|
|
}
|
|
|
|
|
else if (i + 1 < end) {
|
|
|
|
|
bytes = (int)strlcpy(bufp, LOC(lang, "list_and"), size);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
bytes = 0;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (bytes && wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
2014-08-14 09:57:05 +02:00
|
|
|
|
*bufp = 0;
|
|
|
|
|
var.v = strcpy(balloc(bufp - buf + 1), buf);
|
|
|
|
|
opush(stack, var);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
#ifdef _SECURECRT_ERRCODE_VALUES_DEFINED
|
2014-08-14 09:57:05 +02:00
|
|
|
|
if (errno == ERANGE) {
|
|
|
|
|
errno = eold;
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void eval_direction(struct opstack **stack, const void *userdata)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
const faction *report = (const faction *)userdata;
|
|
|
|
|
const struct locale *lang = report ? report->locale : default_locale;
|
|
|
|
|
int i = opop(stack).i;
|
|
|
|
|
const char *c = LOC(lang, (i >= 0) ? directions[i] : "unknown_direction");
|
|
|
|
|
size_t len = strlen(c);
|
|
|
|
|
variant var;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
var.v = strcpy(balloc(len + 1), c);
|
|
|
|
|
opush(stack, var);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void eval_skill(struct opstack **stack, const void *userdata)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
const faction *report = (const faction *)userdata;
|
|
|
|
|
const struct locale *lang = report ? report->locale : default_locale;
|
|
|
|
|
skill_t sk = (skill_t)opop(stack).i;
|
|
|
|
|
const char *c = skillname(sk, lang);
|
|
|
|
|
size_t len = strlen(c);
|
|
|
|
|
variant var;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
var.v = strcpy(balloc(len + 1), c);
|
|
|
|
|
opush(stack, var);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void eval_int36(struct opstack **stack, const void *userdata)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
int i = opop(stack).i;
|
|
|
|
|
const char *c = itoa36(i);
|
|
|
|
|
size_t len = strlen(c);
|
|
|
|
|
variant var;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-08-14 09:57:05 +02:00
|
|
|
|
var.v = strcpy(balloc(len + 1), c);
|
|
|
|
|
opush(stack, var);
|
|
|
|
|
unused_arg(userdata);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
2011-03-07 08:02:35 +01:00
|
|
|
|
|
2010-08-08 10:06:34 +02:00
|
|
|
|
/*** END MESSAGE RENDERING ***/
|
|
|
|
|
|
2014-12-17 17:40:36 +01:00
|
|
|
|
/* - String Listen --------------------------------------------- */
|
|
|
|
|
void addstrlist(strlist ** SP, const char *s)
|
|
|
|
|
{
|
|
|
|
|
strlist *slist = malloc(sizeof(strlist));
|
|
|
|
|
slist->next = NULL;
|
|
|
|
|
slist->s = _strdup(s);
|
|
|
|
|
addlist(SP, slist);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void freestrlist(strlist * s)
|
|
|
|
|
{
|
|
|
|
|
strlist *q, *p = s;
|
|
|
|
|
while (p) {
|
|
|
|
|
q = p->next;
|
|
|
|
|
free(p->s);
|
|
|
|
|
free(p);
|
|
|
|
|
p = q;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-08 10:06:34 +02:00
|
|
|
|
#include <util/nrmessage.h>
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static void log_orders(const struct message *msg)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
char buffer[4096];
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i != msg->type->nparameters; ++i) {
|
|
|
|
|
if (msg->type->types[i]->copy == &var_copy_order) {
|
|
|
|
|
const char *section = nr_section(msg);
|
2014-11-07 23:16:00 +01:00
|
|
|
|
nr_render(msg, default_locale, buffer, sizeof(buffer), NULL);
|
2014-08-14 09:57:05 +02:00
|
|
|
|
log_debug("MESSAGE [%s]: %s\n", section, buffer);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
void register_reports(void)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-08-14 09:57:05 +02:00
|
|
|
|
/* register datatypes for the different message objects */
|
|
|
|
|
register_argtype("alliance", NULL, NULL, VAR_VOIDPTR);
|
|
|
|
|
register_argtype("building", NULL, NULL, VAR_VOIDPTR);
|
|
|
|
|
register_argtype("direction", NULL, NULL, VAR_INT);
|
|
|
|
|
register_argtype("faction", NULL, NULL, VAR_VOIDPTR);
|
|
|
|
|
register_argtype("race", NULL, NULL, VAR_VOIDPTR);
|
|
|
|
|
register_argtype("region", NULL, NULL, VAR_VOIDPTR);
|
|
|
|
|
register_argtype("resource", NULL, NULL, VAR_VOIDPTR);
|
|
|
|
|
register_argtype("ship", NULL, NULL, VAR_VOIDPTR);
|
|
|
|
|
register_argtype("skill", NULL, NULL, VAR_VOIDPTR);
|
|
|
|
|
register_argtype("spell", NULL, NULL, VAR_VOIDPTR);
|
|
|
|
|
register_argtype("curse", NULL, NULL, VAR_VOIDPTR);
|
|
|
|
|
register_argtype("unit", NULL, NULL, VAR_VOIDPTR);
|
|
|
|
|
register_argtype("int", NULL, NULL, VAR_INT);
|
|
|
|
|
register_argtype("string", var_free_string, var_copy_string, VAR_VOIDPTR);
|
|
|
|
|
register_argtype("order", var_free_order, var_copy_order, VAR_VOIDPTR);
|
|
|
|
|
register_argtype("resources", var_free_resources, NULL, VAR_VOIDPTR);
|
|
|
|
|
register_argtype("items", var_free_resources, var_copy_items, VAR_VOIDPTR);
|
|
|
|
|
register_argtype("regions", var_free_regions, NULL, VAR_VOIDPTR);
|
|
|
|
|
|
|
|
|
|
msg_log_create = &log_orders;
|
|
|
|
|
|
|
|
|
|
/* register functions that turn message contents to readable strings */
|
|
|
|
|
add_function("alliance", &eval_alliance);
|
|
|
|
|
add_function("region", &eval_region);
|
|
|
|
|
add_function("terrain", &eval_terrain);
|
|
|
|
|
add_function("weight", &eval_weight);
|
|
|
|
|
add_function("resource", &eval_resource);
|
|
|
|
|
add_function("race", &eval_race);
|
|
|
|
|
add_function("faction", &eval_faction);
|
|
|
|
|
add_function("ship", &eval_ship);
|
|
|
|
|
add_function("unit", &eval_unit);
|
|
|
|
|
add_function("unit.dative", &eval_unit_dative);
|
|
|
|
|
add_function("unit.name", &eval_unitname);
|
|
|
|
|
add_function("unit.id", &eval_unitid);
|
|
|
|
|
add_function("unit.size", &eval_unitsize);
|
|
|
|
|
add_function("building", &eval_building);
|
|
|
|
|
add_function("skill", &eval_skill);
|
|
|
|
|
add_function("order", &eval_order);
|
|
|
|
|
add_function("direction", &eval_direction);
|
|
|
|
|
add_function("int36", &eval_int36);
|
|
|
|
|
add_function("trailto", &eval_trailto);
|
|
|
|
|
add_function("localize", &eval_localize);
|
|
|
|
|
add_function("spell", &eval_spell);
|
|
|
|
|
add_function("curse", &eval_curse);
|
|
|
|
|
add_function("resources", &eval_resources);
|
|
|
|
|
add_function("regions", &eval_regions);
|
|
|
|
|
add_function("trail", &eval_trail);
|
|
|
|
|
|
|
|
|
|
/* register alternative visibility functions */
|
|
|
|
|
register_function((pf_generic)view_neighbours, "view_neighbours");
|
|
|
|
|
register_function((pf_generic)view_regatta, "view_regatta");
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|