Merge pull request #649 from ennorehling/spellref

allow forward references to spells in configuration data.
This commit is contained in:
Enno Rehling 2017-02-02 20:25:56 +01:00 committed by GitHub
commit d81cb0f9a0
34 changed files with 228 additions and 299 deletions

2
clibs

@ -1 +1 @@
Subproject commit f91ef37f08c5244bf616f1836c0aa9caaf36805c
Subproject commit 27c8b3202b52766465743c3324fc0b52c5ba4b11

2
cmake

@ -1 +1 @@
Subproject commit f1fb3943ace59994d90d71a891b80033dc2700a2
Subproject commit d88983c7ff4bc3a4884a7c3f74e8190bac5eab23

View File

@ -8,6 +8,8 @@
"jsreport"
],
"settings": {
"game.name" : "Eressea",
"game.id" : 2,
"orders.default": "work",
"NewbieImmunity": 8,
"modules.wormholes": true,

View File

@ -25,6 +25,8 @@
"jsreport"
],
"settings": {
"game.name" : "Eressea",
"game.id" : 3,
"orders.default": "work",
"database.gameid": 7,
"NewbieImmunity": 4,

View File

@ -1,16 +0,0 @@
<?xml version="1.0"?>
<!DOCTYPE catalog
PUBLIC "-//OASIS/DTD Entity Resolution XML Catalog V1.0//EN"
"http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd">
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
<rewriteURI
uriStartString="config://core/"
rewritePrefix="../../res/core/" />
<rewriteURI
uriStartString="config://game/"
rewritePrefix="../../res/e3a/" />
<rewriteURI
uriStartString="config://default/"
rewritePrefix="../../res/" />
</catalog>

View File

@ -1,93 +0,0 @@
{
"include": [
"keywords.json",
"prefixes.json",
"e3/terrains.json"
],
"disabled": [
"herbalism",
"alchemy",
"entertainment",
"espionage",
"perception",
"stealth",
"taxation",
"trade",
"besiege",
"steal",
"buy",
"teach",
"sabotage",
"spy",
"tax",
"entertain",
"sell",
"jsreport"
],
"settings": {
"orders.default": "work",
"database.gameid": 7,
"NewbieImmunity": 4,
"modules.astralspace": false,
"modules.wormholes": false,
"modules.markets": true,
"magic.regeneration": 0.75,
"magic.power": 0.5,
"resource.factor": 0.25,
"skills.cost.tactics": 500,
"entertain.base": 0,
"entertain.perlevel": 20,
"nmr.timeout": 5,
"nmr.removenewbie": 0,
"GiveRestriction": 3,
"hunger.long": false,
"hunger.damage": "1d9+9",
"hunger.demons.skill": true,
"hunger.demons.peasant_tolerance": true,
"init_spells": 0,
"recruit.allow_merge": true,
"study.expensivemigrants": true,
"study.speedup": 2,
"study.produceexp": 12,
"world.era": 3,
"rules.reserve.twophase": true,
"rules.owners.force_leave": false,
"rules.transfermen": false,
"stealth.faction.other": false,
"rules.stealth.anon_battle": false,
"rules.check_overload": false,
"rules.combat.goblinbonus": 3,
"rules.alliances": true,
"rules.combat.herospeed": 3,
"rules.combat.demon_vampire": 5,
"rules.combat.skill_bonus": 0,
"rules.combat.nat_armor": 1,
"rules.items.loot_divisor": 2,
"rules.items.give_divisor": 2,
"rules.move.owner_leave": true,
"rules.region_owners": true,
"rules.cavalry.skill": 2,
"rules.cavalry.mode": 1,
"rules.magic.multipotion": true,
"rules.magic.wol_effect": 5,
"rules.magic.factionlist": true,
"rules.magic.wol_type": 2,
"rules.blessed_harvest.flags": 1,
"rules.magic.elfpower": true,
"rules.magic.playerschools": "gwyrrd illaun draig cerddor",
"rules.build.other_buildings": true,
"rules.economy.taxation": 1,
"rules.food.flags": 2,
"rules.economy.roqf": 5,
"rules.economy.herbrot": 0,
"rules.region_owner_pay_building": "market harbour lighthouse",
"rules.dwarf_castles": true,
"rules.limit.faction": 250,
"rules.grow.formula": 1,
"rules.tactics.formula": 1,
"rules.help.mask": "fight guard money give",
"movement.shipspeed.skillbonus": 6,
"alliance.auto": "fight",
"alliance.restricted": "fight"
}
}

View File

@ -1,39 +0,0 @@
<?xml version="1.0"?>
<eressea xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="config://core/messages.xml"/>
<xi:include href="config://core/de/strings.xml"/>
<xi:include href="config://core/en/strings.xml"/>
<xi:include href="config://core/common/items.xml"/>
<xi:include href="config://core/common/herbs.xml" />
<xi:include href="config://core/spoils.xml"/>
<xi:include href="config://core/common/buildings.xml"/>
<xi:include href="config://game/familiars.xml"/>
<xi:include href="config://default/adamantium.xml" />
<xi:include href="config://game/ships.xml"/>
<xi:include href="config://game/shipnames.xml"/>
<xi:include href="config://core/calendar.xml"/>
<xi:include href="config://game/items.xml" />
<xi:include href="config://game/strings.xml"/>
<xi:include href="config://game/messages.xml"/>
<xi:include href="config://game/races.xml"/>
<xi:include href="config://game/buildings.xml"/>
<xi:include href="config://game/equipment.xml"/>
<xi:include href="config://game/spells.xml"/>
<xi:include href="config://game/luxuries.xml" />
<xi:include href="config://game/weapons.xml" />
<xi:include href="config://game/armor.xml" />
<xi:include href="config://game/resources.xml" />
<calendar name="thirdage" newyear="month_1" start="1"/>
<xi:include href="config://default/names-undead.xml"/>
<xi:include href="config://default/names-skeletons.xml"/>
<xi:include href="config://default/names-zombies.xml"/>
<xi:include href="config://default/names-ghouls.xml"/>
<xi:include href="config://default/names-dragons.xml"/>
<rules>
<function name="wage" value="minimum_wage"/>
</rules>
</eressea>

11
s/build
View File

@ -1,8 +1,5 @@
#!/bin/sh
ROOT=`pwd`
while [ ! -d $ROOT/.git ]; do
ROOT=`dirname $ROOT`
done
ROOT=$(git rev-parse --show-toplevel)
[ -z "$BUILD" ] && BUILD=Debug
if [ -z "$JOBS" ] ; then
@ -35,7 +32,13 @@ fi
echo "build eressea"
cd $ROOT/$BUILD
BRANCH=$(git status -s -b | head -1 | cut -d\ -f 2 | sed 's/\..*//')
if [ "$BRANCH"=="master" ] ; then
VERSION=$(git describe --match 'v*.*.*' --tags | sed 's/^v//')
cmake -DERESSEA_VERSION="$VERSION" ..
else
REV=$(git rev-parse --short HEAD)
cmake -DERESSEA_BUILDNO="$REV" ..
fi
make $MAKEOPTS && make test
cd $OLDPWD

View File

@ -1,13 +1,6 @@
#!/bin/sh
ROOT=$(pwd)
while [ ! -d $ROOT/.git ]; do
ROOT=$(dirname $ROOT)
if [ "$ROOT" == "/" ; then
echo "could not find root, are you in the git repository?"
exit
fi
done
ROOT=$(git rev-parse --show-toplevel)
[ -z $BUILD ] && BUILD=Debug
[ -z "$CC" ] && [ ! -z `which clang` ] && CC="clang"
[ -z "$CC" ] && [ ! -z `which gcc` ] && CC="gcc"

View File

@ -1,11 +1,7 @@
#!/bin/bash
set -e
ROOT=$(pwd)
while [ ! -d $ROOT/.git ]; do
ROOT=$(dirname $ROOT)
done
ROOT=$(git rev-parse --show-toplevel)
[ -z $BUILD ] && BUILD=Debug ; export BUILD
if [ ! -e $ROOT/$BUILD ]; then
@ -19,7 +15,6 @@ cd $ROOT
$ROOT/$BUILD/eressea/eressea -v1 scripts/run-tests.lua
$ROOT/$BUILD/eressea/eressea -v1 scripts/run-tests-e2.lua
$ROOT/$BUILD/eressea/eressea -v1 scripts/run-tests-e3.lua
$ROOT/$BUILD/eressea/eressea -v1 scripts/run-tests-e4.lua
rm -rf data reports orders.txt score score.alliances datum turn
cd $OLDWPD

14
s/upgrade Executable file
View File

@ -0,0 +1,14 @@
#!/bin/sh
set -e
ROOT=`pwd`
while [ ! -d $ROOT/.git ]; do
ROOT=`dirname $ROOT`
done
cd $ROOT
git pull
git submodule update
s/build
s/runtests
s/install

View File

@ -1,11 +0,0 @@
require 'eressea.e3.rules'
require 'eressea.spells'
eressea.log.debug("rules for game E4")
return {
require('eressea'),
-- require('eressea.markets'),
require('eressea.frost'),
require('eressea.ents')
}

View File

@ -1,23 +0,0 @@
-- Tests that work in E3. With game config of E3.
-- Tests are under scripts/test/e3 and all files must be in scripts/test/e3/init.lua
path = 'scripts'
if config.install then
path = config.install .. '/' .. path
package.path = package.path .. ';' .. config.install .. '/lunit/?.lua'
--needed to find lunit if not run form eressea root. Needs right [lua] install setting in eressea.ini (point to eressea root from the start folder)
end
package.path = package.path .. ';' .. path .. '/?.lua;' .. path .. '/?/init.lua'
config.rules = 'e4'
require 'eressea'
require 'eressea.path'
require 'eressea.xmlconf'
require 'tests.e3'
require 'lunit'
eressea.settings.set("rules.alliances", "0")
rules = require('eressea.' .. config.rules)
result = lunit.main()
return result.errors + result.failed

View File

@ -15,6 +15,11 @@ set_source_files_properties(kernel/version.c PROPERTIES
COMPILE_DEFINITIONS ERESSEA_VERSION="${ERESSEA_VERSION}")
ENDIF()
IF(DEFINED ERESSEA_BUILDNO)
set_source_files_properties(kernel/version.c PROPERTIES
COMPILE_DEFINITIONS ERESSEA_BUILDNO="${ERESSEA_BUILDNO}")
ENDIF()
IF (CMAKE_COMPILER_IS_GNUCC)
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-error=unused-but-set-variable")
ENDIF()

View File

@ -1858,10 +1858,13 @@ static void do_combatspell(troop at)
static void do_extra_spell(troop at, const att * a)
{
const spell *sp = a->data.sp;
const spell *sp = spellref_get(a->data.sp);
if (sp->cast == NULL) {
log_error("spell '%s' has no function.\n", sp->sname);
if (!sp) {
log_error("no such spell: '%s'", a->data.sp->name);
}
else if (sp->cast == NULL) {
log_error("spell '%s' has no function.", sp->sname);
}
else {
assert(a->level > 0);

View File

@ -718,6 +718,7 @@ static void cr_output_spells(stream *out, const unit * u, int maxlevel)
for (ql = book->spells, qi = 0; ql; selist_advance(&ql, &qi, 1)) {
spellbook_entry * sbe = (spellbook_entry *)selist_get(ql, qi);
if (sbe->level <= maxlevel) {
// TODO: no need to deref spref here, spref->name == sp->sname
spell * sp = sbe->sp;
const char *name = translate(mkname("spell", sp->sname), spell_name(sp, f->locale));
if (!header) {

View File

@ -749,13 +749,18 @@ void config_set_from(const dictionary *d)
key[slen] = '.';
iniparser_getseckeys(d, sec, keys);
for (k=0;k!=nkeys;++k) {
const char *val;
const char *val, *orig;
size_t klen = strlen(keys[k]);
assert(klen+slen+1<sizeof(key));
memcpy(key+slen+1, keys[k]+slen+1, klen-slen);
orig = config_get(key);
val = iniparser_getstring(d, keys[k], NULL);
if (val) {
config_set(key, val);
if (!orig) {
if (val) {
config_set(key, val);
}
} else {
log_debug("not overwriting %s=%s with %s", key, orig, val);
}
}
}

View File

@ -87,8 +87,7 @@ void equipment_setskill(equipment * eq, skill_t sk, const char *value)
}
typedef struct lazy_spell {
char *name;
struct spell *sp;
struct spellref *spref;
int level;
} lazy_spell;
@ -96,9 +95,8 @@ void equipment_addspell(equipment * eq, const char * name, int level)
{
if (eq) {
lazy_spell *ls = malloc(sizeof(lazy_spell));
ls->sp = NULL;
ls->spref = spellref_create(NULL, name);
ls->level = level;
ls->name = strdup(name);
selist_push(&eq->spells, ls);
}
}
@ -162,12 +160,8 @@ void equip_unit_mask(struct unit *u, const struct equipment *eq, int mask)
for (qi = 0; ql; selist_advance(&ql, &qi, 1)) {
lazy_spell *sbe = (lazy_spell *)selist_get(ql, qi);
if (!sbe->sp) {
sbe->sp = find_spell(sbe->name);
free(sbe->name);
sbe->name = NULL;
}
unit_add_spell(u, mage, sbe->sp, sbe->level);
spell *sp = spellref_get(sbe->spref);
unit_add_spell(u, mage, sp, sbe->level);
}
}
}
@ -238,7 +232,7 @@ void equip_items(struct item **items, const struct equipment *eq)
void free_ls(void *arg) {
lazy_spell *ls = (lazy_spell*)arg;
free(ls->name);
spellref_free(ls->spref);
free(ls);
}

View File

@ -32,6 +32,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "region.h"
#include "ship.h"
#include "skill.h"
#include "spell.h"
#include "terrain.h"
#include "unit.h"
@ -181,7 +182,13 @@ void racelist_insert(struct race_list **rl, const struct race *r)
void free_races(void) {
while (races) {
int i;
race * rc = races->next;
for (i = 0; races->attack[i].type!=AT_NONE; ++i) {
spellref_free(races->attack[i].data.sp);
}
spellref_free(races->precombatspell);
free_params(&races->parameters);
free(xrefs);
xrefs = 0;

View File

@ -45,6 +45,7 @@ extern "C" {
struct param;
struct spell;
struct spellref;
struct locale;
extern int num_races;
@ -104,7 +105,7 @@ extern "C" {
int type;
union {
const char *dice;
const struct spell *sp;
struct spellref *sp;
} data;
int flags;
int level;
@ -137,7 +138,7 @@ extern "C" {
int at_bonus; /* Ver<65>ndert den Angriffsskill (default: 0) */
int df_bonus; /* Ver<65>ndert den Verteidigungskill (default: 0) */
struct param *parameters; // additional properties, for an example see natural_armor
const struct spell *precombatspell;
struct spellref *precombatspell;
signed char *study_speed; /* study-speed-bonus in points/turn (0=30 Tage) */
int flags;
int battle_flags;

View File

@ -1633,14 +1633,7 @@ int read_game(gamedata *data) {
READ_INT(store, &gameid);
if (gameid != game_id()) {
int c;
log_warning("game mismatch: datafile contains game %d, but config is for %d", gameid, game_id());
printf("WARNING: invalid game id. any key to continue, Ctrl-C to stop\n");
c = getchar();
if (c == EOF) {
log_error("aborting.");
abort();
}
}
}
else {

View File

@ -145,3 +145,39 @@ spell *find_spellbyid(unsigned int id)
log_warning("cannot find spell by id: %u\n", id);
return NULL;
}
struct spellref *spellref_create(spell *sp, const char *name)
{
spellref *spref = malloc(sizeof(spellref));
if (sp) {
spref->sp = sp;
spref->name = strdup(sp->sname);
}
else if (name) {
spref->name = strdup(name);
spref->sp = NULL;
}
return spref;
}
void spellref_free(spellref *spref)
{
if (spref) {
free(spref->name);
free(spref);
}
}
struct spell *spellref_get(struct spellref *spref)
{
if (!spref->sp) {
assert(spref->name);
spref->sp = find_spell(spref->name);
if (spref->sp) {
free(spref->name);
spref->name = NULL;
}
}
return spref->sp;
}

View File

@ -45,6 +45,15 @@ extern "C" {
fumble_f fumble;
} spell;
typedef struct spellref {
char * name;
struct spell *sp;
} spellref;
struct spellref *spellref_create(struct spell *sp, const char *name);
void spellref_free(struct spellref *spref);
struct spell *spellref_get(struct spellref *spref);
int sp_antimagiczone(struct castorder *co);
struct spell * create_spell(const char * name, unsigned int id);
@ -61,7 +70,7 @@ extern "C" {
}
#endif
#endif
/* ------------------------------------------------------------- *//* Erläuterungen zu den Spruchdefinitionen
/* ------------------------------------------------------------- *//* Erl<EFBFBD>uterungen zu den Spruchdefinitionen
*
* Spruchstukturdefinition:
* spell{
@ -79,35 +88,35 @@ extern "C" {
* id:
* SPL_NOSPELL muss der letzte Spruch in der Liste spelldaten sein,
* denn nicht auf die Reihenfolge in der Liste sondern auf die id wird
* geprüft
* gepr<EFBFBD>ft
*
* sptyp:
* besondere Spruchtypen und Flags
* (Regionszauber, Kampfzauber, Farcastbar, Stufe variable, ..)
*
* rank:
* gibt die Priorität und damit die Reihenfolge an, in der der Spruch
* gibt die Priorit<EFBFBD>t und damit die Reihenfolge an, in der der Spruch
* gezaubert wird.
* 1: Aura übertragen
* 1: Aura <EFBFBD>bertragen
* 2: Antimagie
* 3: Magierverändernde Sprüche (Magic Boost, ..)
* 3: Magierver<EFBFBD>ndernde Spr<EFBFBD>che (Magic Boost, ..)
* 4: Monster erschaffen
* 5: Standartlevel
* 7: Teleport
*
* Komponenten[Anzahl mögl. Items][Art:Anzahl:Kostentyp]
* Komponenten[Anzahl m<EFBFBD>gl. Items][Art:Anzahl:Kostentyp]
*
* R_AURA:
* Grundkosten für einen Zauber. Soviel Mp ssen mindestens investiert
* werden, um den Spruch zu wirken. Zusätzliche Mp nnen unterschiedliche
* Grundkosten f<EFBFBD>r einen Zauber. Soviel Mp m<EFBFBD>ssen mindestens investiert
* werden, um den Spruch zu wirken. Zus<EFBFBD>tzliche Mp k<EFBFBD>nnen unterschiedliche
* Auswirkungen haben, die in der Spruchfunktionsroutine definiert werden.
*
* R_PERMAURA:
* Kosten an permantenter Aura
*
* Komponenten Kostentyp:
* SPC_LEVEL == Spruch mit Levelabhängigen Magiekosten. Die angegeben
* Kosten müssen r Stufe 1 berechnet sein.
* SPC_LEVEL == Spruch mit Levelabh<EFBFBD>ngigen Magiekosten. Die angegeben
* Kosten m<EFBFBD>ssen f<EFBFBD>r Stufe 1 berechnet sein.
* SPC_FIX == Feste Kosten
*
* Wenn keine spezielle Syntax angegeben ist, wird die
@ -128,34 +137,34 @@ extern "C" {
*
* u : eine Einheitennummer
* r : hier kommen zwei Regionskoordinaten x y
* b : Gebäude- oder Burgnummer
* b : Geb<EFBFBD>ude- oder Burgnummer
* s : Schiffsnummer
* c : String, wird ohne Weiterverarbeitung übergeben
* i : Zahl (int), wird ohne Weiterverarbeitung übergeben
* c : String, wird ohne Weiterverarbeitung <EFBFBD>bergeben
* i : Zahl (int), wird ohne Weiterverarbeitung <EFBFBD>bergeben
* k : Keywort - dieser String gibt den Paramter an, der folgt. Der
* Parameter wird mit findparam() identifiziert.
* k muss immer von einem c als Platzhalter für das Objekt gefolgt
* k muss immer von einem c als Platzhalter f<EFBFBD>r das Objekt gefolgt
* werden.
* Ein gutes Beispiel sind hierfür die Sprüche zur Magieanalyse.
* Ein gutes Beispiel sind hierf<EFBFBD>r die Spr<EFBFBD>che zur Magieanalyse.
* + : gibt an, das der vorherige Parameter mehrfach vorkommen kann. Da
* ein Ende nicht definiert werden kann, muss dies immer am Schluss
* kommen.
*
* Flags für das Parsing:
* Flags f<EFBFBD>r das Parsing:
* TESTRESISTANCE : alle Zielobjekte, also alle Parameter vom Typ Unit,
* Burg, Schiff oder Region, werden auf ihre
* Magieresistenz überprüft
* Magieresistenz <EFBFBD>berpr<EFBFBD>ft
* TESTCANSEE : jedes Objekt vom Typ Einheit wird auf seine
* Sichtbarkeit überprüft
* Sichtbarkeit <EFBFBD>berpr<EFBFBD>ft
* SEARCHLOCAL : die Zielobjekte werden nur regional gesucht
* REGIONSPELL : Ziel ist die Region, auch wenn kein Zielobjekt
* angegeben wird. Ist TESTRESISTANCE gesetzt, so wird
* die Magieresistenz der Region überprüft
* die Magieresistenz der Region <EFBFBD>berpr<EFBFBD>ft
*
* Bei fehlendem Ziel oder wenn dieses dem Zauber widersteht, wird die
* Spruchfunktion nicht aufgerufen.
* Sind zu wenig Parameter vorhanden, wird der Zauber ebenfalls nicht
* ausgeführt.
* ausgef<EFBFBD>hrt.
* Ist eins von mehreren Zielobjekten resistent, so wird das Flag
* pa->param[n]->flag == TARGET_RESISTS
* Ist eins von mehreren Zielobjekten nicht gefunden worden, so ist

View File

@ -69,9 +69,27 @@ static void test_create_spell_with_id(CuTest * tc)
test_cleanup();
}
static void test_spellref(CuTest *tc)
{
spellref *ref;
spell *sp;
test_setup();
ref = spellref_create(NULL, "hodor");
CuAssertPtrNotNull(tc, ref);
CuAssertPtrEquals(tc, NULL, ref->sp);
CuAssertStrEquals(tc, "hodor", ref->name);
CuAssertPtrEquals(tc, NULL, spellref_get(ref));
sp = create_spell("hodor", 0);
CuAssertPtrNotNull(tc, sp);
CuAssertPtrEquals(tc, sp, spellref_get(ref));
spellref_free(ref);
test_cleanup();
}
CuSuite *get_spell_suite(void)
{
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_spellref);
SUITE_ADD_TEST(suite, test_create_a_spell);
SUITE_ADD_TEST(suite, test_create_duplicate_spell);
SUITE_ADD_TEST(suite, test_create_spell_with_id);

View File

@ -71,7 +71,7 @@ void write_spellbook(const struct spellbook *book, struct storage *store)
WRITE_TOK(store, "end");
}
void spellbook_add(spellbook *sb, struct spell * sp, int level)
void spellbook_add(spellbook *sb, spell *sp, int level)
{
spellbook_entry * sbe;
@ -116,7 +116,7 @@ int spellbook_foreach(spellbook *sb, int(*callback)(spellbook_entry *, void *),
return 0;
}
spellbook_entry * spellbook_get(spellbook *sb, const struct spell * sp)
spellbook_entry * spellbook_get(spellbook *sb, const struct spell *sp)
{
if (sb) {
selist *ql;
@ -124,11 +124,10 @@ spellbook_entry * spellbook_get(spellbook *sb, const struct spell * sp)
for (qi = 0, ql = sb->spells; ql; selist_advance(&ql, &qi, 1)) {
spellbook_entry *sbe = (spellbook_entry *)selist_get(ql, qi);
if (sp == sbe->sp) {
if (sbe->sp==sp) {
return sbe;
}
}
}
return 0;
}

View File

@ -29,7 +29,7 @@ extern "C" {
struct selist;
typedef struct spellbook_entry {
struct spell * sp;
struct spell *sp;
int level;
} spellbook_entry;
@ -44,10 +44,10 @@ extern "C" {
void read_spellbook(struct spellbook **bookp, struct gamedata *data, int(*get_level)(const struct spell * sp, void *), void * cbdata);
void write_spellbook(const struct spellbook *book, struct storage *store);
void spellbook_add(spellbook *sbp, struct spell * sp, int level);
void spellbook_add(spellbook *sbp, struct spell *sp, int level);
int spellbook_foreach(spellbook *sb, int(*callback)(spellbook_entry *, void *), void * data);
void spellbook_clear(spellbook *sb);
spellbook_entry * spellbook_get(spellbook *sb, const struct spell * sp);
spellbook_entry * spellbook_get(spellbook *sb, const struct spell *sp);
#ifdef __cplusplus
}

View File

@ -5,15 +5,18 @@
#ifndef ERESSEA_VERSION
// the version number, if it was not passed to make with -D
#define ERESSEA_VERSION "3.11.0-devel"
#define ERESSEA_VERSION "3.11.0"
#endif
const char *eressea_version(void) {
#ifdef ERESSEA_BUILDNO
return ERESSEA_VERSION "-" ERESSEA_BUILDNO;
#endif
return ERESSEA_VERSION;
}
int version_no(const char *str) {
int maj = 0, min = 0, bld = 0;
sscanf(str, "%d.%d.%d", &maj, &min, &bld);
return (maj << 16) | (min << 8) | bld;
int maj = 0, min = 0, pat = 0;
sscanf(str, "%d.%d.%d", &maj, &min, &pat);
return (maj << 16) | (min << 8) | pat;
}

View File

@ -75,16 +75,15 @@ static void xml_readtext(xmlNodePtr node, struct locale **lang, xmlChar ** text)
*text = xmlNodeListGetString(node->doc, node->children, 1);
}
static const spell *xml_spell(xmlNode * node, const char *name)
static spellref *xml_spellref(xmlNode * node, const char *name)
{
const spell *sp = NULL;
xmlChar *propValue = xmlGetProp(node, BAD_CAST name);
if (propValue != NULL) {
sp = find_spell((const char *)propValue);
assert(sp);
spellref *ref = spellref_create(NULL, (const char *)propValue);
xmlFree(propValue);
return ref;
}
return sp;
return NULL;
}
static xmlChar *xml_cleanup_string(xmlChar * str)
@ -1853,7 +1852,7 @@ static int parse_races(xmlDocPtr doc)
|| !"precombatspell is already initialized");
for (k = 0; k != result->nodesetval->nodeNr; ++k) {
xmlNodePtr node = result->nodesetval->nodeTab[k];
rc->precombatspell = xml_spell(node, "spell");
rc->precombatspell = xml_spellref(node, "spell");
}
xmlXPathFreeObject(result);
@ -1878,11 +1877,11 @@ static int parse_races(xmlDocPtr doc)
xmlFree(propValue);
}
else {
attack->data.sp = xml_spell(node, "spell");
attack->data.sp = xml_spellref(node, "spell");
if (attack->data.sp) {
attack->level = xml_ivalue(node, "level", 0);
if (attack->level <= 0) {
log_error("magical attack '%s' for race '%s' needs a level: %d\n", attack->data.sp->sname, rc->_name, attack->level);
log_error("magical attack '%s' for race '%s' needs a level: %d\n", attack->data.sp->name, rc->_name, attack->level);
}
}
}
@ -2069,17 +2068,20 @@ static int parse_strings(xmlDocPtr doc)
void register_xmlreader(void)
{
xml_register_callback(parse_strings);
xml_register_callback(parse_messages);
xml_register_callback(parse_resources);
xml_register_callback(parse_rules);
xml_register_callback(parse_buildings); /* requires resources */
xml_register_callback(parse_ships); /* requires terrains */
xml_register_callback(parse_spells); /* requires resources */
xml_register_callback(parse_spellbooks); /* requires spells */
xml_register_callback(parse_equipment); /* requires spells */
xml_register_callback(parse_races); /* requires spells */
xml_register_callback(parse_races);
xml_register_callback(parse_calendar);
xml_register_callback(parse_resources);
xml_register_callback(parse_buildings); /* requires resources */
xml_register_callback(parse_ships); /* requires resources, terrains */
xml_register_callback(parse_equipment); /* requires resources */
xml_register_callback(parse_spells); /* requires resources */
xml_register_callback(parse_spellbooks); /* requires spells */
xml_register_callback(parse_strings);
xml_register_callback(parse_messages);
}
#endif

View File

@ -430,7 +430,6 @@ void show_new_spells(faction * f, int level, const spellbook *book)
for (qi = 0; ql; selist_advance(&ql, &qi, 1)) {
spellbook_entry *sbe = (spellbook_entry *)selist_get(ql, qi);
if (sbe->level <= level) {
if (!already_seen(f, sbe->sp)) {
attrib * a = a_new(&at_reportspell);
spellbook_entry * entry = (spellbook_entry *)a->data.v;
@ -481,13 +480,15 @@ void pick_random_spells(faction * f, int level, spellbook * book, int num_spells
commonspells[maxspell] = sbe;
sbe = 0;
}
else if (f->spellbook && spellbook_get(f->spellbook, sbe->sp)) {
// already have this spell, remove it from the list of candidates
commonspells[spellno] = commonspells[--numspells];
if (maxspell > numspells) {
maxspell = numspells;
else {
if (f->spellbook && spellbook_get(f->spellbook, sbe->sp)) {
// already have this spell, remove it from the list of candidates
commonspells[spellno] = commonspells[--numspells];
if (maxspell > numspells) {
maxspell = numspells;
}
sbe = 0;
}
sbe = 0;
}
}
@ -560,8 +561,11 @@ const spell *get_combatspell(const unit * u, int nr)
if (m) {
return m->combatspells[nr].sp;
}
else if (u_race(u)->precombatspell != NULL) {
return u_race(u)->precombatspell;
else {
const race * rc = u_race(u);
if (rc->precombatspell) {
return spellref_get(rc->precombatspell);
}
}
return NULL;
@ -2945,6 +2949,7 @@ const char *spell_info(const spell * sp, const struct locale *lang)
return LOC(lang, mkname("spellinfo", sp->sname));
}
// TODO: should take the name, not the spell (spellref optimizations)
const char *spell_name(const spell * sp, const struct locale *lang)
{
return LOC(lang, mkname("spell", sp->sname));
@ -2964,15 +2969,14 @@ static void select_spellbook(void **tokens, spellbook *sb, const struct locale *
for (qi = 0, ql = sb->spells; ql; selist_advance(&ql, &qi, 1)) {
spellbook_entry *sbe = (spellbook_entry *)selist_get(ql, qi);
spell *sp = sbe->sp;
const char *n = spell_name(sp, lang);
const char *n = spell_name(sbe->sp, lang);
if (!n) {
log_error("no translation in locale %s for spell %s\n", locale_name(lang), sp->sname);
log_error("no translation in locale %s for spell %s\n", locale_name(lang), sbe->sp->sname);
}
else {
variant token;
token.v = sp;
token.v = sbe->sp;
addtoken((struct tnode **)tokens, n, token);
}
}

View File

@ -76,10 +76,20 @@ static void load_inifile(dictionary * d)
static dictionary *parse_config(const char *filename)
{
dictionary *d = iniparser_load(filename);
char path[MAX_PATH];
dictionary *d;
const char *cfgpath = config_get("config.path");
if (cfgpath) {
join_path(cfgpath, filename, path, sizeof(path));
log_debug("reading from configuration file %s\n", path);
d = iniparser_load(path);
} else {
log_debug("reading from configuration file %s\n", filename);
d = iniparser_load(filename);
}
if (d) {
load_inifile(d);
log_debug("reading from configuration file %s\n", filename);
config_set_from(d);
memdebug = iniparser_getint(d, "game:memcheck", memdebug);
@ -176,6 +186,10 @@ static int parse_args(int argc, char **argv, int *exitcode)
else {
const char *arg;
switch (argi[1]) {
case 'c':
i = get_arg(argc, argv, 2, i, &arg, 0);
config_set("config.path", arg);
break;
case 'r':
i = get_arg(argc, argv, 2, i, &arg, 0);
config_set("config.rules", arg);
@ -270,15 +284,15 @@ int main(int argc, char **argv)
{
int err = 0;
lua_State *L;
dictionary *d;
dictionary *d = 0;
setup_signal_handler();
/* ini file sets defaults for arguments*/
/* parse arguments again, to override ini file */
parse_args(argc, argv, &err);
d = parse_config(inifile);
if (!d) {
log_error("could not open ini configuration %s\n", inifile);
}
/* parse arguments again, to override ini file */
parse_args(argc, argv, &err);
locale_init();

View File

@ -234,7 +234,7 @@ paragraph(struct stream *out, const char *str, ptrdiff_t indent, int hanging_ind
} while (*begin);
}
static size_t write_spell_modifier(spell * sp, int flag, const char * str, bool cont, char * bufp, size_t size) {
static size_t write_spell_modifier(const spell * sp, int flag, const char * str, bool cont, char * bufp, size_t size) {
if (sp->sptyp & flag) {
size_t bytes = 0;
if (cont) {
@ -255,7 +255,7 @@ void nr_spell_syntax(struct stream *out, spellbook_entry * sbe, const struct loc
char buf[4096];
char *bufp = buf;
size_t size = sizeof(buf) - 1;
spell * sp = sbe->sp;
const spell * sp = sbe->sp;
const char *params = sp->parameter;
if (sp->sptyp & ISCOMBATSPELL) {
@ -445,7 +445,7 @@ void nr_spell(struct stream *out, spellbook_entry * sbe, const struct locale *la
char buf[4096];
char *startp, *bufp = buf;
size_t size = sizeof(buf) - 1;
spell * sp = sbe->sp;
const spell * sp = sbe->sp;
newline(out);
centre(out, spell_name(sp, lang), true);

View File

@ -680,6 +680,7 @@ size_t size)
if (wrptr(&bufp, &size, result) != 0) {
WARN_STATIC_BUFFER();
}
// TODO: no need to deref the spellref here (spref->name is good)
bufp = STRLCPY(bufp, spell_name(sbe->sp, f->locale), size);
}
}

View File

@ -116,6 +116,13 @@ static void test_unicode_bug2262(CuTest *tc) {
CuAssertIntEquals(tc, EILSEQ, unicode_utf8_trim(name));
}
static void test_unicode_compare(CuTest *tc)
{
CuAssertIntEquals(tc, 0, unicode_utf8_strcasecmp("ABCDEFG", "abcdefg"));
CuAssertIntEquals(tc, 0, unicode_utf8_strcasecmp("abcdefg123", "ABCDEFG123"));
CuAssertIntEquals(tc, 1, unicode_utf8_strcasecmp("bacdefg123", "ABCDEFG123"));
}
CuSuite *get_unicode_suite(void)
{
CuSuite *suite = CuSuiteNew();
@ -124,5 +131,6 @@ CuSuite *get_unicode_suite(void)
SUITE_ADD_TEST(suite, test_unicode_trim);
SUITE_ADD_TEST(suite, test_unicode_utf8_to_other);
SUITE_ADD_TEST(suite, test_unicode_utf8_to_ucs);
SUITE_ADD_TEST(suite, test_unicode_compare);
return suite;
}

View File

@ -8,7 +8,6 @@ SET SERVER=%BUILD%\eressea.exe
%SERVER% ..\scripts\run-tests.lua
%SERVER% -re2 ..\scripts\run-tests-e2.lua
%SERVER% -re3 ..\scripts\run-tests-e3.lua
%SERVER% -re4 ..\scripts\run-tests-e4.lua
PAUSE
RMDIR /s /q reports
DEL score score.alliances datum turn