server/src/kernel/race.c

332 lines
8.6 KiB
C
Raw Normal View History

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>
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 "race.h"
#include "alchemy.h"
#include "build.h"
#include "building.h"
#include "equipment.h"
#include "faction.h"
#include "group.h"
#include "item.h"
#include "names.h"
#include "pathfinder.h"
#include "region.h"
#include "ship.h"
#include "skill.h"
#include "terrain.h"
#include "unit.h"
#include "version.h"
/* util includes */
#include <util/attrib.h>
#include <util/bsdstring.h>
#include <util/functions.h>
#include <util/language.h>
#include <util/log.h>
#include <util/rng.h>
#include <storage.h>
2010-08-08 10:06:34 +02:00
/* attrib includes */
#include <attributes/raceprefix.h>
/* libc includes */
2012-06-04 03:41:07 +02:00
#include <assert.h>
#include <ctype.h>
#include <math.h>
2010-08-08 10:06:34 +02:00
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/** external variables **/
2011-03-07 08:02:35 +01:00
race *races;
2010-08-08 10:06:34 +02:00
int num_races = 0;
2014-06-30 04:04:30 +02:00
static int cache_breaker;
2010-08-08 10:06:34 +02:00
static const char *racenames[MAXRACES] = {
"dwarf", "elf", NULL, "goblin", "human", "troll", "demon", "insect",
"halfling", "cat", "aquarian", "orc", "snotling", "undead", "illusion",
"youngdragon", "dragon", "wyrm", "ent", "catdragon", "dracoid",
"special", "spell", "irongolem", "stonegolem", "shadowdemon",
"shadowmaster", "mountainguard", "alp", "toad", "braineater", "peasant",
"wolf", NULL, NULL, NULL, NULL, "songdragon", NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, "seaserpent",
"shadowknight", "centaur", "skeleton", "skeletonlord", "zombie",
"juju-zombie", "ghoul", "ghast", "museumghost", "gnome", "template",
"clone"
};
2014-06-30 04:04:30 +02:00
static race * race_cache[MAXRACES];
struct race *get_race(race_t rt) {
2014-06-30 04:04:30 +02:00
static int cache = -1;
2014-06-30 04:15:03 +02:00
const char * name;
race * result = 0;
2014-06-30 04:15:03 +02:00
assert(rt < MAXRACES);
name = racenames[rt];
if (!name) {
return 0;
}
2014-06-30 04:04:30 +02:00
if (cache_breaker != cache) {
cache = cache_breaker;
memset(race_cache, 0, sizeof(race_cache));
2014-06-30 04:15:03 +02:00
return race_cache[rt] = rc_get_or_create(name);
}
else {
result = race_cache[rt];
2014-06-30 04:04:30 +02:00
if (!result) {
2014-06-30 04:15:03 +02:00
result = race_cache[rt] = rc_get_or_create(name);
2014-06-30 04:04:30 +02:00
}
}
return result;
}
2011-03-07 08:02:35 +01:00
race_list *get_familiarraces(void)
2010-08-08 10:06:34 +02:00
{
static int init = 0;
static race_list *familiarraces;
if (!init) {
race *rc = races;
for (; rc != NULL; rc = rc->next) {
if (rc->init_familiar != NULL) {
racelist_insert(&familiarraces, rc);
}
}
init = false;
2010-08-08 10:06:34 +02:00
}
return familiarraces;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
void racelist_clear(struct race_list **rl)
2010-08-08 10:06:34 +02:00
{
while (*rl) {
race_list *rl2 = (*rl)->next;
free(*rl);
*rl = rl2;
}
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
void racelist_insert(struct race_list **rl, const struct race *r)
2010-08-08 10:06:34 +02:00
{
race_list *rl2 = (race_list *)malloc(sizeof(race_list));
2010-08-08 10:06:34 +02:00
rl2->data = r;
rl2->next = *rl;
2010-08-08 10:06:34 +02:00
*rl = rl2;
2010-08-08 10:06:34 +02:00
}
void free_races(void) {
while (races) {
race * rc = races->next;
2016-03-11 11:31:05 +01:00
free_params(&races->parameters);
2014-12-30 01:44:28 +01:00
free(races->_name);
free(races->def_damage);
free(races);
races = rc;
}
num_races = 0;
}
static race *rc_find_i(const char *name)
2010-08-08 10:06:34 +02:00
{
const char *rname = name;
race *rc = races;
2010-08-08 10:06:34 +02:00
while (rc && !strcmp(rname, rc->_name) == 0) {
rc = rc->next;
}
if (!rc && strcmp(name, "uruk") == 0) {
rc = rc_find_i("orc");
log_warning("a reference was made to the retired race '%s', returning '%s'.", name, rc->_name);
}
return rc;
2010-08-08 10:06:34 +02:00
}
const race * rc_find(const char *name) {
return rc_find_i(name);
}
race *rc_get_or_create(const char *zName)
{
2014-06-30 04:15:03 +02:00
race *rc;
int i;
2014-06-30 04:15:03 +02:00
assert(zName);
rc = rc_find_i(zName);
if (!rc) {
rc = (race *)calloc(sizeof(race), 1);
rc->hitpoints = 1;
rc->weight = PERSON_WEIGHT;
rc->capacity = 540;
rc->recruit_multi = 1.0F;
rc->regaura = 1.0F;
rc->speed = 1.0F;
rc->battle_flags = 0;
if (strchr(zName, ' ') != NULL) {
log_error("race '%s' has an invalid name. remove spaces\n", zName);
assert(strchr(zName, ' ') == NULL);
}
rc->_name = _strdup(zName);
rc->precombatspell = NULL;
rc->attack[0].type = AT_COMBATSPELL;
for (i = 1; i < RACE_ATTACKS; ++i)
rc->attack[i].type = AT_NONE;
rc->index = num_races++;
2014-06-30 04:04:30 +02:00
++cache_breaker;
rc->next = races;
return races = rc;
}
return rc;
}
2010-08-08 10:06:34 +02:00
/** dragon movement **/
bool allowed_dragon(const region * src, const region * target)
2010-08-08 10:06:34 +02:00
{
if (fval(src->terrain, ARCTIC_REGION) && fval(target->terrain, SEA_REGION))
return false;
return allowed_fly(src, target);
2010-08-08 10:06:34 +02:00
}
bool r_insectstalled(const region * r)
2010-08-08 10:06:34 +02:00
{
return fval(r->terrain, ARCTIC_REGION);
2010-08-08 10:06:34 +02:00
}
const char* rc_name(const race * rc, name_t n, char *name, size_t size) {
const char * postfix = 0;
if (!rc) {
return NULL;
}
switch (n) {
case NAME_SINGULAR: postfix = ""; break;
case NAME_PLURAL: postfix = "_p"; break;
case NAME_DEFINITIVE: postfix = "_d"; break;
case NAME_CATEGORY: postfix = "_x"; break;
default: assert(!"invalid name_t enum in rc_name_s");
}
if (postfix) {
_snprintf(name, size, "race::%s%s", rc->_name, postfix);
return name;
}
return NULL;
2010-08-08 10:06:34 +02:00
}
const char *rc_name_s(const race * rc, name_t n)
{
static char name[64]; // FIXME: static return value
return rc_name(rc, n, name, sizeof(name));
}
2011-03-07 08:02:35 +01:00
const char *raceprefix(const unit * u)
2010-08-08 10:06:34 +02:00
{
attrib *asource = u->faction->attribs;
if (fval(u, UFL_GROUP)) {
attrib *agroup = a_find(u->attribs, &at_group);
if (agroup != NULL)
asource = ((const group *)(agroup->data.v))->attribs;
}
return get_prefix(asource);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
const char *racename(const struct locale *loc, const unit * u, const race * rc)
2010-08-08 10:06:34 +02:00
{
const char *str, *prefix = raceprefix(u);
if (prefix != NULL) {
static char lbuf[80]; // FIXME: static return value
char *bufp = lbuf;
size_t size = sizeof(lbuf) - 1;
int ch, bytes;
bytes = (int)strlcpy(bufp, LOC(loc, mkname("prefix", prefix)), size);
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();
bytes = (int)strlcpy(bufp, LOC(loc, rc_name_s(rc, u->number != 1)), size);
assert(~bufp[0] & 0x80 || !"unicode/not implemented");
ch = tolower(*(unsigned char *)bufp);
bufp[0] = (char)ch;
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();
*bufp = 0;
return lbuf;
}
str = LOC(loc, rc_name_s(rc, (u->number == 1) ? NAME_SINGULAR : NAME_PLURAL));
return str ? str : rc->_name;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
void write_race_reference(const race * rc, struct storage *store)
2010-08-08 10:06:34 +02:00
{
WRITE_TOK(store, rc ? rc->_name : "none");
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
variant read_race_reference(struct storage *store)
2010-08-08 10:06:34 +02:00
{
variant result;
char zName[20];
READ_TOK(store, zName, sizeof(zName));
2010-08-08 10:06:34 +02:00
if (strcmp(zName, "none") == 0) {
result.v = NULL;
return result;
}
else {
result.v = rc_find_i(zName);
}
assert(result.v != NULL);
2010-08-08 10:06:34 +02:00
return result;
}
/** Returns the English name of the race, which is what the database uses.
*/
const char *dbrace(const struct race *rc)
{
static char zText[32]; // FIXME: static return value
char *zPtr = zText;
/* the english names are all in ASCII, so we don't need to worry about UTF8 */
strlcpy(zText, (const char *)LOC(get_locale("en"), rc_name_s(rc, NAME_SINGULAR)), sizeof(zText));
while (*zPtr) {
*zPtr = (char)(toupper(*zPtr));
++zPtr;
}
return zText;
}
void register_race_name_function(race_name_func func, const char *name) {
register_function((pf_generic)func, name);
}
char * race_namegen(const struct race *rc, struct unit *u) {
if (rc->generate_name) {
rc->generate_name(u);
}
return NULL;
}