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-12-17 21:31:02 +01: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 "building.h"
|
|
|
|
|
|
2017-08-21 20:18:19 +02:00
|
|
|
|
#include <attributes/reduceproduction.h>
|
|
|
|
|
#include <spells/regioncurse.h>
|
|
|
|
|
|
2010-08-08 10:06:34 +02:00
|
|
|
|
/* kernel includes */
|
2016-11-23 17:36:39 +01:00
|
|
|
|
#include "curse.h"
|
2010-08-08 10:06:34 +02:00
|
|
|
|
#include "item.h"
|
|
|
|
|
#include "unit.h"
|
|
|
|
|
#include "faction.h"
|
2014-06-30 03:10:02 +02:00
|
|
|
|
#include "race.h"
|
2010-08-08 10:06:34 +02:00
|
|
|
|
#include "region.h"
|
|
|
|
|
#include "skill.h"
|
2016-11-23 17:36:39 +01:00
|
|
|
|
#include "terrain.h"
|
2014-12-17 17:22:26 +01:00
|
|
|
|
#include "lighthouse.h"
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
|
|
|
|
/* util includes */
|
|
|
|
|
#include <util/attrib.h>
|
|
|
|
|
#include <util/base36.h>
|
2012-05-18 18:19:46 +02:00
|
|
|
|
#include <util/bsdstring.h>
|
2010-08-08 10:06:34 +02:00
|
|
|
|
#include <util/event.h>
|
|
|
|
|
#include <util/functions.h>
|
2016-04-09 18:22:20 +02:00
|
|
|
|
#include <util/gamedata.h>
|
2010-08-08 10:06:34 +02:00
|
|
|
|
#include <util/language.h>
|
|
|
|
|
#include <util/log.h>
|
|
|
|
|
#include <util/resolve.h>
|
|
|
|
|
#include <util/umlaut.h>
|
|
|
|
|
|
2013-12-31 10:06:28 +01:00
|
|
|
|
#include <storage.h>
|
2017-05-06 15:33:35 +02:00
|
|
|
|
#include <selist.h>
|
|
|
|
|
#include <critbit.h>
|
2013-12-31 10:06:28 +01:00
|
|
|
|
|
2010-08-08 10:06:34 +02:00
|
|
|
|
/* libc includes */
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
|
|
|
|
|
typedef struct building_typelist {
|
2014-12-17 21:31:02 +01:00
|
|
|
|
struct building_typelist *next;
|
|
|
|
|
building_type *type;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
} building_typelist;
|
|
|
|
|
|
2017-01-26 17:41:21 +01:00
|
|
|
|
selist *buildingtypes = NULL;
|
2017-05-06 15:33:35 +02:00
|
|
|
|
static critbit_tree cb_bldgtypes;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2011-03-09 14:44:31 +01:00
|
|
|
|
/* Returns a building type for the (internal) name */
|
2014-06-13 07:14:07 +02:00
|
|
|
|
static building_type *bt_find_i(const char *name)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2017-05-06 15:33:35 +02:00
|
|
|
|
const char *match;
|
|
|
|
|
building_type *btype = NULL;
|
2011-03-09 00:25:51 +01:00
|
|
|
|
|
2017-05-06 15:33:35 +02:00
|
|
|
|
match = cb_find_str(&cb_bldgtypes, name);
|
|
|
|
|
if (match) {
|
|
|
|
|
cb_get_kv(match, &btype, sizeof(btype));
|
2014-12-17 21:31:02 +01:00
|
|
|
|
}
|
2017-05-06 15:33:35 +02:00
|
|
|
|
return btype;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-06-13 07:14:07 +02:00
|
|
|
|
const building_type *bt_find(const char *name)
|
|
|
|
|
{
|
2017-05-22 21:35:25 +02:00
|
|
|
|
building_type *btype = bt_find_i(name);
|
|
|
|
|
if (!btype) {
|
|
|
|
|
log_warning("bt_find: could not find building '%s'\n", name);
|
|
|
|
|
}
|
|
|
|
|
return btype;
|
2014-06-13 07:14:07 +02:00
|
|
|
|
}
|
|
|
|
|
|
2016-09-19 04:04:02 +02:00
|
|
|
|
static int bt_changes = 1;
|
|
|
|
|
|
|
|
|
|
bool bt_changed(int *cache)
|
|
|
|
|
{
|
|
|
|
|
assert(cache);
|
|
|
|
|
if (*cache != bt_changes) {
|
|
|
|
|
*cache = bt_changes;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-06 15:39:09 +02:00
|
|
|
|
static void bt_register(building_type * btype)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2017-05-06 15:33:35 +02:00
|
|
|
|
size_t len;
|
|
|
|
|
char data[64];
|
|
|
|
|
|
|
|
|
|
selist_push(&buildingtypes, (void *)btype);
|
|
|
|
|
len = cb_new_kv(btype->_name, strlen(btype->_name), &btype, sizeof(btype), data);
|
|
|
|
|
assert(len <= sizeof(data));
|
|
|
|
|
cb_insert(&cb_bldgtypes, data, len);
|
2016-09-19 04:04:02 +02:00
|
|
|
|
++bt_changes;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2016-09-19 04:04:02 +02:00
|
|
|
|
static void free_buildingtype(void *ptr) {
|
2015-01-30 20:37:14 +01:00
|
|
|
|
building_type *btype = (building_type *)ptr;
|
2015-10-13 22:56:16 +02:00
|
|
|
|
free_construction(btype->construction);
|
2015-10-14 12:14:33 +02:00
|
|
|
|
free(btype->maintenance);
|
2014-12-30 23:34:24 +01:00
|
|
|
|
free(btype->_name);
|
|
|
|
|
free(btype);
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-14 02:36:05 +02:00
|
|
|
|
void free_buildingtypes(void) {
|
2017-05-06 15:33:35 +02:00
|
|
|
|
cb_clear(&cb_bldgtypes);
|
2017-01-26 17:41:21 +01:00
|
|
|
|
selist_foreach(buildingtypes, free_buildingtype);
|
|
|
|
|
selist_free(buildingtypes);
|
2014-06-14 02:36:05 +02:00
|
|
|
|
buildingtypes = 0;
|
2016-09-19 04:04:02 +02:00
|
|
|
|
++bt_changes;
|
2014-06-14 02:36:05 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-06-08 07:17:48 +02:00
|
|
|
|
building_type *bt_get_or_create(const char *name)
|
|
|
|
|
{
|
2017-03-17 22:31:59 +01:00
|
|
|
|
assert(name && name[0]);
|
2014-12-17 21:31:02 +01:00
|
|
|
|
if (name != NULL) {
|
|
|
|
|
building_type *btype = bt_find_i(name);
|
|
|
|
|
if (btype == NULL) {
|
|
|
|
|
btype = calloc(sizeof(building_type), 1);
|
2017-01-10 16:31:05 +01:00
|
|
|
|
btype->_name = strdup(name);
|
2015-02-02 16:55:18 +01:00
|
|
|
|
btype->auraregen = 1.0;
|
|
|
|
|
btype->maxsize = -1;
|
2015-11-02 14:56:58 +01:00
|
|
|
|
btype->capacity = 1;
|
2015-02-02 16:55:18 +01:00
|
|
|
|
btype->maxcapacity = -1;
|
2014-12-17 21:31:02 +01:00
|
|
|
|
bt_register(btype);
|
|
|
|
|
}
|
|
|
|
|
return btype;
|
2014-06-08 07:17:48 +02:00
|
|
|
|
}
|
2014-12-17 21:31:02 +01:00
|
|
|
|
return NULL;
|
2014-06-08 07:17:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
int buildingcapacity(const building * b)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-12-17 21:31:02 +01:00
|
|
|
|
if (b->type->capacity >= 0) {
|
|
|
|
|
if (b->type->maxcapacity >= 0) {
|
2017-01-10 16:31:05 +01:00
|
|
|
|
return MIN(b->type->maxcapacity, b->size * b->type->capacity);
|
2014-12-17 21:31:02 +01:00
|
|
|
|
}
|
|
|
|
|
return b->size * b->type->capacity;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
2016-08-06 13:52:29 +02:00
|
|
|
|
if (building_finished(b)) {
|
2014-12-17 21:31:02 +01:00
|
|
|
|
if (b->type->maxcapacity >= 0) {
|
|
|
|
|
return b->type->maxcapacity;
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
2014-12-17 21:31:02 +01:00
|
|
|
|
return 0;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
attrib_type at_building_generic_type = {
|
2016-02-09 06:43:19 +01:00
|
|
|
|
"building_generic_type", NULL, NULL, NULL, a_writestring, a_readstring, NULL,
|
2011-03-07 08:02:35 +01:00
|
|
|
|
ATF_UNIQUE
|
2010-08-08 10:06:34 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-04-26 21:44:24 +02:00
|
|
|
|
/* TECH DEBT: simplest thing that works for E3 dwarf/halfling faction rules */
|
|
|
|
|
static int adjust_size(const building *b, int bsize) {
|
|
|
|
|
assert(b);
|
|
|
|
|
if (config_get_int("rules.dwarf_castles", 0)
|
|
|
|
|
&& strcmp(b->type->_name, "castle") == 0) {
|
|
|
|
|
unit *u = building_owner(b);
|
|
|
|
|
if (u && u->faction->race == get_race(RC_HALFLING)) {
|
|
|
|
|
return bsize * 5 / 4;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return bsize;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-09 14:44:31 +01:00
|
|
|
|
/* Returns the (internal) name for a building of given size and type. Especially, returns the correct
|
|
|
|
|
* name if it depends on the size (as for Eressea castles).
|
|
|
|
|
*/
|
2014-06-18 08:10:55 +02:00
|
|
|
|
const char *buildingtype(const building_type * btype, const building * b, int bsize)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2017-04-26 21:44:24 +02:00
|
|
|
|
const construction *con;
|
|
|
|
|
|
2014-06-18 08:10:55 +02:00
|
|
|
|
assert(btype);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-06-18 08:10:55 +02:00
|
|
|
|
if (b && b->attribs) {
|
2016-08-30 10:13:59 +02:00
|
|
|
|
if (is_building_type(btype, "generic")) {
|
2014-06-18 08:10:55 +02:00
|
|
|
|
const attrib *a = a_find(b->attribs, &at_building_generic_type);
|
|
|
|
|
if (a) {
|
2017-04-26 21:44:24 +02:00
|
|
|
|
return (const char *)a->data.v;
|
2014-06-18 08:10:55 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-05-06 15:53:21 +02:00
|
|
|
|
if (btype->construction && btype->construction->name) {
|
2017-04-26 21:44:24 +02:00
|
|
|
|
if (b) {
|
|
|
|
|
bsize = adjust_size(b, bsize);
|
|
|
|
|
}
|
|
|
|
|
for (con = btype->construction; con; con = con->improvement) {
|
|
|
|
|
bsize -= con->maxsize;
|
|
|
|
|
if (!con->improvement || bsize <0) {
|
2017-05-06 15:53:21 +02:00
|
|
|
|
return con->name;
|
2017-04-26 21:44:24 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return btype->_name;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define BMAXHASH 7919
|
|
|
|
|
static building *buildhash[BMAXHASH];
|
2011-03-07 08:02:35 +01:00
|
|
|
|
void bhash(building * b)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-12-17 21:31:02 +01:00
|
|
|
|
building *old = buildhash[b->no % BMAXHASH];
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-12-17 21:31:02 +01:00
|
|
|
|
buildhash[b->no % BMAXHASH] = b;
|
|
|
|
|
b->nexthash = old;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
void bunhash(building * b)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-12-17 21:31:02 +01:00
|
|
|
|
building **show;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-12-17 21:31:02 +01:00
|
|
|
|
for (show = &buildhash[b->no % BMAXHASH]; *show; show = &(*show)->nexthash) {
|
|
|
|
|
if ((*show)->no == b->no)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (*show) {
|
|
|
|
|
assert(*show == b);
|
|
|
|
|
*show = (*show)->nexthash;
|
|
|
|
|
b->nexthash = 0;
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static building *bfindhash(int i)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-12-17 21:31:02 +01:00
|
|
|
|
building *old;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-12-17 21:31:02 +01:00
|
|
|
|
for (old = buildhash[i % BMAXHASH]; old; old = old->nexthash)
|
|
|
|
|
if (old->no == i)
|
|
|
|
|
return old;
|
|
|
|
|
return 0;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
building *findbuilding(int i)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-12-17 21:31:02 +01:00
|
|
|
|
return bfindhash(i);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
/* for finding out what was meant by a particular building string */
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static local_names *bnames;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2011-03-09 14:44:31 +01:00
|
|
|
|
/* Find the building type for a given localized name (as seen by the user). Useful for parsing
|
|
|
|
|
* orders. The inverse of locale_string(lang, btype->_name), sort of. */
|
2011-03-07 08:02:35 +01:00
|
|
|
|
const building_type *findbuildingtype(const char *name,
|
2014-12-17 21:31:02 +01:00
|
|
|
|
const struct locale *lang)
|
|
|
|
|
{
|
|
|
|
|
variant type;
|
|
|
|
|
local_names *bn = bnames;
|
2011-03-09 00:25:51 +01:00
|
|
|
|
|
2014-12-17 21:31:02 +01:00
|
|
|
|
while (bn) {
|
|
|
|
|
if (bn->lang == lang)
|
|
|
|
|
break;
|
|
|
|
|
bn = bn->next;
|
|
|
|
|
}
|
|
|
|
|
if (!bn) {
|
2017-01-26 17:41:21 +01:00
|
|
|
|
selist *ql = buildingtypes;
|
2014-12-17 21:31:02 +01:00
|
|
|
|
int qi;
|
2011-03-09 00:25:51 +01:00
|
|
|
|
|
2014-12-17 21:31:02 +01:00
|
|
|
|
bn = (local_names *)calloc(sizeof(local_names), 1);
|
|
|
|
|
bn->next = bnames;
|
|
|
|
|
bn->lang = lang;
|
2011-03-09 00:25:51 +01:00
|
|
|
|
|
2017-01-26 17:41:21 +01:00
|
|
|
|
for (qi = 0, ql = buildingtypes; ql; selist_advance(&ql, &qi, 1)) {
|
|
|
|
|
building_type *btype = (building_type *)selist_get(ql, qi);
|
2014-12-17 21:31:02 +01:00
|
|
|
|
|
2015-01-08 20:55:29 +01:00
|
|
|
|
const char *n = LOC(lang, btype->_name);
|
2017-02-24 14:29:14 +01:00
|
|
|
|
if (!n) {
|
|
|
|
|
log_error("building type %s has no translation in %s",
|
|
|
|
|
btype->_name, locale_name(lang));
|
|
|
|
|
} else {
|
|
|
|
|
type.v = (void *)btype;
|
|
|
|
|
addtoken((struct tnode **)&bn->names, n, type);
|
|
|
|
|
}
|
2014-12-17 21:31:02 +01:00
|
|
|
|
}
|
|
|
|
|
bnames = bn;
|
2011-03-07 08:02:35 +01:00
|
|
|
|
}
|
2014-12-17 21:31:02 +01:00
|
|
|
|
if (findtoken(bn->names, name, &type) == E_TOK_NOMATCH)
|
|
|
|
|
return NULL;
|
|
|
|
|
return (const building_type *)type.v;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-01-25 18:17:19 +01:00
|
|
|
|
int cmp_castle_size(const building * b, const building * a)
|
|
|
|
|
{
|
2017-02-22 19:38:46 +01:00
|
|
|
|
if (!b || !(b->type->flags & BTF_FORTIFICATION) || !building_owner(b)) {
|
2017-01-25 18:17:19 +01:00
|
|
|
|
return -1;
|
|
|
|
|
}
|
2017-02-22 19:38:46 +01:00
|
|
|
|
if (!a || !(a->type->flags & BTF_FORTIFICATION) || !building_owner(a)) {
|
2017-01-25 18:17:19 +01:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
return b->size - a->size;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-22 19:38:46 +01:00
|
|
|
|
static const int castle_bonus[6] = { 0, 1, 3, 5, 8, 12 };
|
|
|
|
|
static const int watch_bonus[3] = { 0, 1, 2 };
|
2015-01-30 20:37:14 +01:00
|
|
|
|
|
2017-02-22 19:38:46 +01:00
|
|
|
|
int building_protection(const building_type * btype, int stage)
|
|
|
|
|
{
|
2017-07-17 13:37:40 +02:00
|
|
|
|
assert(btype->flags & BTF_FORTIFICATION);
|
2017-02-22 19:38:46 +01:00
|
|
|
|
if (btype->maxsize < 0) {
|
|
|
|
|
return castle_bonus[MIN(stage, 5)];
|
2015-01-09 15:53:14 +01:00
|
|
|
|
}
|
2017-02-22 19:38:46 +01:00
|
|
|
|
return watch_bonus[MIN(stage, 2)];
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
void write_building_reference(const struct building *b, struct storage *store)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-12-17 21:31:02 +01:00
|
|
|
|
WRITE_INT(store, (b && b->region) ? b->no : 0);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-09-21 16:26:53 +02:00
|
|
|
|
void resolve_building(building *b)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2017-09-21 16:26:53 +02:00
|
|
|
|
resolve(RESOLVE_BUILDING | b->no, b);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-09-22 16:39:46 +02:00
|
|
|
|
int read_building_reference(gamedata * data, building **bp, resolve_fun fun)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2017-09-21 16:26:53 +02:00
|
|
|
|
int id;
|
|
|
|
|
READ_INT(data->store, &id);
|
|
|
|
|
if (id > 0) {
|
|
|
|
|
*bp = findbuilding(id);
|
|
|
|
|
if (*bp == NULL) {
|
|
|
|
|
*bp = NULL;
|
2017-09-22 16:39:46 +02:00
|
|
|
|
ur_add(RESOLVE_BUILDING | id, (void**)bp, fun);
|
2017-09-21 16:26:53 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
*bp = NULL;
|
|
|
|
|
}
|
|
|
|
|
return id;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
building *new_building(const struct building_type * btype, region * r,
|
2014-12-17 21:31:02 +01:00
|
|
|
|
const struct locale * lang)
|
|
|
|
|
{
|
|
|
|
|
building **bptr = &r->buildings;
|
|
|
|
|
building *b = (building *)calloc(1, sizeof(building));
|
|
|
|
|
const char *bname = 0;
|
|
|
|
|
char buffer[32];
|
|
|
|
|
|
|
|
|
|
b->no = newcontainerid();
|
|
|
|
|
bhash(b);
|
|
|
|
|
|
|
|
|
|
b->type = btype;
|
|
|
|
|
b->region = r;
|
|
|
|
|
while (*bptr)
|
|
|
|
|
bptr = &(*bptr)->next;
|
|
|
|
|
*bptr = b;
|
|
|
|
|
|
2016-08-30 10:13:59 +02:00
|
|
|
|
update_lighthouse(b);
|
2014-12-17 21:31:02 +01:00
|
|
|
|
if (!bname) {
|
|
|
|
|
bname = LOC(lang, btype->_name);
|
|
|
|
|
}
|
|
|
|
|
if (!bname) {
|
|
|
|
|
bname = LOC(lang, parameters[P_GEBAEUDE]);
|
|
|
|
|
}
|
|
|
|
|
if (!bname) {
|
|
|
|
|
bname = parameters[P_GEBAEUDE];
|
|
|
|
|
}
|
|
|
|
|
assert(bname);
|
2016-11-17 21:31:11 +01:00
|
|
|
|
slprintf(buffer, sizeof(buffer), "%s %s", bname, itoa36(b->no));
|
2017-01-10 16:31:05 +01:00
|
|
|
|
b->name = strdup(bname);
|
2014-12-17 21:31:02 +01:00
|
|
|
|
return b;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
static building *deleted_buildings;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
|
|
|
|
/** remove a building from the region.
|
|
|
|
|
* remove_building lets units leave the building
|
|
|
|
|
*/
|
2011-03-07 08:02:35 +01:00
|
|
|
|
void remove_building(building ** blist, building * b)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-06-18 08:10:55 +02:00
|
|
|
|
unit *u;
|
|
|
|
|
const struct building_type *bt_caravan, *bt_dam, *bt_tunnel;
|
|
|
|
|
|
|
|
|
|
assert(bfindhash(b->no));
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
|
|
|
|
bt_caravan = bt_find("caravan");
|
|
|
|
|
bt_dam = bt_find("dam");
|
|
|
|
|
bt_tunnel = bt_find("tunnel");
|
|
|
|
|
|
2014-06-18 08:10:55 +02:00
|
|
|
|
handle_event(b->attribs, "destroy", b);
|
|
|
|
|
for (u = b->region->units; u; u = u->next) {
|
|
|
|
|
if (u->building == b) leave(u, true);
|
|
|
|
|
}
|
2011-03-07 08:02:35 +01:00
|
|
|
|
|
2014-06-18 08:10:55 +02:00
|
|
|
|
b->size = 0;
|
|
|
|
|
update_lighthouse(b);
|
|
|
|
|
bunhash(b);
|
2011-03-07 08:02:35 +01:00
|
|
|
|
|
2016-11-23 17:36:39 +01:00
|
|
|
|
/* Falls Karawanserei, Damm oder Tunnel einst<73>rzen, wird die schon
|
2017-02-18 21:15:14 +01:00
|
|
|
|
* gebaute Strasse zur Haelfte vernichtet */
|
|
|
|
|
/* TODO: caravan, tunnel, dam modularization ? is_building_type ? */
|
2014-06-18 08:10:55 +02:00
|
|
|
|
if (b->type == bt_caravan || b->type == bt_dam || b->type == bt_tunnel) {
|
|
|
|
|
region *r = b->region;
|
|
|
|
|
int d;
|
|
|
|
|
for (d = 0; d != MAXDIRECTIONS; ++d) {
|
|
|
|
|
direction_t dir = (direction_t)d;
|
|
|
|
|
if (rroad(r, dir) > 0) {
|
|
|
|
|
rsetroad(r, dir, rroad(r, dir) / 2);
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-05-19 08:20:38 +02:00
|
|
|
|
}
|
2014-12-17 21:31:02 +01:00
|
|
|
|
|
2014-06-18 08:10:55 +02:00
|
|
|
|
/* Stattdessen nur aus Liste entfernen, aber im Speicher halten. */
|
|
|
|
|
while (*blist && *blist != b) {
|
|
|
|
|
blist = &(*blist)->next;
|
|
|
|
|
}
|
|
|
|
|
*blist = b->next;
|
|
|
|
|
b->region = NULL;
|
|
|
|
|
b->next = deleted_buildings;
|
|
|
|
|
deleted_buildings = b;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
void free_building(building * b)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-12-17 21:31:02 +01:00
|
|
|
|
while (b->attribs)
|
|
|
|
|
a_remove(&b->attribs, b->attribs);
|
|
|
|
|
free(b->name);
|
|
|
|
|
free(b->display);
|
|
|
|
|
free(b);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
void free_buildings(void)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-12-17 21:31:02 +01:00
|
|
|
|
while (deleted_buildings) {
|
|
|
|
|
building *b = deleted_buildings;
|
|
|
|
|
deleted_buildings = b->next;
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extern struct attrib_type at_icastle;
|
|
|
|
|
|
|
|
|
|
/** returns the building's build stage (NOT size in people).
|
|
|
|
|
* only makes sense for castles or similar buildings with multiple
|
|
|
|
|
* stages */
|
2012-05-17 09:13:30 +02:00
|
|
|
|
int buildingeffsize(const building * b, int img)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-12-17 21:31:02 +01:00
|
|
|
|
const struct building_type *btype = NULL;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-12-17 21:31:02 +01:00
|
|
|
|
if (b == NULL)
|
|
|
|
|
return 0;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-12-17 21:31:02 +01:00
|
|
|
|
btype = b->type;
|
|
|
|
|
if (img) {
|
|
|
|
|
const attrib *a = a_find(b->attribs, &at_icastle);
|
|
|
|
|
if (a) {
|
|
|
|
|
btype = (const struct building_type *)a->data.v;
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
2014-12-17 21:31:02 +01:00
|
|
|
|
return bt_effsize(btype, b, b->size);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int bt_effsize(const building_type * btype, const building * b, int bsize)
|
|
|
|
|
{
|
2017-04-26 21:44:24 +02:00
|
|
|
|
int n = 0;
|
2014-12-17 21:31:02 +01:00
|
|
|
|
const construction *cons = btype->construction;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2017-04-26 21:44:24 +02:00
|
|
|
|
if (b) {
|
|
|
|
|
bsize = adjust_size(b, bsize);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-04-29 19:21:48 +02:00
|
|
|
|
if (!cons) {
|
2014-12-17 21:31:02 +01:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2017-04-26 21:44:24 +02:00
|
|
|
|
while (cons && cons->maxsize != -1 && bsize >= cons->maxsize) {
|
|
|
|
|
bsize -= cons->maxsize;
|
2014-12-17 21:31:02 +01:00
|
|
|
|
cons = cons->improvement;
|
|
|
|
|
++n;
|
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-12-17 21:31:02 +01:00
|
|
|
|
return n;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
const char *write_buildingname(const building * b, char *ibuf, size_t size)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-12-17 21:31:02 +01:00
|
|
|
|
slprintf(ibuf, size, "%s (%s)", b->name, itoa36(b->no));
|
|
|
|
|
return ibuf;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
const char *buildingname(const building * b)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-12-17 21:31:02 +01:00
|
|
|
|
typedef char name[OBJECTIDSIZE + 1];
|
|
|
|
|
static name idbuf[8];
|
|
|
|
|
static int nextbuf = 0;
|
|
|
|
|
char *ibuf = idbuf[(++nextbuf) % 8];
|
|
|
|
|
return write_buildingname(b, ibuf, sizeof(name));
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2012-05-26 19:43:05 +02:00
|
|
|
|
void building_set_owner(struct unit * owner)
|
2012-05-17 21:23:25 +02:00
|
|
|
|
{
|
2014-12-17 21:31:02 +01:00
|
|
|
|
assert(owner && owner->building);
|
|
|
|
|
owner->building->_owner = owner;
|
2012-05-17 21:23:25 +02:00
|
|
|
|
}
|
|
|
|
|
|
2012-05-19 08:20:38 +02:00
|
|
|
|
static unit *building_owner_ex(const building * bld, const struct faction * last_owner)
|
2012-05-19 06:26:41 +02:00
|
|
|
|
{
|
2014-12-17 21:31:02 +01:00
|
|
|
|
unit *u, *heir = 0;
|
2016-11-23 17:36:39 +01:00
|
|
|
|
/* Eigent<6E>mer tot oder kein Eigent<6E>mer vorhanden. Erste lebende Einheit
|
2014-12-17 21:31:02 +01:00
|
|
|
|
* nehmen. */
|
|
|
|
|
for (u = bld->region->units; u; u = u->next) {
|
|
|
|
|
if (u->building == bld) {
|
|
|
|
|
if (u->number > 0) {
|
|
|
|
|
if (heir && last_owner && heir->faction != last_owner && u->faction == last_owner) {
|
|
|
|
|
heir = u;
|
|
|
|
|
break; /* we found someone from the same faction who is not dead. let's take this guy */
|
|
|
|
|
}
|
|
|
|
|
else if (!heir) {
|
|
|
|
|
heir = u; /* you'll do in an emergency */
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-05-18 00:23:15 +02:00
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
2015-11-22 12:20:33 +01:00
|
|
|
|
if (!heir && config_token("rules.region_owner_pay_building", bld->type->_name)) {
|
2014-08-08 17:15:12 +02:00
|
|
|
|
if (rule_region_owners()) {
|
2017-04-28 21:29:42 +02:00
|
|
|
|
u = building_owner(largestbuilding(bld->region, cmp_taxes, false));
|
2014-08-08 17:15:12 +02:00
|
|
|
|
}
|
|
|
|
|
else {
|
2017-04-28 21:29:42 +02:00
|
|
|
|
u = building_owner(largestbuilding(bld->region, cmp_wage, false));
|
2014-08-08 17:15:12 +02:00
|
|
|
|
}
|
2014-08-08 13:29:26 +02:00
|
|
|
|
if (u) {
|
|
|
|
|
heir = u;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return heir;
|
2012-05-19 06:26:41 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unit *building_owner(const building * bld)
|
|
|
|
|
{
|
2017-02-18 21:15:14 +01:00
|
|
|
|
unit *owner;
|
2014-12-17 21:31:02 +01:00
|
|
|
|
if (!bld) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2017-02-18 21:15:14 +01:00
|
|
|
|
owner = bld->_owner;
|
2014-12-17 21:31:02 +01:00
|
|
|
|
if (!owner || (owner->building != bld || owner->number <= 0)) {
|
|
|
|
|
unit * heir = building_owner_ex(bld, owner ? owner->faction : 0);
|
|
|
|
|
return (heir && heir->number > 0) ? heir : 0;
|
|
|
|
|
}
|
|
|
|
|
return owner;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2012-05-19 06:26:41 +02:00
|
|
|
|
void building_update_owner(building * bld) {
|
2014-12-17 21:31:02 +01:00
|
|
|
|
unit * owner = bld->_owner;
|
|
|
|
|
bld->_owner = building_owner_ex(bld, owner ? owner->faction : 0);
|
2012-05-19 06:26:41 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
const char *building_getname(const building * self)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-12-17 21:31:02 +01:00
|
|
|
|
return self->name;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
void building_setname(building * self, const char *name)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-12-17 21:31:02 +01:00
|
|
|
|
free(self->name);
|
|
|
|
|
if (name)
|
2017-01-10 16:31:05 +01:00
|
|
|
|
self->name = strdup(name);
|
2014-12-17 21:31:02 +01:00
|
|
|
|
else
|
|
|
|
|
self->name = NULL;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
region *building_getregion(const building * b)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-12-17 21:31:02 +01:00
|
|
|
|
return b->region;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2015-11-16 02:13:48 +01:00
|
|
|
|
bool
|
|
|
|
|
buildingtype_exists(const region * r, const building_type * bt, bool working)
|
|
|
|
|
{
|
|
|
|
|
building *b;
|
|
|
|
|
|
|
|
|
|
for (b = rbuildings(r); b; b = b->next) {
|
2016-08-21 20:12:28 +02:00
|
|
|
|
if (b->type == bt && (!working || fval(b, BLD_MAINTAINED)) && building_finished(b)) {
|
2015-11-16 02:13:48 +01:00
|
|
|
|
return true;
|
2016-08-06 13:52:29 +02:00
|
|
|
|
}
|
2015-11-16 02:13:48 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-06 13:52:29 +02:00
|
|
|
|
bool building_finished(const struct building *b) {
|
|
|
|
|
return b->size >= b->type->maxsize;
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-02 14:18:50 +01:00
|
|
|
|
bool building_is_active(const struct building *b) {
|
2016-08-21 20:12:28 +02:00
|
|
|
|
return b && fval(b, BLD_MAINTAINED) && building_finished(b);
|
2015-11-16 02:13:48 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
building *active_building(const unit *u, const struct building_type *btype) {
|
|
|
|
|
if (u->building && u->building->type == btype && building_is_active(u->building)) {
|
|
|
|
|
return inside_building(u);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
2015-11-02 14:18:50 +01:00
|
|
|
|
}
|
|
|
|
|
|
2015-11-16 02:13:48 +01:00
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
|
void building_setregion(building * b, region * r)
|
2010-08-08 10:06:34 +02:00
|
|
|
|
{
|
2014-12-17 21:31:02 +01:00
|
|
|
|
building **blist = &b->region->buildings;
|
|
|
|
|
while (*blist && *blist != b) {
|
|
|
|
|
blist = &(*blist)->next;
|
|
|
|
|
}
|
|
|
|
|
*blist = b->next;
|
|
|
|
|
b->next = NULL;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-12-17 21:31:02 +01:00
|
|
|
|
blist = &r->buildings;
|
|
|
|
|
while (*blist && *blist != b)
|
|
|
|
|
blist = &(*blist)->next;
|
|
|
|
|
*blist = b;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
2014-12-17 21:31:02 +01:00
|
|
|
|
b->region = r;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
}
|
2015-11-12 17:55:39 +01:00
|
|
|
|
|
|
|
|
|
bool in_safe_building(unit *u1, unit *u2) {
|
|
|
|
|
if (u1->building) {
|
|
|
|
|
building * b = inside_building(u1);
|
2015-11-13 00:50:54 +01:00
|
|
|
|
if (b && b->type->flags & BTF_FORTIFICATION) {
|
2015-11-12 17:55:39 +01:00
|
|
|
|
if (!u2->building) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (u2->building != b || b != inside_building(u2)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2016-08-30 10:13:59 +02:00
|
|
|
|
|
|
|
|
|
bool is_building_type(const struct building_type *btype, const char *name) {
|
|
|
|
|
assert(btype);
|
|
|
|
|
return name && strcmp(btype->_name, name)==0;
|
|
|
|
|
}
|
2016-11-23 17:36:39 +01:00
|
|
|
|
|
|
|
|
|
building *largestbuilding(const region * r, cmp_building_cb cmp_gt,
|
|
|
|
|
bool imaginary)
|
|
|
|
|
{
|
2017-04-29 13:37:34 +02:00
|
|
|
|
building *b, *best = NULL;
|
2016-11-23 17:36:39 +01:00
|
|
|
|
|
2017-04-29 13:37:34 +02:00
|
|
|
|
for (b = r->buildings; b; b = b->next) {
|
2016-11-23 17:36:39 +01:00
|
|
|
|
if (cmp_gt(b, best) <= 0)
|
|
|
|
|
continue;
|
|
|
|
|
if (!imaginary) {
|
|
|
|
|
const attrib *a = a_find(b->attribs, &at_icastle);
|
|
|
|
|
if (a)
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
best = b;
|
|
|
|
|
}
|
|
|
|
|
return best;
|
|
|
|
|
}
|
|
|
|
|
/* Lohn bei den einzelnen Burgstufen f<>r Normale Typen, Orks, Bauern,
|
|
|
|
|
* Modifikation f<EFBFBD>r St<EFBFBD>dter. */
|
|
|
|
|
|
|
|
|
|
static const int wagetable[7][4] = {
|
|
|
|
|
{ 10, 10, 11, -7 }, /* Baustelle */
|
|
|
|
|
{ 10, 10, 11, -5 }, /* Handelsposten */
|
|
|
|
|
{ 11, 11, 12, -3 }, /* Befestigung */
|
|
|
|
|
{ 12, 11, 13, -1 }, /* Turm */
|
|
|
|
|
{ 13, 12, 14, 0 }, /* Burg */
|
|
|
|
|
{ 14, 12, 15, 1 }, /* Festung */
|
|
|
|
|
{ 15, 13, 16, 2 } /* Zitadelle */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
default_wage(const region * r, const faction * f, const race * rc, int in_turn)
|
|
|
|
|
{
|
2017-04-28 21:29:42 +02:00
|
|
|
|
building *b = largestbuilding(r, cmp_wage, false);
|
2016-11-23 17:36:39 +01:00
|
|
|
|
int esize = 0;
|
|
|
|
|
double wage;
|
|
|
|
|
|
|
|
|
|
if (b != NULL) {
|
|
|
|
|
/* TODO: this reveals imaginary castles */
|
|
|
|
|
esize = buildingeffsize(b, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (f != NULL) {
|
|
|
|
|
int index = 0;
|
|
|
|
|
if (rc == get_race(RC_ORC) || rc == get_race(RC_SNOTLING)) {
|
|
|
|
|
index = 1;
|
|
|
|
|
}
|
|
|
|
|
wage = wagetable[esize][index];
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (is_mourning(r, in_turn)) {
|
|
|
|
|
wage = 10;
|
|
|
|
|
}
|
|
|
|
|
else if (fval(r->terrain, SEA_REGION)) {
|
|
|
|
|
wage = 11;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
wage = wagetable[esize][2];
|
|
|
|
|
}
|
2017-04-30 21:38:30 +02:00
|
|
|
|
if (r->attribs && rule_blessed_harvest() == HARVEST_WORK) {
|
2016-11-23 17:36:39 +01:00
|
|
|
|
/* E1 rules */
|
2017-08-06 18:52:09 +02:00
|
|
|
|
wage += harvest_effect(r);
|
2016-11-23 17:36:39 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (r->attribs) {
|
|
|
|
|
attrib *a;
|
2017-08-21 19:43:35 +02:00
|
|
|
|
curse *c;
|
|
|
|
|
|
2016-11-23 17:36:39 +01:00
|
|
|
|
/* Godcurse: Income -10 */
|
2017-08-21 19:43:35 +02:00
|
|
|
|
c = get_curse(r->attribs, &ct_godcursezone);
|
|
|
|
|
if (c && curse_active(c)) {
|
2017-01-10 16:31:05 +01:00
|
|
|
|
wage = MAX(0, wage - 10);
|
2016-11-23 17:36:39 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Bei einer D<>rre verdient man nur noch ein Viertel */
|
2017-08-21 19:43:35 +02:00
|
|
|
|
c = get_curse(r->attribs, &ct_drought);
|
|
|
|
|
if (c && curse_active(c)) {
|
|
|
|
|
wage /= curse_geteffect(c);
|
2016-11-23 17:36:39 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
a = a_find(r->attribs, &at_reduceproduction);
|
|
|
|
|
if (a) {
|
|
|
|
|
wage = (wage * a->data.sa[0]) / 100;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return (int)wage;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
minimum_wage(const region * r, const faction * f, const race * rc, int in_turn)
|
|
|
|
|
{
|
|
|
|
|
if (f && rc) {
|
|
|
|
|
return rc->maintenance;
|
|
|
|
|
}
|
|
|
|
|
return default_wage(r, f, rc, in_turn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Gibt Arbeitslohn f<>r entsprechende Rasse zur<75>ck, oder f<>r
|
|
|
|
|
* die Bauern wenn f == NULL. */
|
|
|
|
|
int wage(const region * r, const faction * f, const race * rc, int in_turn)
|
|
|
|
|
{
|
2017-03-16 16:07:52 +01:00
|
|
|
|
static int config;
|
|
|
|
|
static int rule_wage;
|
|
|
|
|
if (config_changed(&config)) {
|
|
|
|
|
rule_wage = config_get_int("rules.wage.function", 1);
|
2016-11-23 17:36:39 +01:00
|
|
|
|
}
|
2017-03-16 16:07:52 +01:00
|
|
|
|
if (rule_wage==0) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (rule_wage==1) {
|
|
|
|
|
return default_wage(r, f, rc, in_turn);
|
|
|
|
|
}
|
|
|
|
|
return minimum_wage(r, f, rc, in_turn);
|
2016-11-23 17:36:39 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int cmp_wage(const struct building *b, const building * a)
|
|
|
|
|
{
|
|
|
|
|
if (is_building_type(b->type, "castle")) {
|
|
|
|
|
if (!a)
|
|
|
|
|
return 1;
|
|
|
|
|
if (b->size > a->size)
|
|
|
|
|
return 1;
|
|
|
|
|
if (b->size == a->size)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool is_owner_building(const struct building * b)
|
|
|
|
|
{
|
|
|
|
|
region *r = b->region;
|
|
|
|
|
if (b->type->taxes && r->land && r->land->ownership) {
|
|
|
|
|
unit *u = building_owner(b);
|
|
|
|
|
return u && u->faction == r->land->ownership->owner;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-29 19:21:48 +02:00
|
|
|
|
int building_taxes(const building *b) {
|
2017-04-27 19:08:10 +02:00
|
|
|
|
assert(b);
|
2017-04-29 19:21:48 +02:00
|
|
|
|
return b->type->taxes;
|
2017-04-27 19:08:10 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-11-23 17:36:39 +01:00
|
|
|
|
int cmp_taxes(const building * b, const building * a)
|
|
|
|
|
{
|
|
|
|
|
faction *f = region_get_owner(b->region);
|
|
|
|
|
if (b->type->taxes) {
|
|
|
|
|
unit *u = building_owner(b);
|
|
|
|
|
if (!u) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
else if (a) {
|
2017-04-29 19:21:48 +02:00
|
|
|
|
int newtaxes = building_taxes(b);
|
|
|
|
|
int oldtaxes = building_taxes(a);
|
2016-11-23 17:36:39 +01:00
|
|
|
|
|
2017-04-28 20:10:20 +02:00
|
|
|
|
if (newtaxes > oldtaxes)
|
2016-11-23 17:36:39 +01:00
|
|
|
|
return -1;
|
2017-04-28 20:10:20 +02:00
|
|
|
|
else if (newtaxes < oldtaxes)
|
2016-11-23 17:36:39 +01:00
|
|
|
|
return 1;
|
|
|
|
|
else if (b->size < a->size)
|
|
|
|
|
return -1;
|
|
|
|
|
else if (b->size > a->size)
|
|
|
|
|
return 1;
|
|
|
|
|
else {
|
|
|
|
|
if (u && u->faction == f) {
|
|
|
|
|
u = building_owner(a);
|
2017-04-28 21:29:42 +02:00
|
|
|
|
if (u && u->faction == f) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2016-11-23 17:36:39 +01:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-04-28 21:29:42 +02:00
|
|
|
|
return 0;
|
2016-11-23 17:36:39 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int cmp_current_owner(const building * b, const building * a)
|
|
|
|
|
{
|
|
|
|
|
faction *f = region_get_owner(b->region);
|
|
|
|
|
|
|
|
|
|
assert(rule_region_owners());
|
|
|
|
|
if (f && b->type->taxes) {
|
|
|
|
|
unit *u = building_owner(b);
|
|
|
|
|
if (!u || u->faction != f)
|
|
|
|
|
return -1;
|
|
|
|
|
if (a) {
|
2017-04-29 19:21:48 +02:00
|
|
|
|
int newtaxes = building_taxes(b);
|
|
|
|
|
int oldtaxes = building_taxes(a);
|
2016-11-23 17:36:39 +01:00
|
|
|
|
|
2017-04-28 21:29:42 +02:00
|
|
|
|
if (newtaxes > oldtaxes) {
|
2016-11-23 17:36:39 +01:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
2017-04-28 21:29:42 +02:00
|
|
|
|
if (newtaxes < oldtaxes) {
|
2016-11-23 17:36:39 +01:00
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
return (b->size - a->size);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-04-28 21:29:42 +02:00
|
|
|
|
return 0;
|
2016-11-23 17:36:39 +01:00
|
|
|
|
}
|