- 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/umlaut.h>
#include <util/language.h> #include <util/language.h>
#include <util/xml.h> #include <util/xml.h>
#include <util/functions.h>
/* libxml includes */ /* libxml includes */
#include <libxml/tree.h> #include <libxml/tree.h>
@ -83,6 +84,7 @@ parse_archetypes(xmlDocPtr doc)
int i; int i;
for (i=0;i!=nodes->nodeNr;++i) { for (i=0;i!=nodes->nodeNr;++i) {
xmlNodePtr node = nodes->nodeTab[i]; xmlNodePtr node = nodes->nodeTab[i];
xmlNodePtr child;
archetype * arch = calloc(1, sizeof(archetype)); archetype * arch = calloc(1, sizeof(archetype));
xmlXPathObjectPtr sub; xmlXPathObjectPtr sub;
@ -109,6 +111,18 @@ parse_archetypes(xmlDocPtr doc)
arch->size = xml_ivalue(node, "cost", 0); 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; xpath->node = node;
sub = xmlXPathEvalExpression(BAD_CAST "allow|deny", xpath); sub = xmlXPathEvalExpression(BAD_CAST "allow|deny", xpath);
if (sub->nodesetval && sub->nodesetval->nodeNr) { if (sub->nodesetval && sub->nodesetval->nodeNr) {

View File

@ -23,6 +23,8 @@ extern "C" {
char * value; char * value;
} rule; } rule;
typedef int (*archetype_function)(struct unit * u, const struct archetype *, int);
typedef struct archetype { typedef struct archetype {
struct archetype * next; struct archetype * next;
char * name[2]; char * name[2];
@ -31,6 +33,7 @@ extern "C" {
struct equipment * equip; struct equipment * equip;
struct construction * ctype; struct construction * ctype;
struct rule * rules; struct rule * rules;
archetype_function exec;
} archetype; } archetype;
extern const struct archetype * find_archetype(const char * s, const struct locale * lang); 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]); 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) { if (owner) {
fprintf(F, "%d;owner\n", owner->no); fprintf(F, "%d;owner\n", owner->no);
} }

View File

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

View File

@ -187,7 +187,7 @@ get_food(region *r)
{ {
unit *u; unit *u;
int peasantfood = rpeasants(r)*10; 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 /* 1. Versorgung von eigenen Einheiten. Das vorhandene Silber
* wird zunächst so auf die Einheiten aufgeteilt, dass idealerweise * wird zunächst so auf die Einheiten aufgeteilt, dass idealerweise
@ -2914,9 +2914,16 @@ age_building(building * b)
return b; return b;
} }
static void age_region(region * r)
{
a_age(&r->attribs);
handle_event(r->attribs, "timer", r);
}
static void static void
ageing(void) ageing(void)
{ {
const building_type * bt_castle = bt_find("castle");
faction *f; faction *f;
region *r; region *r;
@ -2960,9 +2967,9 @@ ageing(void)
building ** bp; building ** bp;
unit ** up; unit ** up;
ship ** sp; ship ** sp;
building * blargest = NULL;
a_age(&r->attribs); age_region(r);
handle_event(r->attribs, "timer", r);
/* Einheiten */ /* Einheiten */
for (up=&r->units;*up;) { for (up=&r->units;*up;) {
@ -2985,7 +2992,24 @@ ageing(void)
building * b = *bp; building * b = *bp;
b = age_building(b); 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) { if (owner!=NULL) {
bytes = snprintf(bufp, size, " Die Region ist im Besitz von %s.", bytes = snprintf(bufp, size, " Die Region ist im Besitz von %s.",
factionname(owner)); factionname(owner));

View File

@ -117,11 +117,16 @@ const troop no_troop = {0, 0};
static int max_turns = 0; static int max_turns = 0;
static int damage_rules = 0; static int damage_rules = 0;
static int loot_rules = 0;
static int skill_formula = 0; static int skill_formula = 0;
#define FORMULA_ORIG 0 #define FORMULA_ORIG 0
#define FORMULA_NEW 1 #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_CRITICAL (1<<0)
#define DAMAGE_MELEE_BONUS (1<<1) #define DAMAGE_MELEE_BONUS (1<<1)
#define DAMAGE_MISSILE_BONUS (1<<2) #define DAMAGE_MISSILE_BONUS (1<<2)
@ -132,6 +137,7 @@ static int skill_formula = 0;
static void static void
static_rules(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 */ /* new formula to calculate to-hit-chance */
skill_formula = get_param_int(global.parameters, "rules.combat.skill_formula", FORMULA_ORIG); skill_formula = get_param_int(global.parameters, "rules.combat.skill_formula", FORMULA_ORIG);
/* maximum number of combat turns */ /* maximum number of combat turns */
@ -1279,17 +1285,18 @@ 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 * troops that are still alive, not those that are still fighting although
* dead. */ * dead. */
int 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; battle *b = as->battle;
side *s; side *ds;
int count = 0; int count = 0;
for (s=b->sides;s!=b->sides+b->nsides;++s) { for (ds=b->sides;ds!=b->sides+b->nsides;++ds) {
if (!helping(as, s)) continue; if ((allytype==ALLY_ANY && helping(as, ds)) || (allytype==ALLY_SELF && as->faction==ds->faction)) {
count += count_side(s, NULL, minrow, maxrow, select); count += count_side(ds, NULL, minrow, maxrow, select);
if (count>0 && (select&SELECT_FIND)) break; if (count>0 && (select&SELECT_FIND)) break;
} }
}
return count; return count;
} }
@ -1933,12 +1940,14 @@ attacks_per_round(troop t)
return t.fighter->person[t.index].speed; return t.fighter->person[t.index].speed;
} }
#define HERO_SPEED 10
static void static void
make_heroes(battle * b) make_heroes(battle * b)
{ {
side * s; 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) { for (s=b->sides;s!=b->sides+b->nsides;++s) {
fighter * fig; fighter * fig;
for (fig=s->fighters;fig;fig=fig->next) { for (fig=s->fighters;fig;fig=fig->next) {
@ -1947,7 +1956,7 @@ make_heroes(battle * b)
int i; int i;
assert(playerrace(u->race)); assert(playerrace(u->race));
for (i=0;i!=u->number;++i) { 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; 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) loot_items(fighter * corpse)
{ {
unit * u = corpse->unit; unit * u = corpse->unit;
@ -2271,15 +2315,44 @@ loot_items(fighter * corpse)
int loot = maxloot/i; int loot = maxloot/i;
if (loot>0) { if (loot>0) {
int maxrow = BEHIND_ROW; fighter *fig = NULL;
int lootchance = 50 + b->keeploot; int looting = 0;
int maxrow = 0;
if (itm->type->flags & (ITF_CURSED|ITF_NOTLOST)) maxrow = LAST_ROW;
itm->number -= loot; itm->number -= loot;
maxloot -= loot; maxloot -= loot;
if (maxrow == LAST_ROW || rng_int() % 100 < lootchance) { if (is_monsters(u->faction) && (loot_rules & LOOT_MONSTERS)) {
fighter *fig = select_enemy(corpse, FIGHT_ROW, maxrow, 0).fighter; 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;
}
}
}
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) { if (fig) {
item * l = fig->loot; item * l = fig->loot;
while (l && l->type!=itm->type) l=l->next; while (l && l->type!=itm->type) l=l->next;
@ -2294,7 +2367,6 @@ loot_items(fighter * corpse)
} }
} }
} }
}
itm = itm->next; itm = itm->next;
} }
} }

View File

@ -231,17 +231,20 @@ extern "C" {
extern void do_battle(struct region * r); 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 { 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_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 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 boolean terminate(troop dt, troop at, int type, const char *damage, boolean missile);
extern void message_all(battle * b, struct message * m); extern void message_all(battle * b, struct message * m);
extern int hits(troop at, troop dt, weapon * awp); extern int hits(troop at, troop dt, weapon * awp);
extern void damage_building(struct battle *b, struct building *bldg, int damage_abs); 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 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 int get_unitrow(const struct fighter * af, const struct side * vs);
extern boolean helping(const struct side * as, const struct side * ds); extern boolean helping(const struct side * as, const struct side * ds);
extern void rmfighter(fighter *df, int i); extern void rmfighter(fighter *df, int i);

View File

@ -523,6 +523,9 @@ free_buildings(void)
extern struct attrib_type at_icastle; 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 int
buildingeffsize(const building * b, boolean img) buildingeffsize(const building * b, boolean img)
{ {

View File

@ -583,7 +583,7 @@ int verbosity = 0;
FILE *debug; FILE *debug;
int int
shipspeed (const ship * sh, const unit * u) shipspeed(const ship * sh, const unit * u)
{ {
int k = sh->type->range; int k = sh->type->range;
static const curse_type * stormwind_ct, * nodrift_ct; static const curse_type * stormwind_ct, * nodrift_ct;
@ -606,10 +606,12 @@ shipspeed (const ship * sh, const unit * u)
if( curse_active(get_curse(sh->attribs, nodrift_ct))) if( curse_active(get_curse(sh->attribs, nodrift_ct)))
k += 1; k += 1;
if (u->faction->race == new_race[RC_AQUARIAN] if (u->faction->race == u->race) {
&& u->race == new_race[RC_AQUARIAN]) { /* race bonus for this faction? */
if (u->race == new_race[RC_AQUARIAN]) {
k += 1; k += 1;
} }
}
a = a_find(sh->attribs, &at_speedup); a = a_find(sh->attribs, &at_speedup);
while (a != NULL && a->type==&at_speedup) { while (a != NULL && a->type==&at_speedup) {
@ -2098,8 +2100,6 @@ get_param_int(const struct param * p, const char * key, int def)
return def; return def;
} }
void void
set_param(struct param ** p, const char * key, const char * data) 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) entrance_allowed(const struct unit * u, const struct region * r)
{ {
#ifdef REGIONOWNERS #ifdef REGIONOWNERS
faction * owner = get_region_owner(r); faction * owner = region_get_owner(r);
if (owner == NULL || u->faction == owner) return true; if (owner == NULL || u->faction == owner) return true;
if (alliedfaction(r->planep, owner, u->faction, HELP_TRAVEL)) return true; if (alliedfaction(r->planep, owner, u->faction, HELP_TRAVEL)) return true;
return false; return false;

View File

@ -50,7 +50,10 @@ typedef struct att {
int flags; int flags;
} att; } att;
struct param;
typedef struct race { typedef struct race {
struct param * parameters;
const char *_name[4]; /* neu: name[4]völker */ const char *_name[4]; /* neu: name[4]völker */
float magres; float magres;
float maxaura; /* Faktor auf Maximale Aura */ float maxaura; /* Faktor auf Maximale Aura */

View File

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

View File

@ -79,7 +79,7 @@ typedef struct land_region {
} * demands; } * demands;
const struct item_type * herbtype; const struct item_type * herbtype;
short herbs; short herbs;
unsigned short morale; short morale;
int trees[3]; /* 0 -> seeds, 1 -> shoots, 2 -> trees */ int trees[3]; /* 0 -> seeds, 1 -> shoots, 2 -> trees */
int horses; int horses;
int peasants; int peasants;
@ -232,8 +232,8 @@ extern const short delta_y[MAXDIRECTIONS];
direction_t dir_invert(direction_t dir); direction_t dir_invert(direction_t dir);
int production(const struct region *r); int production(const struct region *r);
void set_region_owner(struct region * r, struct faction * owner, int turn); void region_set_owner(struct region * r, struct faction * owner, int turn);
struct faction * get_region_owner(const struct region * r); struct faction * region_get_owner(const struct region * r);
struct region * r_connect(const struct region *, direction_t dir); struct region * r_connect(const struct region *, direction_t dir);
#ifdef FAST_CONNECT #ifdef FAST_CONNECT
@ -244,6 +244,8 @@ struct region * r_connect(const struct region *, direction_t dir);
void free_regions(void); void free_regions(void);
int region_get_morale(const region * r);
void write_region_reference(const struct region * r, struct storage * store); void write_region_reference(const struct region * r, struct storage * store);
variant read_region_reference(struct storage * store); variant read_region_reference(struct storage * store);
int resolve_region_coor(variant id, void * address); 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"); 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 int
lastturn(void) lastturn(void)
{ {
@ -990,6 +1015,10 @@ readregion(struct storage * store, short x, short y)
if (store->version>=REGIONITEMS_VERSION) { if (store->version>=REGIONITEMS_VERSION) {
read_items(store, &r->land->items); 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); a_read(store, &r->attribs);
@ -1046,6 +1075,11 @@ writeregion(struct storage * store, const region * r)
#if RELEASE_VERSION>=REGIONITEMS_VERSION #if RELEASE_VERSION>=REGIONITEMS_VERSION
write_items(store, r->land->items); write_items(store, r->land->items);
store->w_brk(store); 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 #endif
} }
a_write(store, r->attribs); 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 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 NOBORDERATTRIBS_VERSION 331 /* border::attribs has been moved to userdata */
#define UIDHASH_VERSION 332 /* borders use the region.uid to store */ #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 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); assert(propValue!=NULL);
if (strcmp((const char*)propValue, "name")==0) { 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) { } else if (strcmp((const char*)propValue, "init")==0) {
btype->init = (void (*)(struct building_type*))fun; btype->init = (void (*)(struct building_type*))fun;
} else { } else {
@ -1487,6 +1487,28 @@ parse_spells(xmlDocPtr doc)
return 0; 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 static int
parse_races(xmlDocPtr doc) parse_races(xmlDocPtr doc)
{ {
@ -1500,6 +1522,7 @@ parse_races(xmlDocPtr doc)
nodes = races->nodesetval; nodes = races->nodesetval;
for (i=0;i!=nodes->nodeNr;++i) { for (i=0;i!=nodes->nodeNr;++i) {
xmlNodePtr node = nodes->nodeTab[i]; xmlNodePtr node = nodes->nodeTab[i];
xmlNodePtr child;
xmlChar * propValue; xmlChar * propValue;
race * rc; race * rc;
xmlXPathObjectPtr result; 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, "resistpierce", false)) rc->battle_flags |= BF_RES_PIERCE;
if (xml_bvalue(node, "canattack", true)) rc->battle_flags |= BF_CANATTACK; if (xml_bvalue(node, "canattack", true)) rc->battle_flags |= BF_CANATTACK;
/* reading eressea/races/race/ai */ for (child=node->children;child;child=child->next) {
xpath->node = node; if (strcmp((const char *)child->name, "ai")==0) {
result = xmlXPathEvalExpression(BAD_CAST "ai", xpath); parse_ai(rc, child);
for (k=0;k!=result->nodesetval->nodeNr;++k) { } else if (strcmp((const char *)child->name, "param")==0) {
xmlNodePtr node = result->nodesetval->nodeTab[k]; parse_param(&rc->parameters, child);
}
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;
} }
xmlXPathFreeObject(result);
/* reading eressea/races/race/skill */ /* reading eressea/races/race/skill */
xpath->node = node; xpath->node = node;
@ -2043,13 +2060,7 @@ parse_main(xmlDocPtr doc)
nodes = result->nodesetval; nodes = result->nodesetval;
for (i=0;i!=nodes->nodeNr;++i) { for (i=0;i!=nodes->nodeNr;++i) {
xmlNodePtr node = nodes->nodeTab[i]; xmlNodePtr node = nodes->nodeTab[i];
xmlChar * propName = xmlGetProp(node, BAD_CAST "name"); parse_param(&global.parameters, node);
xmlChar * propValue = xmlGetProp(node, BAD_CAST "value");
set_param(&global.parameters, (const char*)propName, (const char*)propValue);
xmlFree(propName);
xmlFree(propValue);
} }
xmlXPathFreeObject(result); xmlXPathFreeObject(result);

View File

@ -61,3 +61,5 @@
#else #else
# define BINDINGS_TOLUA /* new default */ # define BINDINGS_TOLUA /* new default */
#endif #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 int
sp_speed(fighter * fi, int level, double power, spell * sp) 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); 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 /* maximal 2*allies Versuche ein Opfer zu finden, ansonsten bestände
* die Gefahr eine Endlosschleife*/ * die Gefahr eine Endlosschleife*/
allies *= 2; allies *= 2;
while (force && allies) { 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; fighter *df = dt.fighter;
--allies; --allies;
@ -1074,13 +1039,13 @@ sp_hero(fighter * fi, int level, double power, spell * sp)
force = MAX(1, (int)power); 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 /* maximal 2*allies Versuche ein Opfer zu finden, ansonsten bestände
* die Gefahr eine Endlosschleife*/ * die Gefahr eine Endlosschleife*/
allies *= 2; allies *= 2;
while (force && allies) { 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; fighter *df = dt.fighter;
--allies; --allies;
@ -1126,13 +1091,13 @@ sp_berserk(fighter * fi, int level, double power, spell * sp)
force = (int)power; 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 /* maximal 2*allies Versuche ein Opfer zu finden, ansonsten bestände
* die Gefahr eine Endlosschleife*/ * die Gefahr eine Endlosschleife*/
allies *= 2; allies *= 2;
while (force && allies) { 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; fighter *df = dt.fighter;
--allies; --allies;

View File

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

View File

@ -27,6 +27,8 @@ without prior permission by the authors of Eressea.
#include <kernel/item.h> #include <kernel/item.h>
#include <kernel/region.h> #include <kernel/region.h>
#include <gamecode/archetype.h>
#include <lua.h> #include <lua.h>
#include <tolua.h> #include <tolua.h>
@ -435,11 +437,43 @@ lua_useitem(struct unit * u, const struct item_type * itype, int amount, struct
return result; 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 void
register_tolua_helpers(void) register_tolua_helpers(void)
{ {
at_building_action.age = lc_age; 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_callspell, "lua_castspell");
register_function((pf_generic)&lua_initfamiliar, "lua_initfamiliar"); register_function((pf_generic)&lua_initfamiliar, "lua_initfamiliar");
register_item_use(&lua_useitem, "lua_useitem"); register_item_use(&lua_useitem, "lua_useitem");