#ifndef H_KRNL_RACE_H
#define H_KRNL_RACE_H
#include <stddef.h>
#include "magic.h"              /* wegen MAXMAGIETYP */
#include "skill.h"

#ifdef __cplusplus
extern "C" {
#endif

#define AT_NONE 0
#define AT_STANDARD	1
#define AT_DRAIN_EXP 2
#define AT_DRAIN_ST 3
#define AT_NATURAL 4
#define AT_DAZZLE 5
#define AT_SPELL 6
#define AT_COMBATSPELL 7
#define AT_STRUCTURAL 8

#define GOLEM_IRON   4          /* Anzahl Eisen in einem Eisengolem */
#define GOLEM_STONE  4          /* Anzahl Steine in einem Steingolem */

#define RACESPOILCHANCE 5       /* Chance auf rassentypische Beute */

#define RACE_ATTACKS 10         /* maximum number of attacks */

    struct param;
    struct spell;
    struct spellref;
    struct locale;
    struct rcoption;
    struct item_type;

    typedef enum {
        RC_DWARF,                     /* 0 - Zwerg */
        RC_ELF,
        RC_GOBLIN,
        RC_HUMAN,
        RC_TROLL,
        RC_DAEMON,
        RC_INSECT,
        RC_HALFLING,
        RC_CAT,
        RC_AQUARIAN,
        RC_ORC,
        /* last of the addplayer races */

        RC_SNOTLING,
        RC_UNDEAD,

        RC_FIREDRAGON,
        RC_DRAGON,
        RC_WYRM,
        RC_TREEMAN,
        RC_BIRTHDAYDRAGON,
        RC_DRACOID,

        RC_IRONGOLEM,
        RC_STONEGOLEM,
        RC_SHADOW,
        RC_SHADOWLORD,
        RC_IRONKEEPER,
        RC_ALP,
        RC_TOAD,
        RC_HIRNTOETER,
        RC_PEASANT,
        RC_WOLF,

        RC_SONGDRAGON,

        RC_SEASERPENT,
        RC_SHADOWKNIGHT,

        RC_SKELETON,
        RC_SKELETON_LORD,
        RC_ZOMBIE,
        RC_ZOMBIE_LORD,
        RC_GHOUL,
        RC_GHOUL_LORD,
        RC_TEMPLATE,
        RC_CLONE,
        MAXRACES,
        NORACE = -1
    } race_t;

#define MAX_START_RACE RC_ORC

    extern int num_races;
    extern const char *racenames[MAXRACES];

    typedef struct att {
        int type;
        union {
            char *dice;
            struct spellref *sp;
        } data;
        int flags;
        int level;
    } att;

    typedef void (*race_func) (struct unit *);

    typedef struct race {
        char *_name;
        variant magres;
        int healing;
        int maxaura;            /* Faktor auf Maximale Aura */
        double regaura;            /* Faktor auf Regeneration */
        double recruit_multi;      /* Faktor fuer Bauernverbrauch */
        int index;
        int recruitcost;
        int maintenance;
        int splitsize;
        int weight;
        int capacity;
        int income;
        double speed;
        int hitpoints;
        char *def_damage;
        int armor;
        int at_default;             /* Angriffsskill Unbewaffnet (default: -2) */
        int df_default;             /* Verteidigungsskill Unbewaffnet (default: -2) */
        int at_bonus;               /* Veraendert den Angriffsskill (default: 0) */
        int df_bonus;               /* Veraendert den Verteidigungskill (default: 0) */
        signed char *study_speed;   /* study-speed-bonus in points/turn (0=30 Tage) */
        int flags;
        int battle_flags;
        int ec_flags;
        int mask_item;
        struct att attack[RACE_ATTACKS];
        signed char bonus[MAXSKILLS];

        race_func name_unit;
        race_func age_unit;

        struct rcoption *options; /* rarely used properties */

        const struct race *familiars[MAXMAGIETYP];
        struct race *next;
    } race;

    typedef struct race_list {
        struct race_list *next;
        const struct race *data;
    } race_list;

    void racelist_clear(struct race_list **rl);
    void racelist_insert(struct race_list **rl, const struct race *r);

    const struct race *findrace(const char *, const struct locale *);

    struct race_list *get_familiarraces(void);
    struct race *races;
    const struct race *get_race(race_t rt);
    /** TODO: compatibility hacks: **/
    race_t old_race(const struct race *);

    race *rc_create(const char *zName);
    race *rc_get_or_create(const char *name);
    bool rc_changed(int *cache);
    const race *rc_find(const char *);
    void free_races(void);

    bool rc_can_use(const struct race *rc, const struct item_type *itype);

    typedef enum name_t { NAME_SINGULAR, NAME_PLURAL, NAME_DEFINITIVE, NAME_CATEGORY } name_t;
    const char * rc_name_s(const race *rc, name_t n);
    const char * rc_key(const char *rcname, name_t n, char *name, size_t size);
    const char * rc_name(const race *rc, name_t n, char *name, size_t size);

    void rc_set_param(struct race *rc, const char *key, const char *value);

    int rc_luxury_trade(const struct race *rc);
    int rc_herb_trade(const struct race *rc);
    variant rc_magres(const struct race *rc);
    double rc_maxaura(const struct race *rc);
    int rc_armor_bonus(const struct race *rc);
    int rc_scare(const struct race *rc);
    const char * rc_hungerdamage(const race *rc);
    const race *rc_otherrace(const race *rc);

#define MIGRANTS_NONE 0
#define MIGRANTS_LOG10 1
    int rc_migrants_formula(const race *rc);
    
    int rc_mask(const race *rc);
    int rc_get_mask(char *list);

    /* Flags. Do not reorder these without changing json_race() in jsonconf.c */
#define RCF_PLAYABLE       (1<<0)   /* cannot be the race for a player faction (and other limits?) */
#define RCF_KILLPEASANTS   (1<<1)   /* a monster that eats peasants */
#define RCF_SCAREPEASANTS  (1<<2)   /* a monster that scares peasants out of the hex */
#define RCF_NOSTEAL        (1<<3)   /* this race has high stealth, but is not allowed to steal */
#define RCF_MOVERANDOM     (1<<4)
#define RCF_CANNOTMOVE     (1<<5)
#define RCF_AI_LEARN       (1<<6)       /* Lernt automatisch wenn struct faction == 0 */
#define RCF_FLY            (1<<7)       /* kann fliegen */
#define RCF_SWIM           (1<<8)       /* kann schwimmen */
#define RCF_WALK           (1<<9)       /* kann ueber Land gehen */
#define RCF_NOLEARN        (1<<10)      /* kann nicht normal lernen */
#define RCF_NOTEACH        (1<<11)      /* kann nicht lehren */
#define RCF_HORSE          (1<<12)      /* Einheit ist Pferd, sozusagen */
#define RCF_DESERT         (1<<13)      /* 5% Chance, das Einheit desertiert */
#define RCF_ILLUSIONARY    (1<<14)      /* (Illusion & Spell) Does not drop items. */
#define RCF_ABSORBPEASANTS (1<<15)      /* Toetet und absorbiert Bauern */
#define RCF_NOHEAL         (1<<16)      /* Einheit kann nicht geheilt werden */
#define RCF_NOWEAPONS      (1<<17)      /* Einheit kann keine Waffen benutzen */
#define RCF_SHAPESHIFT     (1<<18)      /* Kann TARNE RASSE benutzen. */
#define RCF_SHAPESHIFTANY  (1<<19)      /* Kann TARNE RASSE "string" benutzen. */
#define RCF_UNDEAD         (1<<20)      /* Undead. */
#define RCF_DRAGON         (1<<21)      /* Drachenart (fuer Zauber) */
#define RCF_COASTAL        (1<<22)      /* kann in Landregionen an der Kueste sein */
#define RCF_UNARMEDGUARD   (1<<23)      /* kann ohne Waffen bewachen */
#define RCF_CANSAIL        (1<<24)      /* Einheit darf Schiffe betreten */
#define RCF_INVISIBLE      (1<<25)      /* not visible in any report */
#define RCF_SHIPSPEED      (1<<26)      /* race gets +1 on shipspeed */
#define RCF_ATTACK_MOVED   (1<<27)      /* may attack if it has moved */
#define RCF_MIGRANTS       (1<<28)      /* may have migrant units (human bonus) */
#define RCF_FAMILIAR       (1<<29)      /* may be a familiar */

#define RCF_DEFAULT RCF_CANSAIL

    /* Economic flags */
#define ECF_GIVEPERSON     (1<<0)   /* Uebergibt Personen */
#define ECF_GIVEUNIT       (1<<1)   /* Einheiten an andere Partei uebergeben */
#define ECF_GETITEM        (1<<2)   /* nimmt Gegenstaende an */
#define ECF_REC_ETHEREAL   (1<<3)       /* Rekrutiert aus dem Nichts */
#define ECF_REC_UNLIMITED  (1<<4)       /* Rekrutiert ohne Limit */
#define ECF_STONEGOLEM     (1<<5)      /* race gets stonegolem properties */
#define ECF_IRONGOLEM      (1<<6)      /* race gets irongolem properties */

    /* Battle-Flags */
#define BF_EQUIPMENT    (1<<0)  /* Kann Ausruestung benutzen */
#define BF_NOBLOCK      (1<<1)  /* Wird in die Rueckzugsberechnung nicht einbezogen */
#define BF_RES_PIERCE   (1<<2)  /* Halber Schaden durch PIERCE */
#define BF_RES_CUT      (1<<3)  /* Halber Schaden durch CUT */
#define BF_RES_BASH     (1<<4)  /* Halber Schaden durch BASH */
#define BF_INV_NONMAGIC (1<<5)  /* Immun gegen nichtmagischen Schaden */
#define BF_NO_ATTACK    (1<<6)  /* Kann keine ATTACKIERE Befehle ausfuehren */

    const char *racename(const struct locale *lang, const struct unit *u,
        const race * rc);

#define playerrace(rc) ((rc)->flags & RCF_PLAYABLE)
#define dragonrace(rc) ((rc)->flags & RCF_DRAGON)
#define humanoidrace(rc) (((rc)->flags & RCF_UNDEAD) || (rc)==get_race(RC_DRACOID) || playerrace(rc))
#define undeadrace(rc) (((rc)->flags & RCF_UNDEAD) || (rc)==get_race(RC_DRACOID))
#define illusionaryrace(rc) ((rc)->flags & RCF_ILLUSIONARY)

    bool allowed_dragon(const struct region *src,
        const struct region *target);

    bool r_insectstalled(const struct region *r);

    void write_race_reference(const struct race *rc,
        struct storage *store);
    struct race *read_race_reference(struct storage *store);

    const char *raceprefix(const struct unit *u);
    void register_race_function(race_func, const char *);

    void set_study_speed(struct race *rc, skill_t sk, int modifier);
#ifdef __cplusplus
}
#endif
#endif