new code for 'kingdoms':

- disabling skills
- region owners
- maintenance costs configurable
- wage configurable
This commit is contained in:
Enno Rehling 2005-11-25 22:09:59 +00:00
parent 532eb77c51
commit bb1e86ebb4
19 changed files with 364 additions and 62 deletions

View file

@ -2280,10 +2280,12 @@ expandstealing(region * r, request * stealorders)
int uct = 0;
unit *u2;
assert(effskill(oa[i].unit, SK_STEALTH)>=4 || !"this goblin\'s talent is too low");
for (u2 = r->units; u2; u2 = u2->next)
if (u2->faction == u->faction)
uct += u2->number;
n -= uct * 2 * MAINTENANCE;
for (u2 = r->units; u2; u2 = u2->next) {
if (u2->faction == u->faction) {
uct += maintenance_cost(u2);
}
}
n -= uct * 2;
}
#endif
if (n>10 && rplane(r) && (rplane(r)->flags & PFL_NOALLIANCES)) {

View file

@ -176,6 +176,7 @@ get_food(region *r)
{
unit *u;
int peasantfood = rpeasants(r)*10;
faction * owner = region_owner(r);
/* 1. Versorgung von eigenen Einheiten. Das vorhandene Silber
* wird zunächst so auf die Einheiten aufgeteilt, dass idealerweise
@ -187,6 +188,15 @@ get_food(region *r)
/* Erstmal zurücksetzen */
freset(u, UFL_HUNGER);
/* if the region is owned, and the owner is nice, then we'll get
* food from the peasants */
if (owner!=NULL && (get_alliance(owner, u->faction) & HELP_MONEY)) {
int rm = rmoney(r);
int use = min(rm, need);
rsetmoney(r, rm-use);
need -= use;
}
need -= get_money(u);
if (need > 0) {
unit *v;
@ -569,8 +579,8 @@ peasants(region * r)
/* Alle werden satt, oder halt soviele für die es auch Geld gibt */
money = rmoney(r);
satiated = min(peasants, money / MAINTENANCE);
rsetmoney(r, money - satiated * MAINTENANCE);
satiated = min(peasants, money / maintenance_cost(NULL));
rsetmoney(r, money - satiated * maintenance_cost(NULL));
/* Von denjenigen, die nicht satt geworden sind, verhungert der
* Großteil. dead kann nie größer als rpeasants(r) - satiated werden,

View file

@ -396,12 +396,10 @@ sink_ship(region * r, ship * sh, const char *name, char spy, unit * saboteur)
const char *spy_discovered_msg = "%s entdeckte %s beim versenken von %s.";
unit **ui;
region *safety = r;
faction *f;
int i;
direction_t d;
unsigned int index;
double probability = 0.0;
int money, count;
char buffer[DISPLAYSIZE + 1];
vset informed;
vset survivors;
@ -469,23 +467,22 @@ sink_ship(region * r, ship * sh, const char *name, char spy, unit * saboteur)
* amount: */
while (informed.size != 0) {
unit *lastunit = 0;
int money = 0, maintain = 0;
faction * f = (faction *) informed.data[0];
f = (faction *) informed.data[0];
money = 0;
count = 0;
/* find out how much money this faction still has: */
/* find out how much money this faction still has: */
for (index = 0; index != survivors.size; ++index) {
unit *u = (unit *) survivors.data[index];
if (u->faction == f) {
count += u->number;
maintain += maintenance_cost(u);
money += get_money(u);
lastunit = u;
}
}
/* 'money' shall be the maintenance-surplus of the survivng
* units: */
money = money - count * MAINTENANCE;
money = money - maintain;
for (index = 0; money > 0; ++index) {
int remove;
unit *u = (unit *) survivors.data[index];

View file

@ -59,14 +59,15 @@
#include "unit.h"
/* util includes */
#include <base36.h>
#include <event.h>
#include <umlaut.h>
#include <translation.h>
#include <crmessage.h>
#include <log.h>
#include <sql.h>
#include <xml.h>
#include <util/base36.h>
#include <util/crmessage.h>
#include <util/event.h>
#include <util/functions.h>
#include <util/log.h>
#include <util/sql.h>
#include <util/translation.h>
#include <util/umlaut.h>
#include <util/xml.h>
/* libxml includes */
#include <libxml/tree.h>
@ -2334,8 +2335,11 @@ init_locale(const struct locale * lang)
}
for (i=0;i!=MAXSKILLS;++i) {
if (i!=SK_TRADE || !TradeDisabled()) {
var.i = i;
addtoken(&lnames->skillnames, skillname((skill_t)i, lang), var);
const char * skname = skillname((skill_t)i, lang);
if (skname!=NULL) {
var.i = i;
addtoken(&lnames->skillnames, skname, var);
}
}
}
for (i=0;i!=MAXKEYWORDS;++i) {
@ -2709,7 +2713,7 @@ lifestyle(const unit * u)
if (u->faction->no == MONSTER_FACTION) return 0;
need = u->number * u->race->maintenance;
need = maintenance_cost(u);
if (!astralspace) {
astralspace = getplanebyname("Astralraum");
@ -2823,10 +2827,8 @@ static const int wagetable[7][4] = {
{15, 13, 16, 2} /* Zitadelle */
};
/* Gibt Arbeitslohn für entsprechende Rasse zurück, oder für
* die Bauern wenn f == NULL. */
int
wage(const region *r, const faction * f, const race * rc)
static int
default_wage(const region *r, const faction * f, const race * rc)
{
building *b = largestbuilding(r, false);
int esize = 0;
@ -2888,6 +2890,18 @@ wage(const region *r, const faction * f, const race * rc)
return wage;
}
/* Gibt Arbeitslohn für entsprechende Rasse zurück, oder für
* die Bauern wenn f == NULL. */
int
wage(const region *r, const faction * f, const race * rc)
{
if (global.functions.wage) {
return global.functions.wage(r, f, rc);
}
return default_wage(r, f, rc);
}
static region *
findspecialdirection(const region *r, const char *token)
{
@ -2906,6 +2920,18 @@ findspecialdirection(const region *r, const char *token)
return NULL;
}
#define MAINTENANCE 10
int
maintenance_cost(const struct unit * u)
{
if (u==NULL) return MAINTENANCE;
if (global.functions.maintenance) {
int retval = global.functions.maintenance(u);
if (retval>=0) return retval;
}
return u->race->maintenance * u->number;
}
message *
movement_error(unit * u, const char * token, order * ord, int error_code)
{

View file

@ -366,7 +366,6 @@ extern void plagues(struct region * r, boolean ismagic);
#define STARTMONEY 5000
#define PRODUCEEXP 10
#define MAINTENANCE 10
#define TAVERN_MAINTENANCE 14
/* Man gibt in einer Taverne mehr Geld aus! */
@ -1122,6 +1121,7 @@ extern int besieged(const struct unit * u);
extern int maxworkingpeasants(const struct region * r);
extern int wage(const struct region *r, const struct faction *f, const struct race * rc);
extern int maintenance_cost(const struct unit * u);
extern int movewhere(const struct unit *u, const char * token, struct region * r, struct region** resultp);
extern struct message * movement_error(struct unit * u, const char * token, struct order * ord, int error_code);
extern boolean move_blocked(const struct unit * u, const struct region *src, const struct region *dest);
@ -1159,6 +1159,10 @@ typedef struct settings {
struct param * parameters;
void * vm_state;
struct global_functions {
int (*wage)(const struct region *r, const struct faction * f, const struct race * rc);
int (*maintenance)(const struct unit * u);
} functions;
} settings;
extern settings global;

View file

@ -75,10 +75,28 @@ static const char *skillnames[MAXSKILLS] =
"unarmed"
};
static boolean skill_enabled[MAXSKILLS];
const char *
skillname(skill_t sk, const struct locale * lang)
{
return locale_string(lang, mkname("skill", skillnames[sk]));
if (skill_enabled[sk]) {
return locale_string(lang, mkname("skill", skillnames[sk]));
}
return NULL;
}
void
enable_skill(const char * skname, boolean value)
{
skill_t sk;
for (sk=0;sk!=MAXSKILLS) {
if (strcmp(skillnames[sk], skname)==0) {
skill_enabled[sk] = value;
return;
}
}
log_error(("Trying to set unknown skill %s to %u", skname, value));
}
skill_t
@ -88,7 +106,9 @@ sk_find(const char * name)
if (name==NULL) return NOSKILL;
if (strncmp(name, "sk_", 3)==0) name+=3;
for (i=0;i!=MAXSKILLS;++i) {
if (strcmp(name, skillnames[i])==0) return i;
if (skill_enabled[i]) {
if (strcmp(name, skillnames[i])==0) return i;
}
}
return NOSKILL;
}

View file

@ -48,7 +48,7 @@ extern struct attrib * make_skillmod(skill_t sk, unsigned int flags, skillmod_fu
extern const char * skillname(skill_t, const struct locale *);
extern skill_t sk_find(const char * name);
extern void enable_skill(const char * name, boolean value);
extern int level_days(int level);
extern int level(int days);

View file

@ -1865,6 +1865,18 @@ parse_main(xmlDocPtr doc)
}
xmlXPathFreeObject(result);
/* reading eressea/game/skill */
result = xmlXPathEvalExpression(BAD_CAST "skill", xpath);
nodes = result->nodesetval;
for (i=0;i!=nodes->nodeNr;++i) {
xmlNodePtr node = nodes->nodeTab[i];
xmlChar * name = xmlGetProp(node, BAD_CAST "name");
boolean enable = xml_bvalue(node, "enable", true);
enable_skill((const char*)name, enable);
xmlFree(name);
}
xmlXPathFreeObject(result);
xmlXPathFreeContext(xpath);
return 0;
}

View file

@ -4616,7 +4616,7 @@ sp_seduce(castorder *co)
/* Erfolgsmeldung */
sprintf(buf, "%s schenkt %s ", unitname(target), unitname(mage));
loot = min(cast_level * 1000, get_money(target) - (MAINTENANCE*target->number));
loot = min(cast_level * 1000, get_money(target) - (maintenance_cost(target)));
loot = max(loot, 0);
change_money(mage, loot);
change_money(target, -loot);

View file

@ -221,10 +221,6 @@ extern char * strdup(const char *s);
#endif
#if defined (ghs) || defined (__GNUC__) || defined (__hpux) || defined (__sgi) || defined (__DECCXX) || defined (__KCC) || defined (__rational__) || defined (__USLC__) || defined (ACE_RM544)
// Some compilers complain about "statement with no effect" with (a).
// This eliminates the warnings, and no code is generated for the null
// conditional statement. NOTE: that may only be true if -O is enabled,
// such as with GreenHills (ghs) 1.8.8.
# define unused(a) do {/* null */} while (&a == 0)
#else /* ghs || __GNUC__ || ..... */
# define unused(a) (a)

View file

@ -242,21 +242,21 @@ faction_setorigin(faction& f, int x, int y)
y = 0;
}
int
short
faction_getorigin_x(const faction& f) {
return f.ursprung->x;
}
void
faction_setorigin_x(faction& f, int x) {
faction_setorigin_x(faction& f, short x) {
f.ursprung->x = x;
}
int
short
faction_getorigin_y(const faction& f) {
return f.ursprung->y;
}
void
faction_setorigin_y(faction& f, int y) {
faction_setorigin_y(faction& f, short y) {
f.ursprung->y = y;
}

View file

@ -29,14 +29,17 @@
#include <boost/version.hpp>
#include <lua.hpp>
#include <luabind/luabind.hpp>
#include <luabind/object.hpp>
#include <cstdio>
#include <cstring>
using namespace luabind;
static void
free_script(attrib * a) {
if (a->data.v!=NULL) {
luabind::object * f = (luabind::object *)a->data.v;
object * f = (object *)a->data.v;
delete f;
}
}
@ -53,11 +56,11 @@ call_script(struct unit * u)
const attrib * a = a_findc(u->attribs, &at_script);
if (a==NULL) a = a_findc(u->race->attribs, &at_script);
if (a!=NULL && a->data.v!=NULL) {
luabind::object * func = (luabind::object *)a->data.v;
object * func = (object *)a->data.v;
try {
func->operator()(u);
}
catch (luabind::error& e) {
catch (error& e) {
lua_State* L = e.state();
const char* error = lua_tostring(L, -1);
log_error((error));
@ -75,7 +78,7 @@ setscript(struct attrib ** ap, void * fptr)
if (a == NULL) {
a = a_add(ap, a_new(&at_script));
} else if (a->data.v!=NULL) {
luabind::object * f = (luabind::object *)a->data.v;
object * f = (object *)a->data.v;
delete f;
}
a->data.v = fptr;
@ -96,9 +99,9 @@ lua_callspell(castorder *co)
lua_State * L = (lua_State *)global.vm_state;
if (is_function(L, fname)) {
try {
retval = luabind::call_function<int>(L, fname, co->rt, mage, co->level, co->force);
retval = call_function<int>(L, fname, co->rt, mage, co->level, co->force);
}
catch (luabind::error& e) {
catch (error& e) {
lua_State* L = e.state();
const char* error = lua_tostring(L, -1);
log_error(("An exception occured while %s tried to call '%s': %s.\n",
@ -121,9 +124,9 @@ lua_useitem(struct unit * u, const struct item_type * itype, int amount, struct
lua_State * L = (lua_State *)global.vm_state;
if (is_function(L, fname)) {
try {
retval = luabind::call_function<int>(L, fname, u, amount);
retval = call_function<int>(L, fname, u, amount);
}
catch (luabind::error& e) {
catch (error& e) {
lua_State* L = e.state();
const char* error = lua_tostring(L, -1);
log_error(("An exception occured while %s tried to call '%s': %s.\n",
@ -145,9 +148,9 @@ lua_initfamiliar(unit * u)
lua_State * L = (lua_State *)global.vm_state;
if (is_function(L, fname)) {
try {
luabind::call_function<int>(L, fname, u);
call_function<int>(L, fname, u);
}
catch (luabind::error& e) {
catch (error& e) {
lua_State* L = e.state();
const char* error = lua_tostring(L, -1);
log_error(("An exception occured while %s tried to call '%s': %s.\n",
@ -171,9 +174,9 @@ lua_changeresource(unit * u, const struct resource_type * rtype, int delta)
lua_State * L = (lua_State *)global.vm_state;
if (is_function(L, fname)) {
try {
retval = luabind::call_function<int>(L, fname, u, delta);
retval = call_function<int>(L, fname, u, delta);
}
catch (luabind::error& e) {
catch (error& e) {
lua_State* L = e.state();
const char* error = lua_tostring(L, -1);
log_error(("An exception occured while %s tried to call '%s': %s.\n",
@ -189,17 +192,17 @@ bool
is_function(struct lua_State * luaState, const char * fname)
{
#if BOOST_VERSION > 103002
luabind::object globals = luabind::globals(luaState);
luabind::object fun = globals[fname];
object globals = globals(luaState);
object fun = globals[fname];
if (fun.is_valid()) {
if (luabind::type(fun)==LUA_TFUNCTION) {
if (type(fun)==LUA_TFUNCTION) {
return true;
}
log_warning(("Lua global object %s is not a function, type is %u\n", fname, luabind::type(fun)));
log_warning(("Lua global object %s is not a function, type is %u\n", fname, type(fun)));
}
#else
luabind::object globals = luabind::get_globals(luaState);
luabind::object fun = globals[fname];
object globals = get_globals(luaState);
object fun = globals[fname];
if (fun.is_valid()) {
if (fun.type()==LUA_TFUNCTION) {
return true;
@ -220,9 +223,9 @@ lua_getresource(unit * u, const struct resource_type * rtype)
lua_State * L = (lua_State *)global.vm_state;
if (is_function(L, fname)) {
try {
retval = luabind::call_function<int>(L, fname, u);
retval = call_function<int>(L, fname, u);
}
catch (luabind::error& e) {
catch (error& e) {
lua_State* L = e.state();
const char* error = lua_tostring(L, -1);
log_error(("An exception occured while %s tried to call '%s': %s.\n",
@ -234,6 +237,69 @@ lua_getresource(unit * u, const struct resource_type * rtype)
return retval;
}
struct script_interface {
void destroy() {
delete wage;
wage = 0;
delete maintenance;
maintenance = 0;
}
object * wage;
object * maintenance;
};
static script_interface interface;
static int
lua_wage(const region * r, const faction * f, const race * rc)
{
int retval = -1;
assert(interface.wage);
try {
retval = object_cast<int>(interface.wage->operator()(r, f, rc));
}
catch (error& e) {
lua_State* L = e.state();
const char* error = lua_tostring(L, -1);
log_error(("An exception occured in interface 'wage': %s.\n", error));
lua_pop(L, 1);
std::terminate();
}
return retval;
}
static int
lua_maintenance(const unit * u)
{
int retval = -1;
assert(interface.maintenance);
try {
retval = object_cast<int>(interface.maintenance->operator()(u));
}
catch (error& e) {
lua_State* L = e.state();
const char* error = lua_tostring(L, -1);
log_error(("An exception occured in interface 'maintenance': %s.\n", error));
lua_pop(L, 1);
std::terminate();
}
return retval;
}
static void
overload(const char * name, const object& f)
{
if (strcmp(name, "wage")==0) {
global.functions.wage = &lua_wage;
interface.wage = new object(f);;
} else if (strcmp(name, "maintenance")==0) {
global.functions.maintenance = &lua_maintenance;
interface.maintenance = new object(f);;
}
}
void
bind_script(lua_State * L)
{
@ -242,4 +308,14 @@ bind_script(lua_State * L)
register_function((pf_generic)&lua_useitem, "lua_useitem");
register_function((pf_generic)&lua_getresource, "lua_getresource");
register_function((pf_generic)&lua_changeresource, "lua_changeresource");
module(L)[
def("overload", &overload)
];
}
void
reset_scripts()
{
interface.destroy();
}

View file

@ -16,5 +16,6 @@ extern int call_script(struct unit * u);
extern void setscript(struct attrib ** ap, void * fptr);
extern bool is_function(struct lua_State * luaState, const char * fname);
extern void reset_scripts();
#endif

View file

@ -94,6 +94,7 @@
/* lua includes */
#include "lua/bindings.h"
#include "lua/script.h"
#include <boost/version.hpp>
#include <lua.hpp>
#include <luabind/luabind.hpp>
@ -320,6 +321,7 @@ lua_init(void)
void
lua_done(lua_State * luaState)
{
reset_scripts();
lua_close(luaState);
}

View file

@ -22,6 +22,37 @@
<!-- Game specific settings -->
<order name="MEINUNG" disable="yes"/>
<order name="MAGIEGEBIET" disable="yes"/>
<skill name="alchemy" enable="true"/>
<skill name="crossbow" enable="true"/>
<skill name="mining" enable="true"/>
<skill name="bow" enable="true"/>
<skill name="building" enable="true"/>
<skill name="trade" enable="true"/>
<skill name="forestry" enable="true"/>
<skill name="catapult" enable="true"/>
<skill name="herbalism" enable="true"/>
<skill name="magic" enable="true"/>
<skill name="training" enable="true"/>
<skill name="riding" enable="true"/>
<skill name="armorer" enable="true"/>
<skill name="shipcraft" enable="true"/>
<skill name="melee" enable="true"/>
<skill name="sailing" enable="true"/>
<skill name="polearm" enable="true"/>
<skill name="espionage" enable="true"/>
<skill name="quarrying" enable="true"/>
<skill name="roadwork" enable="true"/>
<skill name="tactics" enable="true"/>
<skill name="stealth" enable="true"/>
<skill name="entertainment" enable="true"/>
<skill name="weaponsmithing" enable="true"/>
<skill name="cartmaking" enable="true"/>
<skill name="perception" enable="true"/>
<skill name="taxation" enable="true"/>
<skill name="stamina" enable="true"/>
<skill name="unarmed" enable="true"/>
<param name="entertain.base" value="0"/>
<param name="entertain.perlevel" value="20"/>
<param name="nmr.timeout" value="4"/>

View file

@ -26,6 +26,37 @@
<order name="MEINUNG" disable="yes"/>
<order name="NUMMER" disable="yes"/>
<order name="MAGIEGEBIET" disable="yes"/>
<skill name="alchemy" enable="true"/>
<skill name="crossbow" enable="true"/>
<skill name="mining" enable="true"/>
<skill name="bow" enable="true"/>
<skill name="building" enable="true"/>
<skill name="trade" enable="true"/>
<skill name="forestry" enable="true"/>
<skill name="catapult" enable="true"/>
<skill name="herbalism" enable="true"/>
<skill name="magic" enable="true"/>
<skill name="training" enable="true"/>
<skill name="riding" enable="true"/>
<skill name="armorer" enable="true"/>
<skill name="shipcraft" enable="true"/>
<skill name="melee" enable="true"/>
<skill name="sailing" enable="true"/>
<skill name="polearm" enable="true"/>
<skill name="espionage" enable="true"/>
<skill name="quarrying" enable="true"/>
<skill name="roadwork" enable="true"/>
<skill name="tactics" enable="true"/>
<skill name="stealth" enable="true"/>
<skill name="entertainment" enable="true"/>
<skill name="weaponsmithing" enable="true"/>
<skill name="cartmaking" enable="true"/>
<skill name="perception" enable="true"/>
<skill name="taxation" enable="true"/>
<skill name="stamina" enable="true"/>
<skill name="unarmed" enable="true"/>
<param name="entertain.base" value="15"/>
<param name="entertain.perlevel" value="5"/>
<param name="nmr.timeout" value="20"/>

View file

@ -26,9 +26,41 @@
<game name="HSE4" welcome="eressea">
<comment>Game specific</comment>
<order name="MEINUNG" disable="yes"/>
<order name="NUMMER" disable="yes"/>
<order name="MAGIEGEBIET" disable="yes"/>
<skill name="alchemy" enable="true"/>
<skill name="crossbow" enable="true"/>
<skill name="mining" enable="true"/>
<skill name="bow" enable="true"/>
<skill name="building" enable="true"/>
<skill name="trade" enable="true"/>
<skill name="forestry" enable="true"/>
<skill name="catapult" enable="true"/>
<skill name="herbalism" enable="true"/>
<skill name="magic" enable="true"/>
<skill name="training" enable="true"/>
<skill name="riding" enable="true"/>
<skill name="armorer" enable="true"/>
<skill name="shipcraft" enable="true"/>
<skill name="melee" enable="true"/>
<skill name="sailing" enable="true"/>
<skill name="polearm" enable="true"/>
<skill name="espionage" enable="true"/>
<skill name="quarrying" enable="true"/>
<skill name="roadwork" enable="true"/>
<skill name="tactics" enable="true"/>
<skill name="stealth" enable="true"/>
<skill name="entertainment" enable="true"/>
<skill name="weaponsmithing" enable="true"/>
<skill name="cartmaking" enable="true"/>
<skill name="perception" enable="true"/>
<skill name="taxation" enable="true"/>
<skill name="stamina" enable="true"/>
<skill name="unarmed" enable="true"/>
<param name="entertain.base" value="15"/>
<param name="entertain.perlevel" value="5"/>
<param name="nmr.timeout" value="20"/>

View file

@ -23,6 +23,37 @@
<order name="EMAIL" disable="yes"></order>
<order name="MEINUNG" disable="yes"></order>
<order name="MAGIEGEBIET" disable="yes"></order>
<skill name="alchemy" enable="true"/>
<skill name="crossbow" enable="true"/>
<skill name="mining" enable="true"/>
<skill name="bow" enable="true"/>
<skill name="building" enable="true"/>
<skill name="trade" enable="true"/>
<skill name="forestry" enable="true"/>
<skill name="catapult" enable="true"/>
<skill name="herbalism" enable="true"/>
<skill name="magic" enable="true"/>
<skill name="training" enable="true"/>
<skill name="riding" enable="true"/>
<skill name="armorer" enable="true"/>
<skill name="shipcraft" enable="true"/>
<skill name="melee" enable="true"/>
<skill name="sailing" enable="true"/>
<skill name="polearm" enable="true"/>
<skill name="espionage" enable="true"/>
<skill name="quarrying" enable="true"/>
<skill name="roadwork" enable="true"/>
<skill name="tactics" enable="true"/>
<skill name="stealth" enable="true"/>
<skill name="entertainment" enable="true"/>
<skill name="weaponsmithing" enable="true"/>
<skill name="cartmaking" enable="true"/>
<skill name="perception" enable="true"/>
<skill name="taxation" enable="true"/>
<skill name="stamina" enable="true"/>
<skill name="unarmed" enable="true"/>
<param name="entertain.base" value="0"></param>
<param name="entertain.perlevel" value="20"></param>
<param name="nmr.timeout" value="2"></param>

View file

@ -22,6 +22,37 @@
<order name="ARBEITEN" disable="yes"/>
<order name="MEINUNG" disable="yes"/>
<order name="MAGIEGEBIET" disable="yes"/>
<skill name="alchemy" enable="true"/>
<skill name="crossbow" enable="true"/>
<skill name="mining" enable="true"/>
<skill name="bow" enable="true"/>
<skill name="building" enable="true"/>
<skill name="trade" enable="true"/>
<skill name="forestry" enable="true"/>
<skill name="catapult" enable="true"/>
<skill name="herbalism" enable="true"/>
<skill name="magic" enable="true"/>
<skill name="training" enable="true"/>
<skill name="riding" enable="true"/>
<skill name="armorer" enable="true"/>
<skill name="shipcraft" enable="true"/>
<skill name="melee" enable="true"/>
<skill name="sailing" enable="true"/>
<skill name="polearm" enable="true"/>
<skill name="espionage" enable="true"/>
<skill name="quarrying" enable="true"/>
<skill name="roadwork" enable="true"/>
<skill name="tactics" enable="true"/>
<skill name="stealth" enable="true"/>
<skill name="entertainment" enable="true"/>
<skill name="weaponsmithing" enable="true"/>
<skill name="cartmaking" enable="true"/>
<skill name="perception" enable="true"/>
<skill name="taxation" enable="true"/>
<skill name="stamina" enable="true"/>
<skill name="unarmed" enable="true"/>
<param name="entertain.base" value="15"/>
<param name="entertain.perlevel" value="5"/>
<param name="nmr.timeout" value="5"/>