- recruiting secondary races

- some archetype changes
- new looting rules
This commit is contained in:
Enno Rehling 2009-05-14 20:19:13 +00:00
parent 0181fa3c25
commit 43bf73a01b
22 changed files with 433 additions and 203 deletions

View File

@ -13,6 +13,7 @@
#include <util/umlaut.h>
#include <util/language.h>
#include <util/xml.h>
#include <util/functions.h>
/* libxml includes */
#include <libxml/tree.h>
@ -83,6 +84,7 @@ parse_archetypes(xmlDocPtr doc)
int i;
for (i=0;i!=nodes->nodeNr;++i) {
xmlNodePtr node = nodes->nodeTab[i];
xmlNodePtr child;
archetype * arch = calloc(1, sizeof(archetype));
xmlXPathObjectPtr sub;
@ -109,6 +111,18 @@ parse_archetypes(xmlDocPtr doc)
arch->size = xml_ivalue(node, "cost", 0);
for (child=node->children;child;child=child->next) {
if (strcmp((const char *)child->name, "function")==0) {
xmlChar * propName = xmlGetProp(child, BAD_CAST "name");
xmlChar * propValue = xmlGetProp(child, BAD_CAST "value");
if (strcmp((const char *)propName, "create")) {
pf_generic foo = get_function((const char *)propValue);
arch->exec = (archetype_function)foo;
}
xmlFree(propValue);
xmlFree(propName);
}
}
xpath->node = node;
sub = xmlXPathEvalExpression(BAD_CAST "allow|deny", xpath);
if (sub->nodesetval && sub->nodesetval->nodeNr) {

View File

@ -23,6 +23,8 @@ extern "C" {
char * value;
} rule;
typedef int (*archetype_function)(struct unit * u, const struct archetype *, int);
typedef struct archetype {
struct archetype * next;
char * name[2];
@ -31,6 +33,7 @@ extern "C" {
struct equipment * equip;
struct construction * ctype;
struct rule * rules;
archetype_function exec;
} archetype;
extern const struct archetype * find_archetype(const char * s, const struct locale * lang);

View File

@ -1109,7 +1109,7 @@ cr_output_region(FILE * F, report_context * ctx, seen_region * sr)
if (sr->mode!=see_unit) fprintf(F, "\"%s\";visibility\n", visibility[sr->mode]);
{
faction * owner = get_region_owner(r);
faction * owner = region_get_owner(r);
if (owner) {
fprintf(F, "%d;owner\n", owner->no);
}

View File

@ -436,6 +436,20 @@ expandrecruit(region * r, request * recruitorders)
assert(recruitorders==NULL);
}
static int
recruit_cost(const faction * f, const race * rc)
{
if (is_monsters(f) || f->race==rc) {
return rc->recruitcost;
} else {
const char * str = get_param(f->race->parameters, "other_race");
if (str && strcmp(rc->_name[0], str)==0) {
return get_param_int(f->race->parameters, "other_cost", -1);
}
}
return -1;
}
static void
recruit(unit * u, struct order * ord, request ** recruitorders)
{
@ -446,16 +460,26 @@ recruit(unit * u, struct order * ord, request ** recruitorders)
int recruitcost;
const faction * f = u->faction;
const struct race * rc = f->race;
const char * str;
init_tokens(ord);
skip_token();
n = getuint();
if (is_monsters(f)) {
/* Monster dürfen REKRUTIERE 15 dracoid machen */
const char * str = getstrtoken();
str = getstrtoken();
if (str) {
/* Monster dürfen REKRUTIERE 15 dracoid machen
* also: secondary race */
rc = findrace(str, f->locale);
if (rc==NULL) rc = f->race;
recruitcost = recruit_cost(f, rc);
if ((u->number!=0 && rc!=f->race) || rc==NULL || recruitcost<0) {
rc = f->race;
recruitcost = recruit_cost(f, f->race);
}
} else {
recruitcost = recruit_cost(f, f->race);
}
assert(recruitcost>=0);
#if GUARD_DISABLES_RECRUIT
/* this is a very special case because the recruiting unit may be empty
@ -507,7 +531,6 @@ recruit(unit * u, struct order * ord, request ** recruitorders)
}
}
recruitcost = rc->recruitcost;
if (recruitcost) {
pl = getplane(r);
if (pl && fval(pl, PFL_NORECRUITS)) {
@ -1066,12 +1089,31 @@ maintain_buildings(region * r, boolean crash)
}
}
#define RECRUIT_MERGE 1
#define RECRUIT_CLASSIC 2
#define RECRUIT_ARCHETYPES 4
static int rules_recruit = -1;
static int
recruit_archetype(unit * u, order * ord)
{
boolean merge = (u->number>0);
int want;
const char * s;
if (rules_recruit<0) {
rules_recruit = 0;
if (get_param_int(global.parameters, "recruit.allow_merge", 1)) {
rules_recruit |= RECRUIT_MERGE;
}
if (get_param_int(global.parameters, "recruit.classic", 1)) {
rules_recruit |= RECRUIT_CLASSIC;
}
if (get_param_int(global.parameters, "recruit.archetype", 0)) {
rules_recruit |= RECRUIT_ARCHETYPES;
}
}
init_tokens(ord);
skip_token();
want = getuint();
@ -1081,7 +1123,7 @@ recruit_archetype(unit * u, order * ord)
const archetype * arch = find_archetype(s, u->faction->locale);
attrib * a = NULL;
if (u->number>0) {
if ((rules_recruit&RECRUIT_MERGE)==0 && merge) {
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unit_must_be_new", ""));
/* TODO: error message */
return 0;
@ -1146,15 +1188,29 @@ recruit_archetype(unit * u, order * ord)
n = build(u, arch->ctype, 0, n);
if (n>0) {
set_number(u, n);
equip_unit(u, arch->equip);
u->hp = n * unit_max_hp(u);
if (arch->size) {
if (a==NULL) a = a_add(&u->building->attribs, a_new(&at_recruit));
a->data.i += n*arch->size;
unit * u2;
if (merge) {
u2 = create_unit(u->region, u->faction, 0, u->race, 0, 0, u);
} else {
u2 = u;
}
if (arch->exec) {
n = arch->exec(u2, arch, n);
}
else {
set_number(u2, n);
equip_unit(u2, arch->equip);
u2->hp = n * unit_max_hp(u2);
if (arch->size) {
if (a==NULL) a = a_add(&u->building->attribs, a_new(&at_recruit));
a->data.i += n*arch->size;
}
}
ADDMSG(&u->faction->msgs, msg_message("recruit_archetype",
"unit amount archetype", u, n, arch->name[n==1]));
if (u!=u2 && u->race==u2->race) {
transfermen(u2, u, u2->number);
}
return n;
} else switch(n) {
case ENOMATERIALS:
@ -1173,24 +1229,20 @@ recruit_archetype(unit * u, order * ord)
return -1;
}
int
recruit_classic(void)
static void recruit_init(void)
{
static int value = -1;
if (value<0) {
value = get_param_int(global.parameters, "recruit.classic", 1);
if (rules_recruit<0) {
rules_recruit = 0;
if (get_param_int(global.parameters, "recruit.allow_merge", 1)) {
rules_recruit |= RECRUIT_MERGE;
}
}
return value;
}
int
recruit_archetypes(void)
int recruit_archetypes(void)
{
static int value = -1;
if (value<0) {
value = get_param_int(global.parameters, "recruit.archetypes", 0);
}
return value;
if (rules_recruit<0) recruit_init();
return (rules_recruit&RECRUIT_ARCHETYPES)!=0;
}
void
@ -1232,22 +1284,23 @@ economics(region *r)
}
/* RECRUIT orders */
if (rules_recruit<0) recruit_init();
for (u = r->units; u; u = u->next) {
order * ord;
if (!recruit_classic()) {
if (u->number>0) continue;
}
for (ord = u->orders; ord; ord = ord->next) {
if (get_keyword(ord) == K_RECRUIT) {
if (recruit_archetypes()) {
if (recruit_archetype(u, ord)>=0) {
continue;
if ((rules_recruit&RECRUIT_MERGE) || u->number==0) {
for (ord = u->orders; ord; ord = ord->next) {
if (get_keyword(ord) == K_RECRUIT) {
if (rules_recruit&RECRUIT_ARCHETYPES) {
if (recruit_archetype(u, ord)>=0) {
continue;
}
}
if (rules_recruit&RECRUIT_CLASSIC) {
recruit(u, ord, &recruitorders);
}
break;
}
if (recruit_classic()) {
recruit(u, ord, &recruitorders);
}
break;
}
}
}
@ -3147,8 +3200,9 @@ peasant_taxes(region * r)
building * b;
int money;
int maxsize;
int morale;
f = get_region_owner(r);
f = region_get_owner(r);
if (f==NULL) return;
money = rmoney(r);
@ -3161,8 +3215,9 @@ peasant_taxes(region * r)
if (u==NULL || u->faction!=f) return;
maxsize = buildingeffsize(b, false);
if (maxsize > r->land->morale) {
maxsize = r->land->morale;
morale = region_get_morale(r);
if (maxsize > morale) {
maxsize = morale;
}
if (maxsize>0) {

View File

@ -54,7 +54,6 @@ void maintain_buildings(struct region * r, boolean crash);
extern void add_spende(struct faction * f1, struct faction * f2, int betrag, struct region * r);
extern int make_cmd(struct unit * u, struct order * ord);
extern void split_allocations(struct region * r);
extern int recruit_classic(void);
extern int recruit_archetypes(void);
#ifdef __cplusplus

View File

@ -187,7 +187,7 @@ get_food(region *r)
{
unit *u;
int peasantfood = rpeasants(r)*10;
faction * owner = get_region_owner(r);
faction * owner = region_get_owner(r);
/* 1. Versorgung von eigenen Einheiten. Das vorhandene Silber
* wird zunächst so auf die Einheiten aufgeteilt, dass idealerweise
@ -2914,9 +2914,16 @@ age_building(building * b)
return b;
}
static void age_region(region * r)
{
a_age(&r->attribs);
handle_event(r->attribs, "timer", r);
}
static void
ageing(void)
{
const building_type * bt_castle = bt_find("castle");
faction *f;
region *r;
@ -2960,9 +2967,9 @@ ageing(void)
building ** bp;
unit ** up;
ship ** sp;
building * blargest = NULL;
a_age(&r->attribs);
handle_event(r->attribs, "timer", r);
age_region(r);
/* Einheiten */
for (up=&r->units;*up;) {
@ -2985,7 +2992,24 @@ ageing(void)
building * b = *bp;
b = age_building(b);
if (b==*bp) bp = &(*bp)->next;
if (b==*bp) {
if (b->type==bt_castle) {
if (blargest==NULL || b->size>blargest->size) {
blargest = b;
}
}
bp = &(*bp)->next;
}
if (blargest) {
/* region owners update? */
faction * f = region_get_owner(r);
unit * u = buildingowner(r, blargest);
if (u==NULL) {
region_set_owner(r, NULL, turn);
} else if (u->faction!=f) {
region_set_owner(r, f, turn);
}
}
}
}
}

View File

@ -996,7 +996,7 @@ describe(FILE * F, const seen_region * sr, faction * f)
}
{
const faction * owner = get_region_owner(r);
const faction * owner = region_get_owner(r);
if (owner!=NULL) {
bytes = snprintf(bufp, size, " Die Region ist im Besitz von %s.",
factionname(owner));

View File

@ -117,11 +117,16 @@ const troop no_troop = {0, 0};
static int max_turns = 0;
static int damage_rules = 0;
static int loot_rules = 0;
static int skill_formula = 0;
#define FORMULA_ORIG 0
#define FORMULA_NEW 1
#define LOOT_MONSTERS (1<<0)
#define LOOT_SELF (1<<1) /* code is mutually exclusive with LOOT_OTHERS */
#define LOOT_OTHERS (1<<2)
#define DAMAGE_CRITICAL (1<<0)
#define DAMAGE_MELEE_BONUS (1<<1)
#define DAMAGE_MISSILE_BONUS (1<<2)
@ -132,6 +137,7 @@ static int skill_formula = 0;
static void
static_rules(void)
{
loot_rules = get_param_int(global.parameters, "rules.combat.loot", LOOT_MONSTERS|LOOT_OTHERS);
/* new formula to calculate to-hit-chance */
skill_formula = get_param_int(global.parameters, "rules.combat.skill_formula", FORMULA_ORIG);
/* maximum number of combat turns */
@ -1279,16 +1285,17 @@ count_side(const side * s, const side * vs, int minrow, int maxrow, int select)
* troops that are still alive, not those that are still fighting although
* dead. */
int
count_allies(const side * as, int minrow, int maxrow, int select)
count_allies(const side * as, int minrow, int maxrow, int select, int allytype)
{
battle *b = as->battle;
side *s;
side *ds;
int count = 0;
for (s=b->sides;s!=b->sides+b->nsides;++s) {
if (!helping(as, s)) continue;
count += count_side(s, NULL, minrow, maxrow, select);
if (count>0 && (select&SELECT_FIND)) break;
for (ds=b->sides;ds!=b->sides+b->nsides;++ds) {
if ((allytype==ALLY_ANY && helping(as, ds)) || (allytype==ALLY_SELF && as->faction==ds->faction)) {
count += count_side(ds, NULL, minrow, maxrow, select);
if (count>0 && (select&SELECT_FIND)) break;
}
}
return count;
}
@ -1933,12 +1940,14 @@ attacks_per_round(troop t)
return t.fighter->person[t.index].speed;
}
#define HERO_SPEED 10
static void
make_heroes(battle * b)
{
side * s;
static int hero_speed = 0;
if (hero_speed==0) {
hero_speed = get_param_int(global.parameters, "rules.combat.herospeed", 10);
}
for (s=b->sides;s!=b->sides+b->nsides;++s) {
fighter * fig;
for (fig=s->fighters;fig;fig=fig->next) {
@ -1947,7 +1956,7 @@ make_heroes(battle * b)
int i;
assert(playerrace(u->race));
for (i=0;i!=u->number;++i) {
fig->person[i].speed += (HERO_SPEED-1);
fig->person[i].speed += (hero_speed-1);
}
}
}
@ -2252,7 +2261,42 @@ make_side(battle * b, const faction * f, const group * g, unsigned int flags, co
return s1;
}
void
troop
select_ally(fighter * af, int minrow, int maxrow, int allytype)
{
side *as = af->side;
battle *b = as->battle;
side * ds;
int allies = count_allies(as, minrow, maxrow, SELECT_ADVANCE, allytype);
if (!allies) {
return no_troop;
}
allies = rng_int() % allies;
for (ds=b->sides;ds!=b->sides+b->nsides;++ds) {
if ((allytype==ALLY_ANY && helping(as, ds)) || (allytype==ALLY_SELF && as->faction==ds->faction)) {
fighter * df;
for (df=ds->fighters; df; df=df->next) {
int dr = get_unitrow(df, NULL);
if (dr >= minrow && dr <= maxrow) {
if (df->alive - df->removed > allies) {
troop dt;
assert(allies>=0);
dt.index = allies;
dt.fighter = df;
return dt;
}
allies -= df->alive;
}
}
}
}
assert(!"we should never have gotten here");
return no_troop;
}
static void
loot_items(fighter * corpse)
{
unit * u = corpse->unit;
@ -2271,27 +2315,55 @@ loot_items(fighter * corpse)
int loot = maxloot/i;
if (loot>0) {
int maxrow = BEHIND_ROW;
int lootchance = 50 + b->keeploot;
fighter *fig = NULL;
int looting = 0;
int maxrow = 0;
if (itm->type->flags & (ITF_CURSED|ITF_NOTLOST)) maxrow = LAST_ROW;
itm->number -= loot;
maxloot -= loot;
if (maxrow == LAST_ROW || rng_int() % 100 < lootchance) {
fighter *fig = select_enemy(corpse, FIGHT_ROW, maxrow, 0).fighter;
if (fig) {
item * l = fig->loot;
while (l && l->type!=itm->type) l=l->next;
if (!l) {
l = calloc(sizeof(item), 1);
l->next = fig->loot;
fig->loot = l;
l->type = itm->type;
if (is_monsters(u->faction) && (loot_rules & LOOT_MONSTERS)) {
looting = 1;
} else if (loot_rules&LOOT_OTHERS) {
looting = 1;
} else if (loot_rules&LOOT_SELF) {
looting = 2;
}
if (looting) {
if (itm->type->flags & (ITF_CURSED|ITF_NOTLOST)) {
maxrow = LAST_ROW;
} else {
int lootchance = 50 + b->keeploot;
if (rng_int() % 100 < lootchance) {
maxrow = BEHIND_ROW;
}
l->number += loot;
}
}
if (maxrow>0) {
if (looting==1) {
fig = select_enemy(corpse, FIGHT_ROW, maxrow, 0).fighter;
} else if (looting==2) {
fig = select_ally(corpse, FIGHT_ROW, LAST_ROW, ALLY_SELF).fighter;
} else if (itm->type->flags & (ITF_CURSED|ITF_NOTLOST)) {
/* we absolutely, positively must have somebody loot this thing */
fig = select_enemy(corpse, FIGHT_ROW, maxrow, 0).fighter;
if (!fig) {
fig = select_ally(corpse, FIGHT_ROW, LAST_ROW, ALLY_SELF).fighter;
}
}
}
if (fig) {
item * l = fig->loot;
while (l && l->type!=itm->type) l=l->next;
if (!l) {
l = calloc(sizeof(item), 1);
l->next = fig->loot;
fig->loot = l;
l->type = itm->type;
}
l->number += loot;
}
}
}
}

View File

@ -231,17 +231,20 @@ extern "C" {
extern void do_battle(struct region * r);
/* for combar spells and special attacks */
/* for combat spells and special attacks */
enum { SELECT_ADVANCE = 0x1, SELECT_DISTANCE = 0x2, SELECT_FIND = 0x4 };
enum { ALLY_SELF, ALLY_ANY };
extern troop select_enemy(struct fighter * af, int minrow, int maxrow, int select);
extern troop select_ally(struct fighter * af, int minrow, int maxrow, int allytype);
extern int count_enemies(struct battle * b, const struct fighter * af, int minrow, int maxrow, int select);
extern boolean terminate(troop dt, troop at, int type, const char *damage, boolean missile);
extern void message_all(battle * b, struct message * m);
extern int hits(troop at, troop dt, weapon * awp);
extern void damage_building(struct battle *b, struct building *bldg, int damage_abs);
extern struct cvector * fighters(struct battle *b, const struct side * vs, int minrow, int maxrow, int mask);
extern int count_allies(const struct side * as, int minrow, int maxrow, int select);
extern int count_allies(const struct side * as, int minrow, int maxrow, int select, int allytype);
extern int get_unitrow(const struct fighter * af, const struct side * vs);
extern boolean helping(const struct side * as, const struct side * ds);
extern void rmfighter(fighter *df, int i);

View File

@ -523,33 +523,36 @@ free_buildings(void)
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 */
int
buildingeffsize(const building * b, boolean img)
{
int i = b->size, n = 0;
const construction * cons;
static const struct building_type * bt_castle;
if (!bt_castle) bt_castle = bt_find("castle");
assert(bt_castle);
int i = b->size, n = 0;
const construction * cons;
static const struct building_type * bt_castle;
if (!bt_castle) bt_castle = bt_find("castle");
assert(bt_castle);
if (b==NULL) return 0;
if (b==NULL) return 0;
if (b->type!=bt_castle) {
if (img) {
const attrib * a = a_find(b->attribs, &at_icastle);
if (!a || a->data.v != bt_castle) return 0;
} else return 0;
}
cons = bt_castle->construction;
assert(cons);
if (b->type!=bt_castle) {
if (img) {
const attrib * a = a_find(b->attribs, &at_icastle);
if (!a || a->data.v != bt_castle) return 0;
} else return 0;
}
cons = bt_castle->construction;
assert(cons);
while (cons && cons->maxsize != -1 && i>=cons->maxsize) {
i-=cons->maxsize;
cons = cons->improvement;
++n;
}
while (cons && cons->maxsize != -1 && i>=cons->maxsize) {
i-=cons->maxsize;
cons = cons->improvement;
++n;
}
return n;
return n;
}
const char *

View File

@ -583,7 +583,7 @@ int verbosity = 0;
FILE *debug;
int
shipspeed (const ship * sh, const unit * u)
shipspeed(const ship * sh, const unit * u)
{
int k = sh->type->range;
static const curse_type * stormwind_ct, * nodrift_ct;
@ -606,9 +606,11 @@ shipspeed (const ship * sh, const unit * u)
if( curse_active(get_curse(sh->attribs, nodrift_ct)))
k += 1;
if (u->faction->race == new_race[RC_AQUARIAN]
&& u->race == new_race[RC_AQUARIAN]) {
k += 1;
if (u->faction->race == u->race) {
/* race bonus for this faction? */
if (u->race == new_race[RC_AQUARIAN]) {
k += 1;
}
}
a = a_find(sh->attribs, &at_speedup);
@ -2098,8 +2100,6 @@ get_param_int(const struct param * p, const char * key, int def)
return def;
}
void
set_param(struct param ** p, const char * key, const char * data)
{

View File

@ -198,7 +198,7 @@ static boolean
entrance_allowed(const struct unit * u, const struct region * r)
{
#ifdef REGIONOWNERS
faction * owner = get_region_owner(r);
faction * owner = region_get_owner(r);
if (owner == NULL || u->faction == owner) return true;
if (alliedfaction(r->planep, owner, u->faction, HELP_TRAVEL)) return true;
return false;

View File

@ -50,44 +50,47 @@ typedef struct att {
int flags;
} att;
struct param;
typedef struct race {
const char *_name[4]; /* neu: name[4]völker */
float magres;
float maxaura; /* Faktor auf Maximale Aura */
float regaura; /* Faktor auf Regeneration */
int recruitcost;
int maintenance;
int splitsize;
int weight;
int capacity;
float speed;
struct param * parameters;
const char *_name[4]; /* neu: name[4]völker */
float magres;
float maxaura; /* Faktor auf Maximale Aura */
float regaura; /* Faktor auf Regeneration */
int recruitcost;
int maintenance;
int splitsize;
int weight;
int capacity;
float speed;
float aggression; /* chance that a monster will attack */
int hitpoints;
const char *def_damage;
char armor;
char at_default; /* Angriffsskill Unbewaffnet (default: -2)*/
char df_default; /* Verteidigungsskill Unbewaffnet (default: -2)*/
char at_bonus; /* Verändert den Angriffsskill (default: 0)*/
char df_bonus; /* Verändert den Verteidigungskill (default: 0)*/
const spell * precombatspell;
struct att attack[10];
char bonus[MAXSKILLS];
boolean __remove_me_nonplayer;
int flags;
int battle_flags;
int ec_flags;
race_t oldfamiliars[MAXMAGIETYP];
int hitpoints;
const char *def_damage;
char armor;
char at_default; /* Angriffsskill Unbewaffnet (default: -2)*/
char df_default; /* Verteidigungsskill Unbewaffnet (default: -2)*/
char at_bonus; /* Verändert den Angriffsskill (default: 0)*/
char df_bonus; /* Verändert den Verteidigungskill (default: 0)*/
const spell * precombatspell;
struct att attack[10];
char bonus[MAXSKILLS];
boolean __remove_me_nonplayer;
int flags;
int battle_flags;
int ec_flags;
race_t oldfamiliars[MAXMAGIETYP];
const char *(*generate_name) (const struct unit *);
const char *(*describe) (const struct unit *, const struct locale *);
void (*age)(struct unit *u);
boolean (*move_allowed)(const struct region *, const struct region *);
struct item * (*itemdrop)(const struct race *, int size);
void (*init_familiar)(struct unit *);
const char *(*generate_name) (const struct unit *);
const char *(*describe) (const struct unit *, const struct locale *);
void (*age)(struct unit *u);
boolean (*move_allowed)(const struct region *, const struct region *);
struct item * (*itemdrop)(const struct race *, int size);
void (*init_familiar)(struct unit *);
const struct race * familiars[MAXMAGIETYP];
struct attrib * attribs;
struct race * next;
const struct race * familiars[MAXMAGIETYP];
struct attrib * attribs;
struct race * next;
} race;
typedef struct race_list {

View File

@ -1326,7 +1326,7 @@ r_addmessage(struct region * r, const struct faction * viewer, struct message *
}
struct faction *
get_region_owner(const struct region * r)
region_get_owner(const struct region * r)
{
if (r->land && r->land->ownership) {
return r->land->ownership->owner;
@ -1335,7 +1335,7 @@ get_region_owner(const struct region * r)
}
void
set_region_owner(struct region * r, struct faction * owner, int turn)
region_set_owner(struct region * r, struct faction * owner, int turn)
{
if (r->land && r->land->ownership) {
r->land->ownership->owner = owner;
@ -1371,3 +1371,8 @@ region_getname(const region * r) {
}
return "";
}
int region_get_morale(const region * r)
{
return r->land->morale;
}

View File

@ -79,7 +79,7 @@ typedef struct land_region {
} * demands;
const struct item_type * herbtype;
short herbs;
unsigned short morale;
short morale;
int trees[3]; /* 0 -> seeds, 1 -> shoots, 2 -> trees */
int horses;
int peasants;
@ -232,8 +232,8 @@ extern const short delta_y[MAXDIRECTIONS];
direction_t dir_invert(direction_t dir);
int production(const struct region *r);
void set_region_owner(struct region * r, struct faction * owner, int turn);
struct faction * get_region_owner(const struct region * r);
void region_set_owner(struct region * r, struct faction * owner, int turn);
struct faction * region_get_owner(const struct region * r);
struct region * r_connect(const struct region *, direction_t dir);
#ifdef FAST_CONNECT
@ -244,6 +244,8 @@ struct region * r_connect(const struct region *, direction_t dir);
void free_regions(void);
int region_get_morale(const region * r);
void write_region_reference(const struct region * r, struct storage * store);
variant read_region_reference(struct storage * store);
int resolve_region_coor(variant id, void * address);

View File

@ -588,6 +588,31 @@ write_items(struct storage * store, item *ilist)
store->w_tok(store, "end");
}
static void
write_owner(struct storage * store, region_owner *owner)
{
if (owner) {
store->w_int(store, owner->since_turn);
write_faction_reference(owner->owner, store);
} else {
store->w_int(store, -1);
}
}
static void
read_owner(struct storage * store, region_owner **powner)
{
int since_turn = store->r_int(store);
if (since_turn>=0) {
region_owner * owner = malloc(sizeof(region_owner));
owner->since_turn = since_turn;
read_reference(&owner->owner, store, read_faction_reference, resolve_faction);
*powner = owner;
} else {
*powner = 0;
}
}
int
lastturn(void)
{
@ -990,6 +1015,10 @@ readregion(struct storage * store, short x, short y)
if (store->version>=REGIONITEMS_VERSION) {
read_items(store, &r->land->items);
}
if (store->version>=REGIONOWNER_VERSION) {
r->land->morale = (short)store->r_int(store);
read_owner(store, &r->land->ownership);
}
}
a_read(store, &r->attribs);
@ -1046,6 +1075,11 @@ writeregion(struct storage * store, const region * r)
#if RELEASE_VERSION>=REGIONITEMS_VERSION
write_items(store, r->land->items);
store->w_brk(store);
#endif
#if RELEASE_VERSION>=REGIONOWNER_VERSION
store->w_int(store, r->land->morale);
write_owner(store, r->land->ownership);
store->w_brk(store);
#endif
}
a_write(store, r->attribs);

View File

@ -60,6 +60,7 @@
#define NOZEROIDS_VERSION 330 /* zero is not a valid ID for anything (including factions) */
#define NOBORDERATTRIBS_VERSION 331 /* border::attribs has been moved to userdata */
#define UIDHASH_VERSION 332 /* borders use the region.uid to store */
#define REGIONOWNER_VERSION 333 /* regions have owners and morale */
#define MIN_VERSION CURSETYPE_VERSION /* minimal datafile we support */
#define RELEASE_VERSION UIDHASH_VERSION /* current datafile */
#define RELEASE_VERSION REGIONOWNER_VERSION /* current datafile */

View File

@ -293,7 +293,7 @@ parse_buildings(xmlDocPtr doc)
}
assert(propValue!=NULL);
if (strcmp((const char*)propValue, "name")==0) {
btype->name = (const char * (*)(const struct building_type*, int size))fun;
btype->name = (const char * (*)(const struct building_type*, int))fun;
} else if (strcmp((const char*)propValue, "init")==0) {
btype->init = (void (*)(struct building_type*))fun;
} else {
@ -1487,6 +1487,28 @@ parse_spells(xmlDocPtr doc)
return 0;
}
static void
parse_param(struct param ** params, xmlNodePtr node)
{
xmlChar * propName = xmlGetProp(node, BAD_CAST "name");
xmlChar * propValue = xmlGetProp(node, BAD_CAST "value");
set_param(params, (const char*)propName, (const char*)propValue);
xmlFree(propName);
xmlFree(propValue);
}
static void
parse_ai(race * rc, xmlNodePtr node)
{
rc->splitsize = xml_ivalue(node, "splitsize", 0);
rc->aggression = (float)xml_fvalue(node, "aggression", 0.04);
if (xml_bvalue(node, "killpeasants", false)) rc->flags |= RCF_KILLPEASANTS;
if (xml_bvalue(node, "moverandom", false)) rc->flags |= RCF_MOVERANDOM;
if (xml_bvalue(node, "learn", false)) rc->flags |= RCF_LEARN;
}
static int
parse_races(xmlDocPtr doc)
{
@ -1500,6 +1522,7 @@ parse_races(xmlDocPtr doc)
nodes = races->nodesetval;
for (i=0;i!=nodes->nodeNr;++i) {
xmlNodePtr node = nodes->nodeTab[i];
xmlNodePtr child;
xmlChar * propValue;
race * rc;
xmlXPathObjectPtr result;
@ -1573,19 +1596,13 @@ parse_races(xmlDocPtr doc)
if (xml_bvalue(node, "resistpierce", false)) rc->battle_flags |= BF_RES_PIERCE;
if (xml_bvalue(node, "canattack", true)) rc->battle_flags |= BF_CANATTACK;
/* reading eressea/races/race/ai */
xpath->node = node;
result = xmlXPathEvalExpression(BAD_CAST "ai", xpath);
for (k=0;k!=result->nodesetval->nodeNr;++k) {
xmlNodePtr node = result->nodesetval->nodeTab[k];
rc->splitsize = xml_ivalue(node, "splitsize", 0);
rc->aggression = (float)xml_fvalue(node, "aggression", 0.04);
if (xml_bvalue(node, "killpeasants", false)) rc->flags |= RCF_KILLPEASANTS;
if (xml_bvalue(node, "moverandom", false)) rc->flags |= RCF_MOVERANDOM;
if (xml_bvalue(node, "learn", false)) rc->flags |= RCF_LEARN;
for (child=node->children;child;child=child->next) {
if (strcmp((const char *)child->name, "ai")==0) {
parse_ai(rc, child);
} else if (strcmp((const char *)child->name, "param")==0) {
parse_param(&rc->parameters, child);
}
}
xmlXPathFreeObject(result);
/* reading eressea/races/race/skill */
xpath->node = node;
@ -2043,13 +2060,7 @@ parse_main(xmlDocPtr doc)
nodes = result->nodesetval;
for (i=0;i!=nodes->nodeNr;++i) {
xmlNodePtr node = nodes->nodeTab[i];
xmlChar * propName = xmlGetProp(node, BAD_CAST "name");
xmlChar * propValue = xmlGetProp(node, BAD_CAST "value");
set_param(&global.parameters, (const char*)propName, (const char*)propValue);
xmlFree(propName);
xmlFree(propValue);
parse_param(&global.parameters, node);
}
xmlXPathFreeObject(result);

View File

@ -61,3 +61,5 @@
#else
# define BINDINGS_TOLUA /* new default */
#endif
#undef REGIONOWNERS /* (WIP) region-owner uses HELP_TRAVEL to control entry to region */

View File

@ -385,41 +385,6 @@ sp_sleep(fighter * fi, int level, double power, spell * sp)
}
static troop
select_ally(fighter * af, int minrow, int maxrow)
{
side *as = af->side;
battle *b = as->battle;
side * ds;
int allies = count_allies(as, minrow, maxrow, SELECT_ADVANCE);
if (!allies) {
return no_troop;
}
allies = rng_int() % allies;
for (ds=b->sides;ds!=b->sides+b->nsides;++ds) {
if (helping(as, ds)) {
fighter * df;
for (df=ds->fighters; df; df=df->next) {
int dr = get_unitrow(df, NULL);
if (dr >= minrow && dr <= maxrow) {
if (df->alive - df->removed > allies) {
troop dt;
assert(allies>=0);
dt.index = allies;
dt.fighter = df;
return dt;
}
allies -= df->alive;
}
}
}
}
assert(!"we should never have gotten here");
return no_troop;
}
int
sp_speed(fighter * fi, int level, double power, spell * sp)
{
@ -431,13 +396,13 @@ sp_speed(fighter * fi, int level, double power, spell * sp)
force = lovar(power * power * 5);
allies = count_allies(fi->side, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE);
allies = count_allies(fi->side, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE, ALLY_ANY);
/* maximal 2*allies Versuche ein Opfer zu finden, ansonsten bestände
* die Gefahr eine Endlosschleife*/
allies *= 2;
while (force && allies) {
troop dt = select_ally(fi, FIGHT_ROW, BEHIND_ROW);
troop dt = select_ally(fi, FIGHT_ROW, BEHIND_ROW, ALLY_ANY);
fighter *df = dt.fighter;
--allies;
@ -1074,13 +1039,13 @@ sp_hero(fighter * fi, int level, double power, spell * sp)
force = MAX(1, (int)power);
}
allies = count_allies(fi->side, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE);
allies = count_allies(fi->side, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE, ALLY_ANY);
/* maximal 2*allies Versuche ein Opfer zu finden, ansonsten bestände
* die Gefahr eine Endlosschleife*/
allies *= 2;
while (force && allies) {
troop dt = select_ally(fi, FIGHT_ROW, BEHIND_ROW);
troop dt = select_ally(fi, FIGHT_ROW, BEHIND_ROW, ALLY_ANY);
fighter *df = dt.fighter;
--allies;
@ -1126,13 +1091,13 @@ sp_berserk(fighter * fi, int level, double power, spell * sp)
force = (int)power;
}
allies = count_allies(fi->side, FIGHT_ROW, BEHIND_ROW-1, SELECT_ADVANCE);
allies = count_allies(fi->side, FIGHT_ROW, BEHIND_ROW-1, SELECT_ADVANCE, ALLY_ANY);
/* maximal 2*allies Versuche ein Opfer zu finden, ansonsten bestände
* die Gefahr eine Endlosschleife*/
allies *= 2;
while (force && allies) {
troop dt = select_ally(fi, FIGHT_ROW, BEHIND_ROW-1);
troop dt = select_ally(fi, FIGHT_ROW, BEHIND_ROW-1, ALLY_ANY);
fighter *df = dt.fighter;
--allies;

View File

@ -63,12 +63,12 @@ region_getterrain(const region * r) {
static void
lua_region_setowner(region * r, faction * f) {
set_region_owner(r, f, turn);
region_set_owner(r, f, turn);
}
static faction *
lua_region_getowner(const region * r) {
return get_region_owner(r);
return region_get_owner(r);
}
static void

View File

@ -27,6 +27,8 @@ without prior permission by the authors of Eressea.
#include <kernel/item.h>
#include <kernel/region.h>
#include <gamecode/archetype.h>
#include <lua.h>
#include <tolua.h>
@ -435,11 +437,43 @@ lua_useitem(struct unit * u, const struct item_type * itype, int amount, struct
return result;
}
static int
lua_recruit(struct unit * u, const struct archetype * arch, int amount)
{
lua_State * L = (lua_State *)global.vm_state;
int result = 0;
char fname[64];
snprintf(fname, sizeof(fname), "recruit_%s", arch->name[0]);
lua_pushstring(L, fname);
lua_rawget(L, LUA_GLOBALSINDEX);
if (lua_isfunction(L, 1)) {
tolua_pushusertype(L, (void *)u, "unit");
tolua_pushnumber(L, (lua_Number)amount);
if (lua_pcall(L, 2, 1, 0)!=0) {
const char* error = lua_tostring(L, -1);
log_error(("use(%s) calling '%s': %s.\n",
unitname(u), fname, error));
lua_pop(L, 1);
} else {
result = (int)lua_tonumber(L, -1);
lua_pop(L, 1);
}
} else {
log_error(("use(%s) calling '%s': not a function.\n",
unitname(u), fname));
lua_pop(L, 1);
}
return result;
}
void
register_tolua_helpers(void)
{
at_building_action.age = lc_age;
register_function((pf_generic)&lua_recruit, "lua_recruit");
register_function((pf_generic)&lua_callspell, "lua_castspell");
register_function((pf_generic)&lua_initfamiliar, "lua_initfamiliar");
register_item_use(&lua_useitem, "lua_useitem");