Merge branch 'develop' of github.com:eressea/server into develop

This commit is contained in:
Enno Rehling 2017-09-24 11:36:13 +02:00
commit 427c6af25d
75 changed files with 828 additions and 864 deletions

2
clibs

@ -1 +1 @@
Subproject commit d286006a28c8aa7cd70ed7fd4cd172b50ade9727
Subproject commit da2c0cc39b27c98ed8d31b0503426788fc236bd8

View file

@ -25,7 +25,7 @@
<item name="log" amount="10"/>
<item name="stone" amount="4"/>
</set>
<set name="autoseed_unit">
<set name="seed_unit">
<item name="log" amount="50"/>
<item name="stone" amount="50"/>
<item name="iron" amount="50"/>
@ -38,7 +38,7 @@
<skill name="perception" level="30"/>
<skill name="melee" level="1"/>
</set>
<set name="autoseed_faction">
<set name="seed_faction">
<item name="adamantium" amount="1"/>
</set>
</equipment>

View file

@ -1,7 +1,7 @@
<?xml version="1.0"?>
<equipment>
<set name="seaserpent_spoils">
<set name="spo_seaserpent">
<item name="dragonblood" amount="2"/>
<item name="seaserpenthead" amount="1"/>
</set>

View file

@ -2,27 +2,27 @@
<equipment>
<!-- equipment given to familiars -->
<set name="lynx_familiar">
<set name="fam_lynx">
<skill name="magic" level="1"/>
</set>
<set name="tunnelworm_familiar">
<set name="fam_tunnelworm">
<skill name="magic" level="1"/>
<skill name="mining" level="1"/>
<skill name="forestry" level="1"/>
<skill name="stamina" level="1"/>
</set>
<set name="eagle_familiar">
<set name="fam_eagle">
<skill name="magic" level="1"/>
</set>
<set name="rat_familiar">
<set name="fam_rat">
<skill name="magic" level="1"/>
<skill name="stamina" level="6"/>
</set>
<set name="songdragon_familiar">
<set name="fam_songdragon">
<skill name="magic" level="1"/>
<!-- spells -->
<spell name="flee" level="2"/>
@ -30,7 +30,7 @@
<spell name="frighten" level="8"/>
</set>
<set name="nymph_familiar">
<set name="fam_nymph">
<skill name="magic" level="1"/>
<skill name="bow" level="1"/>
<skill name="training" level="1"/>
@ -42,7 +42,7 @@
<spell name="appeasement" level="1"/>
</set>
<set name="unicorn_familiar">
<set name="fam_unicorn">
<skill name="magic" level="1"/>
<!-- spells -->
<spell name="resist_magic" level="3"/>
@ -53,11 +53,11 @@
<spell name="appeasement" level="1"/>
</set>
<set name="direwolf_familiar">
<set name="fam_direwolf">
<skill name="magic" level="1"/>
</set>
<set name="ghost_familiar">
<set name="fam_ghost">
<skill name="magic" level="1"/>
<!-- spells -->
<spell name="steal_aura" level="6"/>
@ -65,7 +65,7 @@
<spell name="summonundead" level="6"/>
</set>
<set name="imp_familiar">
<set name="fam_imp">
<skill name="magic" level="1"/>
<!-- spells -->
<spell name="steal_aura" level="6"/>
@ -73,14 +73,14 @@
<spell name="seduction" level="6"/>
</set>
<set name="dreamcat_familiar">
<set name="fam_dreamcat">
<skill name="magic" level="1"/>
<!-- spells -->
<spell name="shapeshift" level="3"/>
<spell name="transferauratraum" level="3"/>
</set>
<set name="fairy_familiar">
<set name="fam_fairy">
<skill name="magic" level="1"/>
<!-- spells -->
<spell name="appeasement" level="1"/>
@ -88,15 +88,15 @@
<spell name="seduction" level="6"/>
</set>
<set name="owl_familiar">
<set name="fam_owl">
<skill name="magic" level="1"/>
</set>
<set name="hellcat_familiar">
<set name="fam_hellcat">
<skill name="magic" level="1"/>
</set>
<set name="tiger_familiar">
<set name="fam_tiger">
<skill name="magic" level="1"/>
</set>

View file

@ -2,18 +2,18 @@
<equipment>
<!-- one equipment-set per player-race for the first unit in a faction -->
<set name="autoseed_dwarf">
<set name="seed_dwarf">
<item name="axe" amount="1"/>
<item name="chainmail" amount="1"/>
<skill name="melee" level="1"/>
</set>
<set name="autoseed_elf">
<set name="seed_elf">
<item name="fairyboot" amount="1"/>
<callback name="equip_newunits"/>
</set>
<set name="autoseed_orc">
<set name="seed_orc">
<skill name="polearm" level="4"/>
<skill name="melee" level="4"/>
<skill name="crossbow" level="4"/>
@ -21,30 +21,30 @@
<skill name="bow" level="4"/>
</set>
<set name="autoseed_goblin">
<set name="seed_goblin">
<item name="roi" amount="1"/>
<callback name="equip_newunits"/>
</set>
<set name="autoseed_human">
<set name="seed_human">
<callback name="equip_newunits"/>
</set>
<set name="autoseed_troll">
<set name="seed_troll">
<skill name="building" level="1"/>
<skill name="perception" level="3"/>
<item name="stone" amount="50"/>
</set>
<set name="autoseed_demon">
<set name="seed_demon">
<skill name="stamina" level="15"/>
</set>
<set name="autoseed_insect">
<set name="seed_insect">
<item name="nestwarmth" amount="9"/>
</set>
<set name="autoseed_halfling">
<set name="seed_halfling">
<skill name="trade" level="1"/>
<skill name="riding" level="2"/>
<item name="horse" amount="2"/>
@ -58,18 +58,18 @@
<item name="incense" amount="5"/>
</set>
<set name="autoseed_cat">
<set name="seed_cat">
<item name="roi" amount="1"/>
<callback name="equip_newunits"/>
</set>
<set name="autoseed_aquarian">
<set name="seed_aquarian">
<skill name="sailing" level="1"/>
<callback name="equip_newunits"/>
</set>
<!-- equipment-sets for random encounters -->
<set name="random_desert">
<set name="rand_desert">
<skill name="melee" level="d2"/>
<skill name="trade" level="d3"/>
<skill name="riding" level="d2+1"/>
@ -79,53 +79,53 @@
<item name="money" amount="d30+19"/>
</set>
<set name="random_swamp">
<set name="rand_swamp">
<skill name="stealth" level="d3+1"/>
<skill name="polearm" level="d3+1"/>
<item name="spear" amount="1"/>
<item name="money" amount="d20+9"/>
</set>
<set name="random_glacier">
<set name="rand_glacier">
<skill name="armorer" level="d2+1"/>
<skill name="melee" level="d2+1"/>
<item name="sword" amount="1"/>
<item name="money" amount="d20+19"/>
</set>
<set name="random_mountain">
<set name="rand_mountain">
<skill name="armorer" level="d2+1"/>
<skill name="melee" level="d2+1"/>
<skill name="trade" level="d3"/>
<item name="sword" amount="1"/>
<item name="money" amount="d40+59"/>
<subset chance="0.6">
<set name="item_plate"/>
<set name="i_plate"/>
</subset>
</set>
<set name="random_highland">
<set name="rand_highland">
<skill name="melee" level="d2"/>
<item name="sword" amount="1"/>
<item name="money" amount="d10+19"/>
</set>
<set name="random_forest">
<set name="rand_forest">
<skill name="stealth" level="d2"/>
<skill name="perception" level="d2+1"/>
<skill name="bow" level="d3+1"/>
<item name="bow" amount="1"/>
<item name="money" amount="d20+9"/>
<subset chance="0.2">
<set name="random_herbalist"/>
<set name="rand_herbalist"/>
</subset>
</set>
<set name="random_herbalist">
<set name="rand_herbalist">
<skill name="herbalism" level="d2"/>
</set>
<set name="random_villagers">
<set name="rand_villagers">
<item name="money" amount="d80+19"/>
<skill name="cartmaking" level="d2-1"/>
<skill name="mining" level="d2-1"/>
@ -136,57 +136,57 @@
<item name="money" amount="d30+10"/>
</set>
<set name="random_plain">
<set name="rand_plain">
<item name="money" amount="d80+19"/>
<subset>
<set name="random_sword" chance="0.25"/>
<set name="random_spear" chance="0.25"/>
<set name="random_crossbow" chance="0.25"/>
<set name="random_bow" chance="0.25"/>
<set name="rand_sword" chance="0.25"/>
<set name="rand_spear" chance="0.25"/>
<set name="rand_crossbow" chance="0.25"/>
<set name="rand_bow" chance="0.25"/>
</subset>
<subset chance="0.4">
<set name="item_chain"/>
<set name="i_chain"/>
</subset>
<subset chance="0.3">
<set name="random_rider"/>
<set name="rand_rider"/>
</subset>
</set>
<set name="random_spear">
<set name="rand_spear">
<skill name="polearm" level="d3"/>
<item name="spear" amount="1"/>
</set>
<set name="random_sword">
<set name="rand_sword">
<skill name="melee" level="d3"/>
<item name="sword" amount="1"/>
</set>
<set name="random_crossbow">
<set name="rand_crossbow">
<skill name="crossbow" level="d3"/>
<item name="crossbow" amount="1"/>
</set>
<set name="random_bow">
<set name="rand_bow">
<skill name="bow" level="d3"/>
<item name="bow" amount="1"/>
</set>
<set name="random_rider">
<set name="rand_rider">
<item name="horse" amount="1"/>
<skill name="riding" level="d3"/>
</set>
<set name="recruited_dracoid">
<set name="new_dracoid">
<!-- dracoiden, von drachen rekrutiert -->
<skill name="polearm" level="d4+2"/>
<skill name="melee" level="d4+2"/>
<skill name="bow" level="d3+1"/>
<subset>
<!-- dracoiden haben immer eine von drei waffen -->
<set name="item_sword" chance="0.33"/>
<set name="item_spear" chance="0.33"/>
<set name="item_bow" chance="0.34"/>
<set name="i_sword" chance="0.33"/>
<set name="i_spear" chance="0.33"/>
<set name="i_bow" chance="0.34"/>
</subset>
</set>
@ -195,56 +195,52 @@
<item name="rustysword" amount="1"/>
<item name="rustychainmail" amount="d2-1"/>
<subset chance="0.3">
<set name="item_rustyshield"/>
<set name="i_rustyshield"/>
</subset>
</set>
<!-- single-item sets (that can be given a percentage-chance in a subset) -->
<set name="item_plate">
<set name="i_plate">
<item name="plate" amount="1"/>
</set>
<set name="item_spear">
<set name="i_spear">
<item name="spear" amount="1"/>
</set>
<set name="item_bow">
<set name="i_bow">
<item name="bow" amount="1"/>
</set>
<set name="item_sword">
<set name="i_sword">
<item name="sword" amount="1"/>
</set>
<set name="item_chain">
<set name="i_chain">
<item name="chainmail" amount="1"/>
</set>
<set name="item_log">
<item name="log" amount="1"/>
<set name="i_rustyshield">
<item name="rustyshield" amount="1"/>
</set>
<set name="item_rustychain">
<item name="rustychainmail" amount="1"/>
</set>
<set name="dragon_spoils">
<set name="spo_dragon">
<item name="dragonblood" amount="4"/>
<item name="dragonhead" amount="1"/>
</set>
<set name="youngdragon_spoils">
<set name="spo_youngdragon">
<item name="dragonblood" amount="1"/>
</set>
<set name="wyrm_spoils">
<set name="spo_wyrm">
<item name="dragonblood" amount="10"/>
<item name="dragonhead" amount="1"/>
</set>
<!-- sets that are used by the monster-spawning code -->
<set name="monster_dragon">
<set name="seed_dragon">
<skill name="magic" level="4"/>
<skill name="stealth" level="1"/>
<skill name="stamina" level="1"/>
@ -252,24 +248,24 @@
<item name="money" amount="d500+99"/>
</set>
<set name="monster_braineater">
<set name="seed_braineater">
<skill name="stealth" level="1"/>
<skill name="perception" level="1"/>
</set>
<set name="monster_seaserpent">
<set name="seed_seaserpent">
<skill name="magic" level="4"/>
<skill name="stealth" level="2"/>
<skill name="stamina" level="1"/>
<skill name="perception" level="3"/>
</set>
<set name="new_orc_unit">
<set name="new_orc">
<skill name="polearm" level="1"/>
<skill name="melee" level="1"/>
</set>
<set name="seaserpent_spoils">
<set name="spo_seaserpent">
<item name="dragonblood" amount="6"/>
<item name="seaserpenthead" amount="1"/>
</set>

View file

@ -2,26 +2,26 @@
<equipment>
<!-- equipment given to familiars -->
<set name="lynx_familiar">
<set name="fam_lynx">
<skill name="espionage" level="1"/>
<skill name="magic" level="1"/>
<skill name="stealth" level="1"/>
<skill name="perception" level="1"/>
</set>
<set name="tunnelworm_familiar">
<set name="fam_tunnelworm">
<skill name="magic" level="1"/>
<skill name="mining" level="1"/>
<skill name="forestry" level="1"/>
<skill name="stamina" level="1"/>
</set>
<set name="eagle_familiar">
<set name="fam_eagle">
<skill name="magic" level="1"/>
<skill name="perception" level="1"/>
</set>
<set name="rat_familiar">
<set name="fam_rat">
<skill name="magic" level="1"/>
<skill name="espionage" level="1"/>
<skill name="stealth" level="1"/>
@ -29,7 +29,7 @@
<skill name="stamina" level="6"/>
</set>
<set name="songdragon_familiar">
<set name="fam_songdragon">
<skill name="magic" level="1"/>
<!-- spells -->
<spell name="flee" level="2"/>
@ -37,7 +37,7 @@
<spell name="frighten" level="8"/>
</set>
<set name="nymph_familiar">
<set name="fam_nymph">
<skill name="magic" level="1"/>
<skill name="bow" level="1"/>
<skill name="herbalism" level="1"/>
@ -54,7 +54,7 @@
<spell name="appeasement" level="1"/>
</set>
<set name="unicorn_familiar">
<set name="fam_unicorn">
<skill name="magic" level="1"/>
<skill name="stealth" level="1"/>
<skill name="perception" level="1"/>
@ -67,12 +67,12 @@
<spell name="appeasement" level="1"/>
</set>
<set name="direwolf_familiar">
<set name="fam_direwolf">
<skill name="magic" level="1"/>
<skill name="perception" level="1"/>
</set>
<set name="ghost_familiar">
<set name="fam_ghost">
<skill name="magic" level="1"/>
<!-- spells -->
<spell name="steal_aura" level="6"/>
@ -80,7 +80,7 @@
<spell name="summonundead" level="6"/>
</set>
<set name="imp_familiar">
<set name="fam_imp">
<skill name="magic" level="1"/>
<skill name="espionage" level="1"/>
<skill name="stealth" level="1"/>
@ -92,7 +92,7 @@
<spell name="seduction" level="6"/>
</set>
<set name="dreamcat_familiar">
<set name="fam_dreamcat">
<skill name="magic" level="1"/>
<skill name="espionage" level="1"/>
<skill name="stealth" level="1"/>
@ -103,7 +103,7 @@
<spell name="transferauratraum" level="3"/>
</set>
<set name="fairy_familiar">
<set name="fam_fairy">
<skill name="magic" level="1"/>
<!-- spells -->
<spell name="appeasement" level="1"/>
@ -111,19 +111,19 @@
<spell name="seduction" level="6"/>
</set>
<set name="owl_familiar">
<set name="fam_owl">
<skill name="magic" level="1"/>
<skill name="espionage" level="1"/>
<skill name="stealth" level="1"/>
<skill name="perception" level="1"/>
</set>
<set name="hellcat_familiar">
<set name="fam_hellcat">
<skill name="magic" level="1"/>
<skill name="perception" level="1"/>
</set>
<set name="tiger_familiar">
<set name="fam_tiger">
<skill name="magic" level="1"/>
<skill name="perception" level="1"/>
</set>

View file

@ -65,9 +65,9 @@ local function seed(r, email, race, lang)
assert(f)
local u = unit.create(f, r)
assert(u)
equip_unit(u, "autoseed_faction")
equip_unit(u, "autoseed_unit")
equip_unit(u, "autoseed_" .. race, 7)
equip_unit(u, "seed_faction")
equip_unit(u, "seed_unit")
equip_unit(u, "seed_" .. race, 7)
unit.create(f, r, 5):set_skill("mining", 30)
unit.create(f, r, 5):set_skill("quarrying", 30)
f:set_origin(r)

View file

@ -18,8 +18,9 @@ local function file_exists(name)
if f~=nil then io.close(f) return true else return false end
end
local function assert_file(filename)
assert_equal(true, file_exists(filename))
local function assert_file(filename, exists)
if exists == nil then exists = true end
assert_equal(exists, file_exists(filename))
os.remove(filename)
end
@ -30,9 +31,9 @@ function test_process_turn()
assert_equal(0, write_reports())
assert_equal(0, eressea.write_game("test.dat"))
assert_file("data/test.dat")
assert_file("reports/" .. get_turn() .. "-ii.nr")
assert_file("reports/" .. get_turn() .. "-ii.cr")
assert_file("reports/" .. get_turn() .. "-ii.txt")
assert_file("reports/" .. get_turn() .. "-ii.nr", false)
assert_file("reports/" .. get_turn() .. "-ii.cr", false)
assert_file("reports/" .. get_turn() .. "-ii.txt", false)
assert_file("reports/" .. get_turn() .. "-777.nr")
assert_file("reports/" .. get_turn() .. "-777.cr")
assert_file("reports/" .. get_turn() .. "-777.txt")

View file

@ -96,7 +96,7 @@ static int obs_read(struct attrib *a, void *owner, struct gamedata *data)
{
obs_data *od = (obs_data *)a->data.v;
read_reference(&od->f, data, read_faction_reference, resolve_faction);
read_faction_reference(data, &od->f, NULL);
READ_INT(data->store, &od->skill);
READ_INT(data->store, &od->timer);
return AT_READ_OK;

View file

@ -30,7 +30,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
static int read_follow(attrib * a, void *owner, gamedata *data)
{
read_unit_reference(data); /* skip it */
READ_INT(data->store, NULL); /* skip it */
return AT_READ_FAIL;
}

View file

@ -45,9 +45,7 @@ write_hate(const attrib * a, const void *owner, struct storage *store)
static int read_hate(attrib * a, void *owner, gamedata *data)
{
int result = read_reference(&a->data.v, data, read_unit_reference,
resolve_unit);
if (result == 0 && !a->data.v) {
if (read_unit_reference(data, (unit **)&a->data.v, NULL) <= 0) {
return AT_READ_FAIL;
}
return AT_READ_OK;

View file

@ -67,8 +67,12 @@ static int keys_size(int n) {
assert(n > 0 && n <= 4096);
if (n <= 1) return 1;
if (n <= 4) return 4;
if (n <= 8) return 8;
if (n <= 16) return 16;
if (n <= 256) return 256;
if (n <= 512) return 512;
if (n <= 1024) return 1024;
if (n <= 2048) return 2048;
return 4096;
}

View file

@ -36,10 +36,9 @@ write_targetregion(const attrib * a, const void *owner, struct storage *store)
static int read_targetregion(attrib * a, void *owner, gamedata *data)
{
int result = read_reference(&a->data.v, data, read_region_reference,
RESOLVE_REGION(data->version));
if (result == 0 && !a->data.v)
if (read_region_reference(data, (region **)&a->data.v, NULL) <= 0) {
return AT_READ_FAIL;
}
return AT_READ_OK;
}

View file

@ -927,7 +927,7 @@ void kill_troop(troop dt)
if (drops != NULL) {
i_merge(&du->items, &drops);
}
sprintf(eqname, "%s_spoils", rc->_name);
sprintf(eqname, "spo_%s", rc->_name);
eq = get_equipment(eqname);
if (eq != NULL) {
equip_items(&du->items, eq);

View file

@ -86,8 +86,7 @@ static void lc_done(struct attrib *a)
free(data);
}
static void
lc_write(const struct attrib *a, const void *owner, struct storage *store)
static void lc_write(const struct attrib *a, const void *owner, struct storage *store)
{
building_action *data = (building_action *)a->data.v;
const char *fname = data->fname;
@ -106,8 +105,7 @@ static int lc_read(struct attrib *a, void *owner, gamedata *data)
building *b = (building *)owner;
int result = 0;
if (data->version < ATTRIBOWNER_VERSION) {
result = read_reference(&b, data, read_building_reference, resolve_building);
assert(b == owner);
READ_INT(data->store, NULL);
}
READ_TOK(store, name, sizeof(name));
if (strcmp(name, "tunnel_action") == 0) {

View file

@ -1365,8 +1365,8 @@ static void cr_output_region(FILE * F, report_context * ctx, region * r)
unit *u;
int stealthmod = stealth_modifier(r->seen.mode);
if (r->display && r->display[0])
fprintf(F, "\"%s\";Beschr\n", r->display);
if (r->land && r->land->display && r->land->display[0])
fprintf(F, "\"%s\";Beschr\n", r->land->display);
if (fval(r->terrain, LAND_REGION)) {
assert(r->land);
fprintf(F, "%d;Bauern\n", rpeasants(r));

View file

@ -266,7 +266,6 @@ void add_recruits(unit * u, int number, int wanted)
strlcpy(equipment, "new_", sizeof(equipment));
strlcat(equipment, u_race(u)->_name, sizeof(equipment));
strlcat(equipment, "_unit", sizeof(equipment));
equip_unit(unew, get_equipment(equipment));
if (unew != u) {

View file

@ -418,10 +418,12 @@ message * give_men(int n, unit * u, unit * u2, struct order *ord)
set_racename(&u2->attribs, get_racename(u->attribs));
u_setrace(u2, u_race(u));
u2->irace = u->irace;
if (fval(u, UFL_HERO))
if (fval(u, UFL_HERO)) {
fset(u2, UFL_HERO);
else
}
else {
freset(u2, UFL_HERO);
}
}
/* Einheiten von Schiffen können nicht NACH in von

View file

@ -20,6 +20,7 @@ without prior permission by the authors of Eressea.
#include <util/bsdstring.h>
#include <util/event.h>
#include <util/functions.h>
#include <util/gamedata.h>
#include <util/log.h>
#include <util/parser.h>
#include <util/resolve.h>
@ -290,10 +291,10 @@ use_item_lua(unit *u, const item_type *itype, int amount, struct order *ord)
}
/* compat code for old data files */
static int caldera_read(trigger *t, struct gamedata *data)
static int caldera_read(trigger *t, gamedata *data)
{
UNUSED_ARG(t);
read_building_reference(data);
READ_INT(data->store, NULL);
return AT_READ_FAIL;
}

View file

@ -7,13 +7,40 @@
#include "region.h"
#include "group.h"
#include "faction.h"
#include "objtypes.h"
#include "plane.h"
#include <util/attrib.h>
#include <util/gamedata.h>
#include <storage.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
void read_allies(gamedata * data, faction *f)
{
ally **sfp = &f->allies;
for (;;) {
int aid;
READ_INT(data->store, &aid);
if (aid > 0) {
ally * al = ally_add(sfp, NULL);
int state;
if ((al->faction = findfaction(aid)) == NULL) {
ur_add(RESOLVE_FACTION | aid, (void **)&al->faction, NULL);
}
READ_INT(data->store, &state);
al->status = state & HELP_ALL;
sfp = &al->next;
}
else {
break;
}
}
}
ally * ally_find(ally *al, const struct faction *f) {
for (; al; al = al->next) {
if (al->faction == f) return al;

View file

@ -26,7 +26,9 @@ extern "C" {
struct attrib_type;
struct plane;
struct faction;
struct gamedata;
struct unit;
extern struct attrib_type at_npcfaction;
typedef struct ally {
@ -35,6 +37,7 @@ extern "C" {
int status;
} ally;
void read_allies(struct gamedata * data, struct faction *f);
ally * ally_find(ally *al, const struct faction *f);
ally * ally_add(ally **al_p, struct faction *f);
void ally_remove(ally **al_p, struct faction *f);

View file

@ -322,25 +322,26 @@ void write_building_reference(const struct building *b, struct storage *store)
WRITE_INT(store, (b && b->region) ? b->no : 0);
}
int resolve_building(variant id, void *address)
void resolve_building(building *b)
{
int result = 0;
building *b = NULL;
if (id.i != 0) {
b = findbuilding(id.i);
if (b == NULL) {
result = -1;
}
}
*(building **)address = b;
return result;
resolve(RESOLVE_BUILDING | b->no, b);
}
variant read_building_reference(gamedata * data)
int read_building_reference(gamedata * data, building **bp, resolve_fun fun)
{
variant result;
READ_INT(data->store, &result.i);
return result;
int id;
READ_INT(data->store, &id);
if (id > 0) {
*bp = findbuilding(id);
if (*bp == NULL) {
*bp = NULL;
ur_add(RESOLVE_BUILDING | id, (void**)bp, fun);
}
}
else {
*bp = NULL;
}
return id;
}
building *new_building(const struct building_type * btype, region * r,

View file

@ -20,7 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#define H_KRNL_BUILDING
#include <kernel/types.h>
#include <util/variant.h>
#include <util/resolve.h>
#include <stddef.h>
#include <stdbool.h>
@ -152,10 +152,11 @@ extern "C" {
#include "build.h"
#define NOBUILDING NULL
int resolve_building(variant data, void *address);
#define RESOLVE_BUILDING (TYP_BUILDING << 24)
void resolve_building(building *b);
void write_building_reference(const struct building *b,
struct storage *store);
variant read_building_reference(struct gamedata *data);
int read_building_reference(struct gamedata * data, struct building **bp, resolve_fun fun);
struct building *findbuilding(int n);

View file

@ -606,37 +606,26 @@ int read_borders(gamedata *data)
{
struct storage *store = data->store;
for (;;) {
int bid = 0;
int fid, tid, bid;
char zText[32];
region *from, *to;
border_type *type;
READ_TOK(store, zText, sizeof(zText));
if (!strcmp(zText, "end"))
if (!strcmp(zText, "end")) {
break;
}
READ_INT(store, &bid);
type = find_bordertype(zText);
if (type == NULL) {
log_error("[read_borders] connection %d type %s is not registered", bid, zText);
assert(type || !"connection type not registered");
}
READ_INT(store, &bid);
if (data->version < UIDHASH_VERSION) {
int fx, fy, tx, ty;
READ_INT(store, &fx);
READ_INT(store, &fy);
READ_INT(store, &tx);
READ_INT(store, &ty);
from = findregion(fx, fy);
to = findregion(tx, ty);
}
else {
int fid, tid;
READ_INT(store, &fid);
READ_INT(store, &tid);
from = findregionbyid(fid);
to = findregionbyid(tid);
}
READ_INT(store, &fid);
READ_INT(store, &tid);
from = findregionbyid(fid);
to = findregionbyid(tid);
if (!to || !from) {
log_error("%s connection %d has missing regions", zText, bid);
if (type->read) {
@ -660,19 +649,6 @@ int read_borders(gamedata *data)
b->id = bid;
assert(bid <= nextborder);
type->read(b, data);
if (data->version < NOBORDERATTRIBS_VERSION) {
attrib *a = NULL;
int result = read_attribs(data, &a, b);
if (border_convert_cb) {
border_convert_cb(b, a);
}
while (a) {
a_remove(&a, a);
}
if (result < 0) {
return result;
}
}
if (!type->write) {
log_warning("invalid border '%s' between '%s' and '%s'\n", zText, regionname(from, 0), regionname(to, 0));
}

View file

@ -191,12 +191,7 @@ int curse_read(attrib * a, void *owner, gamedata *data)
READ_INT(store, &c->duration);
READ_FLT(store, &flt);
c->vigour = flt;
if (data->version < INTPAK_VERSION) {
ur = resolve_unit(read_int(data->store), &c->magician);
}
else {
ur = read_reference(&c->magician, data, read_unit_reference, resolve_unit);
}
ur = read_unit_reference(data, &c->magician, NULL);
if (data->version < CURSEFLOAT_VERSION) {
READ_INT(store, &n);
c->effect = (float)n;
@ -231,9 +226,7 @@ int curse_read(attrib * a, void *owner, gamedata *data)
READ_INT(store, &c->data.i);
}
if (c->type->typ == CURSETYP_REGION) {
int rr =
read_reference(&c->data.v, data, read_region_reference,
RESOLVE_REGION(data->version));
int rr = read_region_reference(data, (region **)&c->data.v, NULL);
if (ur == 0 && rr == 0 && !c->data.v) {
return AT_READ_FAIL;
}

View file

@ -30,6 +30,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/* util includes */
#include <selist.h>
#include <critbit.h>
#include <util/log.h>
#include <util/rand.h>
#include <util/rng.h>
@ -202,38 +203,85 @@ void free_ls(void *arg) {
static critbit_tree cb_equipments = { 0 };
#define EQNAMELEN 24
typedef struct eq_entry {
char key[EQNAMELEN];
equipment *value;
} eq_entry;
typedef struct name_cb_data {
const equipment *find;
const char *result;
} name_cb_data;
static int equipment_name_cb(const void * match, const void * key, size_t keylen, void *cbdata) {
const eq_entry *ent = (const eq_entry *)match;
name_cb_data *query = (name_cb_data *)cbdata;
if (ent->value == query->find) {
query->result = ent->key;
return 1;
}
return 0;
}
const char *equipment_name(const struct equipment *eq)
{
name_cb_data data;
data.find = eq;
data.result = NULL;
cb_foreach(&cb_equipments, "", 0, equipment_name_cb, &data);
return data.result;
}
equipment *get_equipment(const char *eqname)
{
const char *match;
equipment *eq = NULL;
const void *match;
if (strlen(eqname) >= EQNAMELEN) {
log_warning("equipment name is longer than %d bytes: %s", EQNAMELEN - 1, eqname);
return NULL;
}
match = cb_find_str(&cb_equipments, eqname);
if (match) {
cb_get_kv(match, &eq, sizeof(eq));
const eq_entry *ent = (const eq_entry *)match;
return ent->value;
}
return eq;
return NULL;
}
equipment *create_equipment(const char *eqname)
{
size_t len = strlen(eqname);
eq_entry ent;
if (len >= EQNAMELEN) {
log_error("equipment name is longer than %d bytes: %s", EQNAMELEN-1, eqname);
len = EQNAMELEN-1;
}
memset(ent.key, 0, EQNAMELEN);
memcpy(ent.key, eqname, len);
ent.value = (equipment *)calloc(1, sizeof(equipment));
cb_insert(&cb_equipments, &ent, sizeof(ent));
return ent.value;
}
equipment *get_or_create_equipment(const char *eqname)
{
equipment *eq = get_equipment(eqname);
if (!eq) {
size_t len;
char data[64];
eq = (equipment *)calloc(1, sizeof(equipment));
eq->name = strdup(eqname);
len = cb_new_kv(eqname, strlen(eqname), &eq, sizeof(eq), data);
assert(len <= sizeof(data));
cb_insert(&cb_equipments, data, len);
return create_equipment(eqname);
}
return eq;
}
static void free_equipment(equipment *eq) {
int i;
free(eq->name);
if (eq->spells) {
selist_foreach(eq->spells, free_ls);
selist_free(eq->spells);
@ -251,10 +299,9 @@ static void free_equipment(equipment *eq) {
}
static int free_equipment_cb(const void * match, const void * key, size_t keylen, void *cbdata) {
equipment *eq;
cb_get_kv(match, &eq, sizeof(eq));
free_equipment(eq);
free(eq);
const eq_entry * ent = (const eq_entry *)match;
free_equipment(ent->value);
free(ent->value);
return 0;
}

View file

@ -45,7 +45,6 @@ extern "C" {
} subset;
typedef struct equipment {
char *name;
struct itemdata *items;
char *skills[MAXSKILLS];
struct selist *spells;
@ -55,8 +54,10 @@ extern "C" {
void equipment_done(void);
const char *equipment_name(const struct equipment *eq);
struct equipment *get_or_create_equipment(const char *eqname);
struct equipment *get_equipment(const char *eqname);
struct equipment *create_equipment(const char *eqname);
void equipment_setitem(struct equipment *eq,
const struct item_type *itype, const char *value);

View file

@ -10,7 +10,7 @@
#include <CuTest.h>
#include <tests.h>
void test_equipment(CuTest * tc)
static void test_equipment(CuTest * tc)
{
equipment * eq;
unit * u;
@ -46,9 +46,33 @@ void test_equipment(CuTest * tc)
test_cleanup();
}
static void test_get_equipment(CuTest * tc)
{
equipment * eq;
test_setup();
eq = create_equipment("catapultammo123");
CuAssertPtrNotNull(tc, eq);
CuAssertStrEquals(tc, "catapultammo123", equipment_name(eq));
eq = get_equipment("catapultammo123");
CuAssertPtrNotNull(tc, eq);
CuAssertStrEquals(tc, "catapultammo123", equipment_name(eq));
eq = get_equipment("catapult");
CuAssertPtrEquals(tc, NULL, eq);
eq = create_equipment("catapult");
eq = get_equipment("catapult");
CuAssertPtrNotNull(tc, eq);
CuAssertStrEquals(tc, "catapult", equipment_name(eq));
eq = get_equipment("catapultammo123");
CuAssertPtrNotNull(tc, eq);
CuAssertStrEquals(tc, "catapultammo123", equipment_name(eq));
test_cleanup();
}
CuSuite *get_equipment_suite(void)
{
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_equipment);
SUITE_ADD_TEST(suite, test_get_equipment);
return suite;
}

View file

@ -203,21 +203,6 @@ const char *factionname(const faction * f)
return ibuf;
}
int resolve_faction(variant id, void *address)
{
int result = 0;
faction *f = NULL;
if (id.i != 0) {
f = findfaction(id.i);
if (f == NULL) {
result = -1;
}
}
assert(address);
*(faction **)address = f;
return result;
}
bool faction_id_is_unused(int id)
{
return findfaction(id) == NULL;
@ -332,10 +317,25 @@ bool checkpasswd(const faction * f, const char *passwd)
return true;
}
variant read_faction_reference(gamedata * data)
void resolve_faction(faction *f)
{
variant id;
READ_INT(data->store, &id.i);
resolve(RESOLVE_FACTION | f->no, f);
}
int read_faction_reference(gamedata * data, faction **fp, resolve_fun fun)
{
int id;
READ_INT(data->store, &id);
if (id > 0) {
*fp = findfaction(id);
if (*fp == NULL) {
*fp = NULL;
ur_add(RESOLVE_FACTION | id, (void **)fp, fun);
}
}
else {
*fp = NULL;
}
return id;
}

View file

@ -21,7 +21,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "skill.h"
#include "types.h"
#include <util/resolve.h>
#include <modules/score.h>
#include <stdbool.h>
#ifdef __cplusplus
@ -126,8 +129,10 @@ extern "C" {
void write_faction_reference(const struct faction *f,
struct storage *store);
variant read_faction_reference(struct gamedata *data);
int resolve_faction(variant data, void *addr);
int read_faction_reference(struct gamedata *data, struct faction **fp, resolve_fun fun);
#define RESOLVE_FACTION (TYP_FACTION << 24)
void resolve_faction(struct faction *f);
void renumber_faction(faction * f, int no);
void free_factions(void);

View file

@ -24,6 +24,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "ally.h"
#include "faction.h"
#include "unit.h"
#include "objtypes.h"
/* attrib includes */
#include <attributes/raceprefix.h>
@ -238,16 +239,16 @@ void read_groups(gamedata *data, faction * f)
g = new_group(f, buf, gid);
pa = &g->allies;
for (;;) {
ally *a;
variant fid;
fid = read_faction_reference(data);
if (fid.i <= 0)
break;
a = ally_add(pa, findfaction(fid.i));
READ_INT(store, &a->status);
if (!a->faction)
ur_add(fid, &a->faction, resolve_faction);
ally *al;
int id;
READ_INT(store, &id);
if (id == 0) break;
al = ally_add(pa, NULL);
al->faction = findfaction(id);
if (!al->faction) {
ur_add(RESOLVE_FACTION | id, (void **)&al->faction, NULL);
}
READ_INT(store, &al->status);
}
read_attribs(data, &g->attribs, g);
}

View file

@ -60,6 +60,12 @@ static critbit_tree cb_resources;
luxury_type *luxurytypes;
potion_type *potiontypes;
#define RTYPENAMELEN 24
typedef struct rt_entry {
char key[RTYPENAMELEN];
struct resource_type *value;
} rt_entry;
static int res_changeaura(unit * u, const resource_type * rtype, int delta)
{
assert(rtype != NULL);
@ -166,13 +172,19 @@ static int num_resources;
static void rt_register(resource_type * rtype)
{
char buffer[64];
const char * name = rtype->_name;
size_t len = strlen(name);
rt_entry ent;
assert(len < sizeof(buffer) - sizeof(rtype));
len = cb_new_kv(name, len, &rtype, sizeof(rtype), buffer);
cb_insert(&cb_resources, buffer, len);
if (len >= RTYPENAMELEN) {
log_error("resource name is longer than %d bytes: %s",
RTYPENAMELEN-1, name);
len = RTYPENAMELEN-1;
}
ent.value = rtype;
memset(ent.key, 0, RTYPENAMELEN);
memcpy(ent.key, name, len);
cb_insert(&cb_resources, &ent, sizeof(ent));
++num_resources;
}
@ -186,22 +198,11 @@ resource_type *rt_get_or_create(const char *name) {
else {
rtype->_name = strdup(name);
rt_register(rtype);
return rt_find(name);
}
}
return rtype;
}
static void it_register(item_type * itype)
{
char buffer[64];
const char * name = itype->rtype->_name;
size_t len = strlen(name);
assert(len < sizeof(buffer) - sizeof(itype));
len = cb_new_kv(name, len, &itype, sizeof(itype), buffer);
}
static const char *it_aliases[][2] = {
{ "Runenschwert", "runesword" },
{ "p12", "truthpotion" },
@ -244,7 +245,6 @@ item_type *it_get_or_create(resource_type *rtype) {
rtype->uchange = res_changeitem;
rtype->itype = itype;
rtype->flags |= RTF_ITEM;
it_register(itype);
return itype;
}
@ -389,13 +389,20 @@ const potion_type *resource2potion(const resource_type * rtype)
resource_type *rt_find(const char *name)
{
void * match;
resource_type *result = 0;
const void *match;
size_t len = strlen(name);
if (cb_find_prefix(&cb_resources, name, strlen(name) + 1, &match, 1, 0)) {
cb_get_kv(match, &result, sizeof(result));
if (len >= RTYPENAMELEN) {
log_warning("resource name is longer than %d bytes: %s",
RTYPENAMELEN-1, name);
return NULL;
}
return result;
match = cb_find_str(&cb_resources, name);
if (match) {
const rt_entry *ent = (const rt_entry *)match;
return ent->value;
}
return NULL;
}
item **i_find(item ** i, const item_type * it)
@ -792,14 +799,14 @@ int change_money(unit * u, int v)
return 0;
}
static int add_resourcename_cb(const void * match, const void * key, size_t keylen, void *data)
static int add_resourcename_cb(const void * match, const void * key,
size_t keylen, void *data)
{
struct locale * lang = (struct locale *)data;
int i = locale_index(lang);
critbit_tree * cb = rnames + i;
resource_type *rtype;
resource_type *rtype = ((rt_entry *)match)->value;
cb_get_kv(match, &rtype, sizeof(rtype));
for (i = 0; i != 2; ++i) {
char buffer[128];
const char * name = LOC(lang, resourcename(rtype, (i == 0) ? 0 : NMF_PLURAL));
@ -835,20 +842,20 @@ const resource_type *findresourcetype(const char *name, const struct locale *lan
else {
log_debug("findresourcetype: transliterate failed for '%s'\n", name);
}
return 0;
return NULL;
}
attrib_type at_showitem = {
"showitem"
};
static int add_itemname_cb(const void * match, const void * key, size_t keylen, void *data)
static int add_itemname_cb(const void * match, const void * key,
size_t keylen, void *data)
{
struct locale * lang = (struct locale *)data;
critbit_tree * cb = inames + locale_index(lang);
resource_type *rtype;
resource_type *rtype = ((rt_entry *)match)->value;
cb_get_kv(match, &rtype, sizeof(rtype));
if (rtype->itype) {
int i;
for (i = 0; i != 2; ++i) {
@ -980,9 +987,10 @@ void free_rtype(resource_type *rtype) {
free(rtype);
}
int free_rtype_cb(const void * match, const void * key, size_t keylen, void *cbdata) {
resource_type *rtype;
cb_get_kv(match, &rtype, sizeof(rtype));
static int free_rtype_cb(const void * match, const void * key,
size_t keylen, void *cbdata)
{
resource_type *rtype = ((rt_entry *)match)->value;;
free_rtype(rtype);
return 0;
}

View file

@ -173,12 +173,31 @@ static void test_core_resources(CuTest *tc) {
test_cleanup();
}
static void test_get_resource(CuTest *tc) {
resource_type *rtype;
test_setup();
CuAssertPtrEquals(tc, NULL, rt_find("catapultammo123"));
rtype = rt_get_or_create("catapultammo123");
CuAssertPtrNotNull(tc, rtype);
CuAssertPtrEquals(tc, rtype, rt_find("catapultammo123"));
CuAssertStrEquals(tc, "catapultammo123", rtype->_name);
CuAssertPtrEquals(tc, NULL, rt_find("catapult"));
rtype = rt_get_or_create("catapult");
CuAssertPtrEquals(tc, rtype, rt_find("catapult"));
CuAssertStrEquals(tc, "catapult", rtype->_name);
test_cleanup();
}
CuSuite *get_item_suite(void)
{
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_resourcename_no_appearance);
SUITE_ADD_TEST(suite, test_resourcename_with_appearance);
SUITE_ADD_TEST(suite, test_change_item);
SUITE_ADD_TEST(suite, test_get_resource);
SUITE_ADD_TEST(suite, test_resource_type);
SUITE_ADD_TEST(suite, test_finditemtype);
SUITE_ADD_TEST(suite, test_findresourcetype);

View file

@ -46,10 +46,10 @@ extern "C" {
int level;
} msglevel;
extern struct message *msg_message(const char *name, const char *sig, ...);
extern struct message *msg_feedback(const struct unit *, struct order *cmd,
struct message *msg_message(const char *name, const char *sig, ...);
struct message *msg_feedback(const struct unit *, struct order *cmd,
const char *name, const char *sig, ...);
extern struct message *add_message(struct message_list **pm,
struct message *add_message(struct message_list **pm,
struct message *m);
void addmessage(struct region *r, struct faction *f, const char *s,
msg_t mtype, int level);

View file

@ -258,39 +258,6 @@ unsigned char index)
return (rel + ursprung_y(f, pl, NULL) + plane_center_y(pl));
}
static int resolve_plane(variant id, void *addr)
{
int result = 0;
plane *pl = NULL;
if (id.i != 0) {
pl = getplanebyid(id.i);
if (pl == NULL) {
result = -1;
}
}
*(plane **)addr = pl;
return result;
}
void write_plane_reference(const plane * u, struct storage *store)
{
WRITE_INT(store, u ? (u->id) : 0);
}
int read_plane_reference(plane ** pp, struct storage *store)
{
variant id;
READ_INT(store, &id.i);
if (id.i == 0) {
*pp = NULL;
return AT_READ_FAIL;
}
*pp = getplanebyid(id.i);
if (*pp == NULL)
ur_add(id, pp, resolve_plane);
return AT_READ_OK;
}
void free_plane(plane *pl) {
free(pl->name);
free(pl);

View file

@ -69,8 +69,6 @@ extern "C" {
struct plane *get_homeplane(void);
int rel_to_abs(const struct plane *pl, const struct faction *f,
int rel, unsigned char index);
void write_plane_reference(const plane * p, struct storage *store);
int read_plane_reference(plane ** pp, struct storage *store);
int plane_width(const plane * pl);
int plane_height(const plane * pl);
void adjust_coordinates(const struct faction *f, int *x, int *y, const struct plane *pl);

View file

@ -561,21 +561,15 @@ void write_race_reference(const race * rc, struct storage *store)
WRITE_TOK(store, rc ? rc->_name : "none");
}
variant read_race_reference(struct storage *store)
struct race * read_race_reference(struct storage *store)
{
variant result;
char zName[20];
READ_TOK(store, zName, sizeof(zName));
if (strcmp(zName, "none") == 0) {
result.v = NULL;
return result;
return NULL;
}
else {
result.v = rc_find_i(zName);
}
assert(result.v != NULL);
return result;
return rc_find_i(zName);
}
void register_race_function(race_func func, const char *name) {

View file

@ -263,7 +263,7 @@ extern "C" {
void write_race_reference(const struct race *rc,
struct storage *store);
variant read_race_reference(struct storage *store);
struct race *read_race_reference(struct storage *store);
const char *raceprefix(const struct unit *u);
void register_race_function(race_func, const char *);

View file

@ -825,8 +825,8 @@ void free_land(land_region * lr)
lr->demands = d->next;
free(d);
}
if (lr->name)
free(lr->name);
free(lr->name);
free(lr->display);
free(lr);
}
@ -894,7 +894,6 @@ void free_region(region * r)
{
if (last == r)
last = NULL;
free(r->display);
if (r->land)
free_land(r->land);
@ -1088,7 +1087,6 @@ void terraform_region(region * r, const terrain_type * terrain)
terraform_resources(r);
if (!fval(terrain, LAND_REGION)) {
region_setinfo(r, NULL);
if (r->land) {
free_land(r->land);
r->land = NULL;
@ -1257,46 +1255,22 @@ int production(const region * r)
return p;
}
int resolve_region_coor(variant id, void *address)
void resolve_region(region *r)
{
region *r = findregion(id.sa[0], id.sa[1]);
if (r) {
*(region **)address = r;
return 0;
}
*(region **)address = NULL;
return -1;
resolve(RESOLVE_REGION | r->uid, r);
}
int resolve_region_id(variant id, void *address)
{
region *r = NULL;
if (id.i != 0) {
r = findregionbyid(id.i);
if (r == NULL) {
*(region **)address = NULL;
return -1;
}
}
*(region **)address = r;
return 0;
}
variant read_region_reference(gamedata *data)
int read_region_reference(gamedata * data, region **rp, resolve_fun fun)
{
struct storage * store = data->store;
variant result;
if (data->version < UIDHASH_VERSION) {
int n;
READ_INT(store, &n);
result.sa[0] = (short)n;
READ_INT(store, &n);
result.sa[1] = (short)n;
int id = 0;
READ_INT(store, &id);
*rp = findregionbyid(id);
if (*rp == NULL) {
ur_add(RESOLVE_REGION | id, (void **)rp, fun);
}
else {
READ_INT(store, &result.i);
}
return result;
return id;
}
void write_region_reference(const region * r, struct storage *store)
@ -1444,13 +1418,14 @@ faction *update_owners(region * r)
void region_setinfo(struct region *r, const char *info)
{
free(r->display);
r->display = info ? strdup(info) : 0;
assert(r->land);
free(r->land->display);
r->land->display = (info && info[0]) ? strdup(info) : 0;
}
const char *region_getinfo(const region * r)
{
return r->display ? r->display : "";
return (r->land && r->land->display) ? r->land->display : "";
}
void region_setname(struct region *r, const char *name)

View file

@ -19,11 +19,14 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#ifndef H_KRNL_REGION
#define H_KRNL_REGION
#include <stddef.h>
#include <stdbool.h>
#include <util/resolve.h>
#include "types.h"
#include "direction.h"
#include <stddef.h>
#include <stdbool.h>
#define MAXLUXURIES 16 /* there must be no more than MAXLUXURIES kinds of luxury goods in any game */
#define MAXREGIONS 524287 /* must be prime for hashing. 262139 was a little small */
#define MAXTREES 100 * 1000 * 1000 /* bug 2360: some players are crazy */
@ -96,7 +99,7 @@ extern "C" {
typedef struct land_region {
char *name;
/* TODO: demand kann nach Konvertierung entfernt werden. */
char *display;
demand *demands;
const struct item_type *herbtype;
short herbs;
@ -122,7 +125,6 @@ extern "C" {
int uid; /* a unique id */
int x, y;
struct plane *_plane; /* to access, use rplane(r) */
char *display;
int flags;
unsigned short age;
struct message_list *msgs;
@ -257,11 +259,10 @@ extern "C" {
int region_get_morale(const region * r);
void region_set_morale(region * r, int morale, int turn);
#define RESOLVE_REGION (TYP_REGION << 24)
void resolve_region(region *r);
void write_region_reference(const struct region *r, struct storage *store);
variant read_region_reference(struct gamedata *data);
int resolve_region_coor(variant id, void *address);
int resolve_region_id(variant id, void *address);
#define RESOLVE_REGION(version) ((version<UIDHASH_VERSION)?resolve_region_coor:resolve_region_id)
int read_region_reference(struct gamedata *data, region **rp, resolve_fun fun);
const char *regionname(const struct region *r, const struct faction *f);

View file

@ -377,7 +377,7 @@ race_t typus2race(unsigned char typus)
return NORACE;
}
static void read_alliances(struct gamedata *data)
static void read_alliances(gamedata *data)
{
storage *store = data->store;
char pbuf[8];
@ -399,8 +399,7 @@ static void read_alliances(struct gamedata *data)
READ_INT(store, &al->flags);
}
if (data->version >= ALLIANCELEADER_VERSION) {
read_reference(&al->_leader, data, read_faction_reference,
resolve_faction);
read_faction_reference(data, &al->_leader, NULL);
READ_INT(store, &id);
}
else {
@ -420,7 +419,6 @@ void read_planes(gamedata *data) {
READ_INT(store, &nread);
while (--nread >= 0) {
int id;
variant fno;
plane *pl;
READ_INT(store, &id);
@ -459,9 +457,10 @@ void read_planes(gamedata *data) {
else {
/* WATCHERS - eliminated in February 2016, ca. turn 966 */
if (data->version < NOWATCH_VERSION) {
fno = read_faction_reference(data);
while (fno.i) {
fno = read_faction_reference(data);
int fno;
READ_INT(data->store, &fno);
while (fno) {
READ_INT(data->store, &fno);
}
}
}
@ -492,7 +491,7 @@ void write_planes(storage *store) {
}
}
void write_alliances(struct gamedata *data)
void write_alliances(gamedata *data)
{
alliance *al = alliances;
while (al) {
@ -509,22 +508,7 @@ void write_alliances(struct gamedata *data)
WRITE_SECTION(data->store);
}
static int resolve_owner(variant id, void *address)
{
region_owner *owner = (region_owner *)address;
int result = 0;
faction *f = NULL;
if (id.i != 0) {
f = findfaction(id.i);
if (f == NULL) {
log_error("region has an invalid owner (%s)", itoa36(id.i));
}
}
owner->owner = f;
return result;
}
static void read_owner(struct gamedata *data, region_owner ** powner)
static void read_owner(gamedata *data, region_owner ** powner)
{
int since_turn;
@ -540,9 +524,7 @@ static void read_owner(struct gamedata *data, region_owner ** powner)
owner->flags = 0;
}
if (data->version >= OWNER_3_VERSION) {
int id;
READ_INT(data->store, &id);
owner->last_owner = id ? findfaction(id) : NULL;
read_faction_reference(data, &owner->last_owner, NULL);
}
else if (data->version >= OWNER_2_VERSION) {
int id;
@ -555,7 +537,7 @@ static void read_owner(struct gamedata *data, region_owner ** powner)
else {
owner->last_owner = NULL;
}
read_reference(owner, data, &read_faction_reference, &resolve_owner);
read_faction_reference(data, &owner->owner, NULL);
*powner = owner;
}
else {
@ -563,7 +545,7 @@ static void read_owner(struct gamedata *data, region_owner ** powner)
}
}
static void write_owner(struct gamedata *data, region_owner * owner)
static void write_owner(gamedata *data, region_owner * owner)
{
if (owner) {
faction *f;
@ -603,8 +585,7 @@ int current_turn(void)
return cturn;
}
static void
writeorder(struct gamedata *data, const struct order *ord,
static void writeorder(gamedata *data, const struct order *ord,
const struct locale *lang)
{
char obuf[1024];
@ -613,7 +594,58 @@ writeorder(struct gamedata *data, const struct order *ord,
WRITE_STR(data->store, obuf);
}
unit *read_unit(struct gamedata *data)
static void read_skills(gamedata *data, unit *u)
{
if (data->version < SKILLSORT_VERSION) {
for (;;) {
int n = NOSKILL, level, weeks;
skill_t sk;
READ_INT(data->store, &n);
sk = (skill_t)n;
if (sk == NOSKILL) break;
READ_INT(data->store, &level);
READ_INT(data->store, &weeks);
if (level) {
skill *sv = add_skill(u, sk);
sv->level = sv->old = (unsigned char)level;
sv->weeks = (unsigned char)weeks;
}
}
}
else {
int i;
READ_INT(data->store, &u->skill_size);
u->skills = malloc(sizeof(skill)*u->skill_size);
for (i = 0; i != u->skill_size; ++i) {
skill *sv = u->skills + i;
int val;
READ_INT(data->store, &val);
sv->id = (skill_t)val;
READ_INT(data->store, &sv->level);
sv->old = sv->level;
READ_INT(data->store, &sv->weeks);
}
}
}
static void write_skills(gamedata *data, const unit *u) {
int i;
skill_t sk = NOSKILL;
WRITE_INT(data->store, u->skill_size);
for (i = 0; i != u->skill_size; ++i) {
skill *sv = u->skills + i;
#ifndef NDEBUG
assert(sv->id > sk);
sk = sv->id;
assert(sv->weeks <= sv->level * 2 + 1);
#endif
WRITE_INT(data->store, sv->id);
WRITE_INT(data->store, sv->level);
WRITE_INT(data->store, sv->weeks);
}
}
unit *read_unit(gamedata *data)
{
unit *u;
const race *rc;
@ -760,20 +792,7 @@ unit *read_unit(struct gamedata *data)
set_order(&u->thisorder, NULL);
assert(u_race(u));
for (;;) {
int n = NOSKILL, level, weeks;
skill_t sk;
READ_INT(data->store, &n);
sk = (skill_t)n;
if (sk == NOSKILL) break;
READ_INT(data->store, &level);
READ_INT(data->store, &weeks);
if (level) {
skill *sv = add_skill(u, sk);
sv->level = sv->old = (unsigned char)level;
sv->weeks = (unsigned char)weeks;
}
}
read_skills(data, u);
read_items(data->store, &u->items);
READ_INT(data->store, &u->hp);
if (u->hp < u->number) {
@ -781,13 +800,14 @@ unit *read_unit(struct gamedata *data)
u->hp = u->number;
}
read_attribs(data, &u->attribs, u);
resolve_unit(u);
return u;
}
void write_unit(struct gamedata *data, const unit * u)
void write_unit(gamedata *data, const unit * u)
{
order *ord;
int i, p = 0;
int p = 0;
unsigned int flags = u->flags & UFL_SAVEMASK;
const race *irace = u_irace(u);
@ -835,18 +855,7 @@ void write_unit(struct gamedata *data, const unit * u)
WRITE_SECTION(data->store);
assert(u_race(u));
for (i = 0; i != u->skill_size; ++i) {
skill *sv = u->skills + i;
assert(sv->weeks <= sv->level * 2 + 1);
if (sv->level > 0) {
WRITE_INT(data->store, sv->id);
WRITE_INT(data->store, sv->level);
WRITE_INT(data->store, sv->weeks);
}
}
WRITE_INT(data->store, -1);
WRITE_SECTION(data->store);
write_skills(data, u);
write_items(data->store, u->items);
WRITE_SECTION(data->store);
if (u->hp == 0 && data->version < NORCSPELL_VERSION) {
@ -859,11 +868,24 @@ void write_unit(struct gamedata *data, const unit * u)
WRITE_SECTION(data->store);
}
static region *readregion(struct gamedata *data, int x, int y)
static void read_regioninfo(gamedata *data, const region *r, char *info, size_t len) {
if (lomem) {
READ_STR(data->store, NULL, 0);
}
else {
READ_STR(data->store, info, len);
if (unicode_utf8_trim(info) != 0) {
log_warning("trim region %d info to '%s'", r->uid, info);
}
}
}
static region *readregion(gamedata *data, int x, int y)
{
region *r = findregion(x, y);
const terrain_type *terrain;
char name[NAMESIZE];
char info[DISPLAYSIZE];
int uid = 0;
int n;
@ -889,16 +911,11 @@ static region *readregion(struct gamedata *data, int x, int y)
}
r->land = 0;
}
if (lomem) {
READ_STR(data->store, NULL, 0);
if (data->version < LANDDISPLAY_VERSION) {
read_regioninfo(data, r, info, sizeof(info));
}
else {
char info[DISPLAYSIZE];
READ_STR(data->store, info, sizeof(info));
if (unicode_utf8_trim(info)!=0) {
log_warning("trim region %d info to '%s'", uid, info);
};
region_setinfo(r, info);
info[0] = '\0';
}
READ_STR(data->store, name, sizeof(name));
@ -915,15 +932,19 @@ static region *readregion(struct gamedata *data, int x, int y)
if (fval(r->terrain, LAND_REGION)) {
r->land = calloc(1, sizeof(land_region));
READ_STR(data->store, name, sizeof(name));
if (unicode_utf8_trim(name)!=0) {
log_warning("trim region %d name to '%s'", uid, name);
};
if (unicode_utf8_trim(name) != 0) {
log_warning("trim region %d name to '%s'", uid, name);
};
r->land->name = strdup(name);
}
if (r->land) {
int i;
rawmaterial **pres = &r->resources;
if (data->version >= LANDDISPLAY_VERSION) {
read_regioninfo(data, r, info, sizeof(info));
}
region_setinfo(r, info);
READ_INT(data->store, &i);
if (i < 0) {
log_error("number of trees in %s is %d.", regionname(r, NULL), i);
@ -1001,7 +1022,11 @@ static region *readregion(struct gamedata *data, int x, int y)
READ_INT(data->store, &n);
rsetmoney(r, n);
}
else {
if (info[0]) {
log_error("%s %d has a description: %s", r->terrain->_name, r->uid, info);
}
}
assert(r->terrain != NULL);
if (r->land) {
@ -1040,27 +1065,27 @@ region *read_region(gamedata *data)
READ_INT(store, &x);
READ_INT(store, &y);
r = readregion(data, x, y);
resolve_region(r);
return r;
}
void writeregion(struct gamedata *data, const region * r)
void writeregion(gamedata *data, const region * r)
{
assert(r);
assert(data);
WRITE_INT(data->store, r->uid);
WRITE_STR(data->store, region_getinfo(r));
WRITE_TOK(data->store, r->terrain->_name);
WRITE_INT(data->store, r->flags & RF_SAVEMASK);
WRITE_INT(data->store, r->age);
WRITE_SECTION(data->store);
if (fval(r->terrain, LAND_REGION)) {
if (r->land) {
const item_type *rht;
struct demand *demand;
rawmaterial *res = r->resources;
assert(r->land);
WRITE_STR(data->store, (const char *)r->land->name);
WRITE_STR(data->store, region_getinfo(r));
assert(rtrees(r, 0) >= 0);
assert(rtrees(r, 1) >= 0);
assert(rtrees(r, 2) >= 0);
@ -1096,11 +1121,9 @@ void writeregion(struct gamedata *data, const region * r)
}
WRITE_TOK(data->store, "end");
WRITE_SECTION(data->store);
#if RELEASE_VERSION>=REGIONOWNER_VERSION
WRITE_INT(data->store, region_get_morale(r));
write_owner(data, r->land->ownership);
WRITE_SECTION(data->store);
#endif
}
write_attribs(data->store, r->attribs, r);
WRITE_SECTION(data->store);
@ -1114,33 +1137,6 @@ void write_region(gamedata *data, const region *r)
writeregion(data, r);
}
static ally **addally(const faction * f, ally ** sfp, int aid, int state)
{
struct faction *af = findfaction(aid);
ally *sf;
state &= ~HELP_OBSERVE;
state &= ~HELP_TRAVEL;
state &= HelpMask();
if (state == 0)
return sfp;
while (*sfp) {
sfp = &(*sfp)->next;
}
sf = ally_add(sfp, af);
if (!sf->faction) {
variant id;
id.i = aid;
ur_add(id, &sf->faction, resolve_faction);
}
sf->status = state & HELP_ALL;
return &sf->next;
}
int get_spell_level_faction(const spell * sp, void * cbdata)
{
static spellbook * common = 0;
@ -1217,9 +1213,8 @@ void _test_write_password(gamedata *data, const faction *f) {
write_password(data, f);
}
faction *read_faction(struct gamedata * data)
faction *read_faction(gamedata * data)
{
ally **sfp;
int planes, n;
faction *f;
char name[DISPLAYSIZE];
@ -1348,28 +1343,17 @@ faction *read_faction(struct gamedata * data)
/* mistakes were made in the past*/
f->options &= ~want(O_JSON);
}
sfp = &f->allies;
for (;;) {
int aid = 0;
READ_INT(data->store, &aid);
if (aid > 0) {
int state;
READ_INT(data->store, &state);
sfp = addally(f, sfp, aid, state);
}
else {
break;
}
}
read_allies(data, f);
read_groups(data, f);
f->spellbook = 0;
if (data->version >= REGIONOWNER_VERSION) {
read_spellbook(FactionSpells() ? &f->spellbook : 0, data, get_spell_level_faction, (void *)f);
}
resolve_faction(f);
return f;
}
void write_faction(struct gamedata *data, const faction * f)
void write_faction(gamedata *data, const faction * f)
{
ally *sf;
ursprung *ur;
@ -1450,7 +1434,7 @@ static int cb_sb_maxlevel(spellbook_entry *sbe, void *cbdata) {
int readgame(const char *filename)
{
int n;
int n, stream_version;
char path[MAX_PATH];
gamedata gdata = { 0 };
storage store;
@ -1467,11 +1451,8 @@ int readgame(const char *filename)
return -1;
}
sz = fread(&gdata.version, sizeof(int), 1, F);
if (sz != sizeof(int) || gdata.version >= INTPAK_VERSION) {
int stream_version;
size_t sz = fread(&stream_version, sizeof(int), 1, F);
assert((sz == 1 && stream_version == STREAM_VERSION) || !"unsupported data format");
}
sz = fread(&stream_version, sizeof(int), 1, F);
assert((sz == 1 && stream_version == STREAM_VERSION) || !"unsupported data format");
assert(gdata.version >= MIN_VERSION || !"unsupported data format");
assert(gdata.version <= MAX_VERSION || !"unsupported data format");
@ -1540,7 +1521,8 @@ struct building *read_building(gamedata *data) {
log_error("building too big: %s (%s size %d of %d), fixing.", buildingname(b), b->type->_name, b->size, b->type->maxsize);
b->size = b->type->maxsize;
}
return b;
resolve_building(b);
return b;
}
void write_ship(gamedata *data, const ship *sh)
@ -1558,7 +1540,7 @@ void write_ship(gamedata *data, const ship *sh)
write_attribs(store, sh->attribs, sh);
}
ship *read_ship(struct gamedata *data)
ship *read_ship(gamedata *data)
{
char name[DISPLAYSIZE];
ship *sh;
@ -1725,6 +1707,9 @@ int read_game(gamedata *data)
/* Burgen */
READ_INT(store, &p);
if (p > 0 && !r->land) {
log_error("%s, uid=%d has %d buildings", regionname(r, NULL), r->uid, p);
}
bp = &r->buildings;
while (--p >= 0) {
@ -1780,10 +1765,6 @@ int read_game(gamedata *data)
}
read_borders(data);
/* Unaufgeloeste Zeiger initialisieren */
log_debug("fixing unresolved references.");
resolve();
log_debug("updating area information for lighthouses.");
for (r = regions; r; r = r->next) {
if (r->flags & RF_LIGHTHOUSE) {

View file

@ -116,12 +116,15 @@ static void test_readwrite_region(CuTest * tc)
gamedata data;
storage store;
region *r;
const char * lipsum = "Lorem ipsum dolor sit amet";
test_setup();
r = test_create_region(0, 0, 0);
free(r->land->name);
r->land->name = strdup(" Hodor ");
CuAssertStrEquals(tc, " Hodor ", r->land->name);
region_setinfo(r, lipsum);
CuAssertStrEquals(tc, lipsum, r->land->display);
mstream_init(&data.strm);
gamedata_init(&data, &store, RELEASE_VERSION);
write_region(&data, r);
@ -132,6 +135,7 @@ static void test_readwrite_region(CuTest * tc)
r = read_region(&data);
CuAssertPtrNotNull(tc, r);
CuAssertStrEquals(tc, "Hodor", r->land->name);
CuAssertStrEquals(tc, lipsum, r->land->display);
regions = r;
mstream_done(&data.strm);

View file

@ -277,6 +277,10 @@ int gift_items(unit * u, int flags)
u->items = NULL;
break;
}
else if (!u3) {
/* pick a last-chance recipient: */
u3 = u2;
}
}
}
if (u->items && u3) {
@ -644,9 +648,7 @@ void a_writesiege(const attrib * a, const void *owner, struct storage *store)
int a_readsiege(attrib * a, void *owner, gamedata *data)
{
int result = read_reference(&a->data.v, data, read_building_reference,
resolve_building);
if (result == 0 && !a->data.v) {
if (read_building_reference(data, (building **)&a->data.v, NULL) <= 0) {
return AT_READ_FAIL;
}
return AT_READ_OK;
@ -747,25 +749,26 @@ void write_unit_reference(const unit * u, struct storage *store)
WRITE_INT(store, (u && u->region) ? u->no : 0);
}
int resolve_unit(variant id, void *address)
void resolve_unit(unit *u)
{
unit *u = NULL;
if (id.i != 0) {
u = findunit(id.i);
if (u == NULL) {
*(unit **)address = NULL;
return -1;
}
}
*(unit **)address = u;
return 0;
resolve(RESOLVE_UNIT | u->no, u);
}
variant read_unit_reference(gamedata *data)
int read_unit_reference(gamedata * data, unit **up, resolve_fun fun)
{
variant var;
READ_INT(data->store, &var.i);
return var;
int id;
READ_INT(data->store, &id);
if (id > 0) {
*up = findunit(id);
if (*up == NULL) {
*up = NULL;
ur_add(RESOLVE_UNIT | id, (void **)up, fun);
}
}
else {
*up = NULL;
}
return id;
}
int get_level(const unit * u, skill_t id)
@ -773,7 +776,7 @@ int get_level(const unit * u, skill_t id)
assert(id != NOSKILL);
if (skill_enabled(id)) {
skill *sv = u->skills;
while (sv != u->skills + u->skill_size) {
while (sv != u->skills + u->skill_size && sv->id <= id) {
if (sv->id == id) {
return sv->level;
}
@ -795,7 +798,7 @@ void set_level(unit * u, skill_t sk, int value)
remove_skill(u, sk);
return;
}
while (sv != u->skills + u->skill_size) {
while (sv != u->skills + u->skill_size && sv->id <= sk) {
if (sv->id == sk) {
sk_set(sv, value);
return;
@ -1186,35 +1189,39 @@ void set_number(unit * u, int count)
void remove_skill(unit * u, skill_t sk)
{
skill *sv = u->skills;
for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) {
int i;
skill *sv;
for (i = 0; i != u->skill_size; ++i) {
sv = u->skills + i;
if (sv->id == sk) {
skill *sl = u->skills + u->skill_size - 1;
if (sl != sv) {
*sv = *sl;
}
memmove(sv, sv + 1, (u->skill_size - i - 1) * sizeof(skill));
--u->skill_size;
return;
}
}
}
skill *add_skill(unit * u, skill_t id)
skill *add_skill(unit * u, skill_t sk)
{
skill *sv = u->skills;
#ifndef NDEBUG
for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) {
assert(sv->id != id);
skill *sv;
int i;
for (i=0; i != u->skill_size; ++i) {
sv = u->skills+i;
if (sv->id >= sk) break;
}
u->skills = realloc(u->skills, (1 + u->skill_size) * sizeof(skill));
sv = u->skills + i;
if (i < u->skill_size) {
assert(sv->id != sk);
memmove(sv + 1, sv, sizeof(skill) * (u->skill_size - i));
}
#endif
++u->skill_size;
u->skills = realloc(u->skills, u->skill_size * sizeof(skill));
sv = (u->skills + u->skill_size - 1);
sv->level = 0;
sv->weeks = 1;
sv->old = 0;
sv->id = id;
if (id == SK_MAGIC && u->faction && !fval(u->faction, FFL_NPC)) {
sv->id = sk;
if (sk == SK_MAGIC && u->faction && !fval(u->faction, FFL_NPC)) {
assert(u->number <= 1);
assert(max_magicians(u->faction) >= u->number);
}
@ -1224,9 +1231,10 @@ skill *add_skill(unit * u, skill_t id)
skill *unit_skill(const unit * u, skill_t sk)
{
skill *sv = u->skills;
while (sv != u->skills + u->skill_size) {
if (sv->id == sk)
while (sv != u->skills + u->skill_size && sv->id <= sk) {
if (sv->id == sk) {
return sv;
}
++sv;
}
return NULL;
@ -1235,7 +1243,7 @@ skill *unit_skill(const unit * u, skill_t sk)
bool has_skill(const unit * u, skill_t sk)
{
skill *sv = u->skills;
while (sv != u->skills + u->skill_size) {
while (sv != u->skills + u->skill_size && sv->id <= sk) {
if (sv->id == sk) {
return (sv->level > 0);
}

View file

@ -19,7 +19,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#ifndef H_KRNL_UNIT_H
#define H_KRNL_UNIT_H
#include <util/variant.h>
#include <util/resolve.h>
#include "types.h"
#include "skills.h"
#include <stddef.h>
@ -182,12 +182,13 @@ extern "C" {
#define GIFT_FRIENDS 1<<1
#define GIFT_PEASANTS 1<<2
int gift_items(struct unit *u, int flags);
void make_zombie(unit * u);
void make_zombie(struct unit * u);
/* see resolve.h */
int resolve_unit(variant data, void *address);
#define RESOLVE_UNIT (TYP_UNIT << 24)
void resolve_unit(struct unit *u);
void write_unit_reference(const struct unit *u, struct storage *store);
variant read_unit_reference(struct gamedata *data);
int read_unit_reference(struct gamedata * data, struct unit **up, resolve_fun fun);
bool leave(struct unit *u, bool force);
bool can_leave(struct unit *u);

View file

@ -31,7 +31,7 @@ static void test_remove_empty_units(CuTest *tc) {
unit *u;
int uid;
test_cleanup();
test_setup();
test_create_world();
u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0));
@ -48,7 +48,7 @@ static void test_remove_empty_units_in_region(CuTest *tc) {
unit *u;
int uid;
test_cleanup();
test_setup();
test_create_world();
u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0));
@ -69,7 +69,7 @@ static void test_remove_units_without_faction(CuTest *tc) {
unit *u;
int uid;
test_cleanup();
test_setup();
test_create_world();
u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0));
@ -85,7 +85,7 @@ static void test_remove_units_with_dead_faction(CuTest *tc) {
unit *u;
int uid;
test_cleanup();
test_setup();
test_create_world();
u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0));
@ -101,7 +101,7 @@ static void test_scale_number(CuTest *tc) {
unit *u;
const struct potion_type *ptype;
test_cleanup();
test_setup();
test_create_world();
ptype = new_potiontype(it_get_or_create(rt_get_or_create("hodor")), 1);
u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0));
@ -122,7 +122,7 @@ static void test_scale_number(CuTest *tc) {
static void test_unit_name(CuTest *tc) {
unit *u;
test_cleanup();
test_setup();
test_create_world();
u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0));
renumber_unit(u, 666);
@ -334,9 +334,50 @@ static void test_inside_building(CuTest *tc) {
test_cleanup();
}
static void test_skills(CuTest *tc) {
unit *u;
skill *sv;
test_setup();
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
sv = add_skill(u, SK_ALCHEMY);
CuAssertPtrNotNull(tc, sv);
CuAssertPtrEquals(tc, sv, u->skills);
CuAssertIntEquals(tc, 1, u->skill_size);
CuAssertIntEquals(tc, SK_ALCHEMY, sv->id);
CuAssertIntEquals(tc, 0, sv->level);
CuAssertIntEquals(tc, 1, sv->weeks);
CuAssertIntEquals(tc, 0, sv->old);
sv = add_skill(u, SK_BUILDING);
CuAssertPtrNotNull(tc, sv);
CuAssertIntEquals(tc, 2, u->skill_size);
CuAssertIntEquals(tc, SK_ALCHEMY, u->skills[0].id);
CuAssertIntEquals(tc, SK_BUILDING, u->skills[1].id);
sv = add_skill(u, SK_LONGBOW);
CuAssertPtrNotNull(tc, sv);
CuAssertPtrEquals(tc, sv, unit_skill(u, SK_LONGBOW));
CuAssertIntEquals(tc, 3, u->skill_size);
CuAssertIntEquals(tc, SK_ALCHEMY, u->skills[0].id);
CuAssertIntEquals(tc, SK_LONGBOW, u->skills[1].id);
CuAssertIntEquals(tc, SK_BUILDING, u->skills[2].id);
CuAssertTrue(tc, !has_skill(u, SK_LONGBOW));
set_level(u, SK_LONGBOW, 1);
CuAssertTrue(tc, has_skill(u, SK_LONGBOW));
remove_skill(u, SK_LONGBOW);
CuAssertIntEquals(tc, SK_BUILDING, u->skills[1].id);
CuAssertIntEquals(tc, 2, u->skill_size);
remove_skill(u, SK_LONGBOW);
CuAssertIntEquals(tc, SK_BUILDING, u->skills[1].id);
CuAssertIntEquals(tc, 2, u->skill_size);
remove_skill(u, SK_BUILDING);
CuAssertIntEquals(tc, SK_ALCHEMY, u->skills[0].id);
CuAssertIntEquals(tc, 1, u->skill_size);
CuAssertTrue(tc, !has_skill(u, SK_LONGBOW));
test_cleanup();
}
static void test_limited_skills(CuTest *tc) {
unit *u;
test_cleanup();
test_setup();
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
CuAssertIntEquals(tc, false, has_limited_skills(u));
set_level(u, SK_ENTERTAINMENT, 1);
@ -592,6 +633,7 @@ CuSuite *get_unit_suite(void)
SUITE_ADD_TEST(suite, test_skill_familiar);
SUITE_ADD_TEST(suite, test_age_familiar);
SUITE_ADD_TEST(suite, test_inside_building);
SUITE_ADD_TEST(suite, test_skills);
SUITE_ADD_TEST(suite, test_limited_skills);
SUITE_ADD_TEST(suite, test_renumber_unit);
SUITE_ADD_TEST(suite, test_name_unit);

View file

@ -960,7 +960,7 @@ static void add_spells(equipment * eq, xmlNodeSetPtr nsetItems)
equipment_addspell(eq, name, level);
}
else {
log_error("spell '%s' for equipment-set '%s' has no level\n", name, eq->name);
log_error("spell '%s' for equipment-set '%s' has no level\n", name, equipment_name(eq));
}
xmlFree(propValue);
}
@ -980,7 +980,7 @@ static void add_skills(equipment * eq, xmlNodeSetPtr nsetSkills)
assert(propValue != NULL);
sk = findskill((const char *)propValue);
if (sk == NOSKILL) {
log_error("unknown skill '%s' in equipment-set %s\n", (const char *)propValue, eq->name);
log_error("unknown skill '%s' in equipment-set %s\n", (const char *)propValue, equipment_name(eq));
xmlFree(propValue);
}
else {
@ -1044,7 +1044,7 @@ add_subsets(xmlDocPtr doc, equipment * eq, xmlNodeSetPtr nsetSubsets)
}
}
if (totalChance > 1.0f) {
log_error("total chance exceeds 1.0: %f in equipment set %s.\n", totalChance, eq->name);
log_error("total chance exceeds 1.0: %f in equipment set %s.\n", totalChance, equipment_name(eq));
}
}
xmlXPathFreeObject(xpathResult);
@ -1069,9 +1069,13 @@ static int parse_equipment(xmlDocPtr doc)
xmlChar *propName = xmlGetProp(node, BAD_CAST "name");
if (propName != NULL) {
equipment *eq = get_or_create_equipment((const char *)propName);
equipment *eq = get_equipment((const char *)propName);
xmlXPathObjectPtr xpathResult;
if (!eq) {
eq = create_equipment((const char *)propName);
}
xpath->node = node;
xpathResult = xmlXPathEvalExpression(BAD_CAST "callback", xpath);

View file

@ -2,6 +2,7 @@
#include <kernel/config.h>
#include "keyword.h"
#include <util/bsdstring.h>
#include <util/language.h>
#include <util/umlaut.h>
#include <util/log.h>
@ -20,7 +21,7 @@ const char * keyword(keyword_t kwd)
if (!result[0]) {
strcpy(result, "keyword::");
}
strcpy(result + 9, keywords[kwd]);
strlcpy(result + 9, keywords[kwd], sizeof(result) - 9);
return result;
}

View file

@ -1559,11 +1559,11 @@ int display_cmd(unit * u, struct order *ord)
break;
case P_REGION:
if (u->faction != region_get_owner(r)) {
if (!r->land || u->faction != region_get_owner(r)) {
cmistake(u, ord, 147, MSG_EVENT);
break;
}
s = &r->display;
s = &r->land->display;
break;
default:

View file

@ -227,7 +227,7 @@ static void test_display_cmd(CuTest *tc) {
ord = create_order(K_DISPLAY, f->locale, "%s Hodor", LOC(f->locale, parameters[P_REGION]));
CuAssertIntEquals(tc, 0, display_cmd(u, ord));
CuAssertPtrEquals(tc, NULL, r->display);
CuAssertPtrEquals(tc, NULL, r->land->display);
free_order(ord);
test_cleanup();

View file

@ -356,9 +356,7 @@ static int read_seenspell(attrib * a, void *owner, struct gamedata *data)
}
sp = find_spell(token);
if (!sp) {
log_warning("read_seenspell: could not find spell '%s'\n", token);
}
if (!sp) {
log_info("read_seenspell: could not find spell '%s'\n", token);
return AT_READ_FAIL;
}
a->data.v = sp;
@ -2264,26 +2262,21 @@ bool create_newfamiliar(unit * mage, unit * familiar)
return true;
}
static int resolve_familiar(variant data, void *addr)
{
unit *familiar;
int result = resolve_unit(data, &familiar);
if (result == 0 && familiar) {
static void * resolve_familiar(int id, void *data) {
if (data) {
unit *familiar = (unit *)data;
attrib *a = a_find(familiar->attribs, &at_familiarmage);
if (a != NULL && a->data.v) {
unit *mage = (unit *)a->data.v;
set_familiar(mage, familiar);
}
}
*(unit **)addr = familiar;
return result;
return data;
}
static int read_familiar(attrib * a, void *owner, struct gamedata *data)
{
int result =
read_reference(&a->data.v, data, read_unit_reference, resolve_familiar);
if (result == 0 && a->data.v == NULL) {
if (read_unit_reference(data, (unit **)&a->data.v, resolve_familiar) <= 0) {
return AT_READ_FAIL;
}
return AT_READ_OK;
@ -2348,52 +2341,42 @@ unit *has_clone(unit * mage)
return NULL;
}
static int resolve_clone(variant data, void *addr)
{
unit *clone;
int result = resolve_unit(data, &clone);
if (result == 0 && clone) {
static void * resolve_clone(int id, void *data) {
if (data) {
unit *clone = (unit *)data;
attrib *a = a_find(clone->attribs, &at_clonemage);
if (a != NULL && a->data.v) {
unit *mage = (unit *)a->data.v;
set_clone(mage, clone);
}
}
*(unit **)addr = clone;
return result;
return data;
}
static int read_clone(attrib * a, void *owner, struct gamedata *data)
{
int result =
read_reference(&a->data.v, data, read_unit_reference, resolve_clone);
if (result == 0 && a->data.v == NULL) {
if (read_unit_reference(data, (unit **)&a->data.v, resolve_clone) <= 0) {
return AT_READ_FAIL;
}
return AT_READ_OK;
}
/* mages */
static int resolve_mage(variant data, void *addr)
{
unit *mage;
int result = resolve_unit(data, &mage);
if (result == 0 && mage) {
static void * resolve_mage(int id, void *data) {
if (data) {
unit *mage = (unit *)data;
attrib *a = a_find(mage->attribs, &at_familiar);
if (a != NULL && a->data.v) {
unit *familiar = (unit *)a->data.v;
set_familiar(mage, familiar);
}
}
*(unit **)addr = mage;
return result;
return data;
}
static int read_magician(attrib * a, void *owner, struct gamedata *data)
{
int result =
read_reference(&a->data.v, data, read_unit_reference, resolve_mage);
if (result == 0 && a->data.v == NULL) {
if (read_unit_reference(data, (unit **)&a->data.v, resolve_mage) <= 0) {
return AT_READ_FAIL;
}
return AT_READ_OK;
@ -3009,30 +2992,36 @@ int cast_spell(struct castorder *co)
static critbit_tree cb_spellbooks;
#define SBNAMELEN 16
typedef struct sb_entry {
char key[SBNAMELEN];
spellbook *value;
} sb_entry;
spellbook * get_spellbook(const char * name)
{
char buffer[64];
spellbook * result;
void * match;
size_t len = strlen(name);
const void * match;
if (cb_find_prefix(&cb_spellbooks, name, strlen(name), &match, 1, 0) > 0) {
cb_get_kv(match, &result, sizeof(result));
if (len >= SBNAMELEN) {
log_error("spellbook name is longer than %d bytes: %s", SBNAMELEN-1, name);
return NULL;
}
else {
size_t len = strlen(name);
result = create_spellbook(name);
assert(strlen(name) + sizeof(result) < sizeof(buffer));
len = cb_new_kv(name, len, &result, sizeof(result), buffer);
if (cb_insert(&cb_spellbooks, buffer, len) == CB_EXISTS) {
match = cb_find_str(&cb_spellbooks, name);
if (!match) {
sb_entry ent;
memset(ent.key, 0, SBNAMELEN);
memcpy(ent.key, name, len);
ent.value = create_spellbook(name);
if (cb_insert(&cb_spellbooks, &ent, sizeof(ent)) == CB_EXISTS) {
log_error("cb_insert failed although cb_find returned nothing for spellbook=%s", name);
assert(!"should not happen");
}
result = 0;
if (cb_find_prefix(&cb_spellbooks, name, strlen(name), &match, 1, 0) > 0) {
cb_get_kv(match, &result, sizeof(result));
}
return ent.value;
}
return result;
return ((const sb_entry *)match)->value;
}
void free_spellbook(spellbook *sb) {
@ -3041,9 +3030,8 @@ void free_spellbook(spellbook *sb) {
}
static int free_spellbook_cb(const void *match, const void *key, size_t keylen, void *data) {
spellbook *sb;
cb_get_kv(match, &sb, sizeof(sb));
free_spellbook(sb);
const sb_entry *ent = (const sb_entry *)match;
free_spellbook(ent->value);
return 0;
}

View file

@ -51,7 +51,18 @@ void test_updatespells(CuTest * tc)
test_cleanup();
}
void test_spellbooks(CuTest * tc)
static void test_get_spellbook(CuTest * tc)
{
spellbook *sb;
test_setup();
CuAssertPtrNotNull(tc, sb = get_spellbook("hodorhodorhodor"));
CuAssertPtrEquals(tc, sb, get_spellbook("hodorhodorhodor"));
CuAssertTrue(tc, sb != get_spellbook("hodor"));
test_cleanup();
}
static void test_spellbooks(CuTest * tc)
{
spell *sp;
spellbook *herp, *derp;
@ -445,24 +456,6 @@ static void test_max_spellpoints(CuTest *tc) {
test_cleanup();
}
static void test_familiar_mage(CuTest *tc) {
unit *um, *uf, *ut;
test_setup();
um = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
uf = test_create_unit(um->faction, um->region);
ut = test_create_unit(um->faction, um->region);
set_number(ut, 0);
CuAssertTrue(tc, create_newfamiliar(um, uf));
CuAssertTrue(tc, is_familiar(uf));
CuAssertTrue(tc, !is_familiar(um));
CuAssertPtrEquals(tc, um, get_familiar_mage(uf));
CuAssertPtrEquals(tc, uf, get_familiar(um));
CuAssertPtrEquals(tc, NULL, give_men(1, um, ut, NULL));
CuAssertPtrEquals(tc, ut, get_familiar_mage(uf));
test_cleanup();
}
static void test_illusioncastle(CuTest *tc)
{
building *b;
@ -490,6 +483,7 @@ CuSuite *get_magic_suite(void)
SUITE_ADD_TEST(suite, test_multi_cast);
SUITE_ADD_TEST(suite, test_updatespells);
SUITE_ADD_TEST(suite, test_spellbooks);
SUITE_ADD_TEST(suite, test_get_spellbook);
SUITE_ADD_TEST(suite, test_pay_spell);
SUITE_ADD_TEST(suite, test_pay_spell_failure);
SUITE_ADD_TEST(suite, test_getspell_unit);
@ -502,6 +496,5 @@ CuSuite *get_magic_suite(void)
SUITE_ADD_TEST(suite, test_magic_resistance);
SUITE_ADD_TEST(suite, test_max_spellpoints);
SUITE_ADD_TEST(suite, test_illusioncastle);
DISABLE_TEST(suite, test_familiar_mage);
return suite;
}

View file

@ -1,4 +1,4 @@
/*
/*
+-------------------+ Christian Schlittchen <corwin@amber.kn-bremen.de>
| | Enno Rehling <enno@eressea.de>
| Eressea PBEM host | Katja Zedel <katze@felidae.kn-bremen.de>
@ -14,7 +14,7 @@
#include <kernel/config.h>
#include "xmas.h"
/* kernel includes */
/* kernel includes */
#include <kernel/building.h>
#include <kernel/faction.h>
#include <kernel/item.h>
@ -50,10 +50,7 @@ static void xmasgate_write(const trigger * t, struct storage *store)
static int xmasgate_read(trigger * t, struct gamedata *data)
{
int bc =
read_reference(&t->data.v, data, read_building_reference,
resolve_building);
if (bc == 0 && !t->data.v) {
if (read_building_reference(data, (building **)&t->data.v, NULL) <= 0) {
return AT_READ_FAIL;
}
return AT_READ_OK;

View file

@ -612,7 +612,7 @@ static void recruit_dracoids(unit * dragon, int size)
name_unit(un);
change_money(dragon, -un->number * 50);
equip_unit(un, get_equipment("recruited_dracoid"));
equip_unit(un, get_equipment("new_dracoid"));
setstatus(un, ST_FIGHT);
for (weapon = un->items; weapon; weapon = weapon->next) {
@ -863,7 +863,7 @@ static int nrand(int start, int sub)
unit *spawn_seaserpent(region *r, faction *f) {
unit *u = create_unit(r, f, 1, get_race(RC_SEASERPENT), 0, NULL, NULL);
fset(u, UFL_ISNEW | UFL_MOVED);
equip_unit(u, get_equipment("monster_seaserpent"));
equip_unit(u, get_equipment("seed_seaserpent"));
return u;
}
@ -894,7 +894,7 @@ void spawn_dragons(void)
u = create_unit(r, monsters, nrand(30, 20) + 1, get_race(RC_DRAGON), 0, NULL, NULL);
}
fset(u, UFL_ISNEW | UFL_MOVED);
equip_unit(u, get_equipment("monster_dragon"));
equip_unit(u, get_equipment("seed_dragon"));
log_debug("spawning %d %s in %s.\n", u->number,
LOC(default_locale,
@ -1132,7 +1132,7 @@ faction *get_or_create_monsters(void)
if (!f) {
const race *rc = rc_get_or_create("dragon");
const char *email = config_get("monster.email");
f = addfaction(email ? email : "noreply@eressea.de", NULL, rc, default_locale, 0);
f = addfaction(email ? email : NULL, NULL, rc, default_locale, 0);
renumber_faction(f, MONSTER_ID);
faction_setname(f, "Monster");
fset(f, FFL_NPC | FFL_NOIDLEOUT);

View file

@ -263,7 +263,7 @@ static void get_villagers(region * r, unit * u)
u);
leave(newunit, true);
fset(newunit, UFL_ISNEW | UFL_MOVED);
equip_unit(newunit, get_equipment("random_villagers"));
equip_unit(newunit, get_equipment("rand_villagers"));
}
static void get_allies(region * r, unit * u)
@ -282,7 +282,7 @@ static void get_allies(region * r, unit * u)
if (get_money(u) / u->number < 100 + rng_int() % 200)
return;
name = "random_plain_men";
equip = "random_plain";
equip = "rand_plain";
number = rng_int() % 8 + 2;
break;
}
@ -293,7 +293,7 @@ static void get_allies(region * r, unit * u)
return;
}
name = "random_forest_men";
equip = "random_forest";
equip = "rand_forest";
number = rng_int() % 6 + 2;
}
break;
@ -303,7 +303,7 @@ static void get_allies(region * r, unit * u)
return;
}
name = "random_swamp_men";
equip = "random_swamp";
equip = "rand_swamp";
number = rng_int() % 6 + 2;
break;
@ -312,7 +312,7 @@ static void get_allies(region * r, unit * u)
return;
}
name = "random_desert_men";
equip = "random_desert";
equip = "rand_desert";
number = rng_int() % 12 + 2;
break;
@ -321,7 +321,7 @@ static void get_allies(region * r, unit * u)
return;
}
name = "random_highland_men";
equip = "random_highland";
equip = "rand_highland";
number = rng_int() % 8 + 2;
break;
@ -330,7 +330,7 @@ static void get_allies(region * r, unit * u)
return;
}
name = "random_mountain_men";
equip = "random_mountain";
equip = "rand_mountain";
number = rng_int() % 6 + 2;
break;
@ -339,7 +339,7 @@ static void get_allies(region * r, unit * u)
return;
}
name = "random_glacier_men";
equip = "random_glacier";
equip = "rand_glacier";
number = rng_int() % 4 + 2;
break;

View file

@ -1069,15 +1069,15 @@ void report_region(struct stream *out, const region * r, faction * f)
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();
if (r->display && r->display[0]) {
if (r->land && r->land->display && r->land->display[0]) {
bytes = (int)strlcpy(bufp, " ", size);
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();
bytes = (int)strlcpy(bufp, r->display, size);
bytes = (int)strlcpy(bufp, r->land->display, size);
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();
n = r->display[strlen(r->display) - 1];
n = r->land->display[strlen(r->land->display) - 1];
if (n != '!' && n != '?' && n != '.') {
bytes = (int)strlcpy(bufp, ".", size);
if (wrptr(&bufp, &size, bytes) != 0)

View file

@ -1616,11 +1616,13 @@ int reports(void)
}
for (f = factions; f; f = f->next) {
int error = write_reports(f, ltime);
if (error)
retval = error;
if (mailit)
write_script(mailit, f);
if (f->email && !fval(f, FFL_NPC)) {
int error = write_reports(f, ltime);
if (error)
retval = error;
if (mailit)
write_script(mailit, f);
}
}
if (mailit)
fclose(mailit);
@ -1701,7 +1703,7 @@ static void var_free_regions(variant x) /*-V524 */
const char *trailinto(const region * r, const struct locale *lang)
{
char ref[32];
static char ref[32];
const char *s;
if (r) {
const char *tname = terrain_name(r);
@ -2145,23 +2147,6 @@ static void eval_int36(struct opstack **stack, const void *userdata)
/*** END MESSAGE RENDERING ***/
#include <util/nrmessage.h>
static void log_orders(const struct message *msg)
{
char buffer[4096];
int i;
for (i = 0; i != msg->type->nparameters; ++i) {
if (msg->type->types[i]->copy == &var_copy_order) {
const char *section = nr_section(msg);
nr_render(msg, default_locale, buffer, sizeof(buffer), NULL);
log_debug("MESSAGE [%s]: %s\n", section, buffer);
break;
}
}
}
int stream_printf(struct stream * out, const char *format, ...)
{
va_list args;
@ -2224,8 +2209,6 @@ void register_reports(void)
register_argtype("items", var_free_resources, var_copy_items, VAR_VOIDPTR);
register_argtype("regions", var_free_regions, NULL, VAR_VOIDPTR);
msg_log_create = &log_orders;
/* register functions that turn message contents to readable strings */
add_function("alliance", &eval_alliance);
add_function("region", &eval_region);

View file

@ -279,13 +279,13 @@ static void test_bufunit(CuTest *tc) {
bufunit(u->faction, u, 0, 0, buffer, sizeof(buffer));
CuAssertStrEquals(tc, "Hodor (1), 1 human, aggressiv.", buffer);
set_level(u, SK_SAILING, 1);
bufunit(u->faction, u, 0, 0, buffer, sizeof(buffer));
CuAssertStrEquals(tc, "Hodor (1), 1 human, aggressiv, Talente: Segeln 1.", buffer);
set_level(u, SK_ALCHEMY, 1);
bufunit(u->faction, u, 0, 0, buffer, sizeof(buffer));
CuAssertStrEquals(tc, "Hodor (1), 1 human, aggressiv, Talente: Segeln 1, Alchemie 2.", buffer);
CuAssertStrEquals(tc, "Hodor (1), 1 human, aggressiv, Talente: Alchemie 2.", buffer);
set_level(u, SK_SAILING, 1);
bufunit(u->faction, u, 0, 0, buffer, sizeof(buffer));
CuAssertStrEquals(tc, "Hodor (1), 1 human, aggressiv, Talente: Alchemie 2, Segeln 1.", buffer);
f = test_create_faction(0);
f->locale = get_or_create_locale("de");

View file

@ -519,7 +519,7 @@ static void make_familiar(unit * familiar, unit * mage)
const struct equipment *eq;
char eqname[64];
const race * rc = u_race(familiar);
snprintf(eqname, sizeof(eqname), "%s_familiar", rc->_name);
snprintf(eqname, sizeof(eqname), "fam_%s", rc->_name);
eq = get_equipment(eqname);
if (eq != NULL) {
equip_items(&familiar->items, eq);
@ -2892,47 +2892,20 @@ static curse *mk_deathcloud(unit * mage, region * r, double force, int duration)
return c;
}
#define COMPAT_DEATHCLOUD
#ifdef COMPAT_DEATHCLOUD
static int dc_read_compat(struct attrib *a, void *target, gamedata *data)
/* return AT_READ_OK on success, AT_READ_FAIL if attrib needs removal */
{
struct storage *store = data->store;
region *r = NULL;
unit *u;
variant var;
int duration;
float strength;
int rx, ry;
UNUSED_ARG(a);
UNUSED_ARG(target);
READ_INT(store, &duration);
READ_FLT(store, &strength);
READ_INT(store, &var.i);
u = findunit(var.i);
/* this only affects really old data. no need to change: */
READ_INT(store, &rx);
READ_INT(store, &ry);
r = findregion(rx, ry);
if (r != NULL) {
double effect;
curse *c;
effect = strength;
c =
create_curse(u, &r->attribs, &ct_deathcloud, strength * 2, duration,
effect, 0);
c->data.v = r;
if (u == NULL) {
ur_add(var, &c->magician, resolve_unit);
}
}
return AT_READ_FAIL; /* we don't care for the attribute. */
READ_INT(store, NULL);
READ_FLT(store, NULL);
READ_INT(store, NULL);
READ_INT(store, NULL);
READ_INT(store, NULL);
return AT_READ_DEPR; /* we don't care for the attribute. */
}
#endif
/* ------------------------------------------------------------- */
/* Name: Todeswolke
@ -6705,9 +6678,7 @@ void register_spells(void)
{
register_borders();
#ifdef COMPAT_DEATHCLOUD
at_deprecate("zauber_todeswolke", dc_read_compat);
#endif
/* init_firewall(); */
ct_register(&ct_firewall);

View file

@ -92,11 +92,9 @@ static void wall_read(connection * b, gamedata * data)
static wall_data dummy;
wall_data *fd = b->data.v ? (wall_data *)b->data.v : &dummy;
read_reference(&fd->mage, data, read_unit_reference, resolve_unit);
read_unit_reference(data, &fd->mage, NULL);
READ_INT(data->store, &fd->force);
if (data->version >= NOBORDERATTRIBS_VERSION) {
READ_INT(data->store, &fd->countdown);
}
READ_INT(data->store, &fd->countdown);
fd->active = true;
}

View file

@ -160,7 +160,7 @@ void spawn_braineaters(float chance)
unit *u =
create_unit(r, f0, 1 + rng_int() % 10 + rng_int() % 10,
get_race(RC_HIRNTOETER), 0, NULL, NULL);
equip_unit(u, get_equipment("monster_braineater"));
equip_unit(u, get_equipment("seed_braineater"));
next = rng_int() % (int)(chance * 100);
}

View file

@ -83,16 +83,10 @@ static void changefaction_write(const trigger * t, struct storage *store)
static int changefaction_read(trigger * t, gamedata *data)
{
variant var;
changefaction_data *td = (changefaction_data *)t->data.v;
read_reference(&td->unit, data, read_unit_reference, resolve_unit);
var = read_faction_reference(data);
if (var.i == 0) {
return AT_READ_FAIL;
}
ur_add(var, &td->faction, resolve_faction);
return AT_READ_OK;
read_unit_reference(data, &td->unit, NULL);
return read_faction_reference(data, &td->faction, NULL) > 0 ? AT_READ_OK : AT_READ_FAIL;
}
trigger_type tt_changefaction = {

View file

@ -89,9 +89,9 @@ static void changerace_write(const trigger * t, struct storage *store)
static int changerace_read(trigger * t, gamedata *data)
{
changerace_data *td = (changerace_data *)t->data.v;
read_reference(&td->u, data, read_unit_reference, resolve_unit);
td->race = (const struct race *)read_race_reference(data->store).v;
td->irace = (const struct race *)read_race_reference(data->store).v;
read_unit_reference(data, &td->u, NULL);
td->race = read_race_reference(data->store);
td->irace = read_race_reference(data->store);
return AT_READ_OK;
}

View file

@ -70,9 +70,7 @@ static void clonedied_write(const trigger * t, struct storage *store)
static int clonedied_read(trigger * t, gamedata *data)
{
int result =
read_reference(&t->data.v, data, read_unit_reference, resolve_unit);
if (result == 0 && t->data.v == NULL) {
if (read_unit_reference(data, (unit **)&t->data.v, NULL) <= 0) {
return AT_READ_FAIL;
}
return AT_READ_OK;

View file

@ -98,8 +98,8 @@ static int createcurse_read(trigger * t, gamedata *data)
char zText[128];
float flt;
read_reference(&td->mage, data, read_unit_reference, resolve_unit);
read_reference(&td->target, data, read_unit_reference, resolve_unit);
read_unit_reference(data, &td->mage, NULL);
read_unit_reference(data, &td->target, NULL);
READ_TOK(data->store, zText, sizeof(zText));
td->type = ct_find(zText);

View file

@ -90,22 +90,16 @@ static void createunit_write(const trigger * t, struct storage *store)
static int createunit_read(trigger * t, gamedata *data)
{
createunit_data *td = (createunit_data *)t->data.v;
variant var;
int id;
int result = AT_READ_OK;
var = read_faction_reference(data);
if (var.i > 0) {
td->f = findfaction(var.i);
if (!td->f) {
ur_add(var, &td->f, resolve_faction);
}
}
else {
id = read_faction_reference(data, &td->f, NULL);
if (id <= 0) {
result = AT_READ_FAIL;
}
read_reference(&td->r, data, read_region_reference,
RESOLVE_REGION(data->version));
td->race = (const struct race *)read_race_reference(data->store).v;
read_region_reference(data, &td->r, NULL);
td->race = read_race_reference(data->store);
if (!td->race) {
result = AT_READ_FAIL;
}

View file

@ -74,16 +74,11 @@ static void gate_write(const trigger * t, struct storage *store)
static int gate_read(trigger * t, gamedata *data)
{
gate_data *gd = (gate_data *)t->data.v;
int bc = read_building_reference(data, &gd->gate, NULL);
int rc = read_region_reference(data, &gd->target, NULL);
int bc =
read_reference(&gd->gate, data, read_building_reference, resolve_building);
int rc =
read_reference(&gd->target, data, read_region_reference,
RESOLVE_REGION(data->version));
if (bc == 0 && rc == 0) {
if (!gd->gate || !gd->target)
return AT_READ_FAIL;
if (bc <= 0 && rc <= 0) {
return AT_READ_FAIL;
}
return AT_READ_OK;
}

View file

@ -86,15 +86,16 @@ static int giveitem_read(trigger * t, gamedata *data)
{
giveitem_data *td = (giveitem_data *)t->data.v;
char zText[128];
int result;
int result = read_reference(&td->u, data, read_unit_reference, resolve_unit);
result = read_unit_reference(data, &td->u, NULL);
READ_INT(data->store, &td->number);
READ_TOK(data->store, zText, sizeof(zText));
td->itype = it_find(zText);
assert(td->itype);
if (result == 0 && td->u == NULL) {
if (result == 0) {
return AT_READ_FAIL;
}
return AT_READ_OK;

View file

@ -60,9 +60,7 @@ static void killunit_write(const trigger * t, struct storage *store)
static int killunit_read(trigger * t, gamedata *data)
{
int result = read_reference(&t->data.v, data, read_unit_reference,
resolve_unit);
if (result == 0 && t->data.v == NULL) {
if (read_unit_reference(data, (unit **)&t->data.v, NULL) == 0) {
return AT_READ_FAIL;
}
return AT_READ_OK;

View file

@ -125,11 +125,8 @@ static void shock_write(const trigger * t, struct storage *store)
}
}
static int shock_read(trigger * t, gamedata *data)
{
int result =
read_reference(&t->data.v, data, read_unit_reference, resolve_unit);
if (result == 0 && t->data.v == NULL) {
static int shock_read(trigger * t, gamedata *data) {
if (read_unit_reference(data, (unit **)&t->data.v, NULL) <= 0) {
return AT_READ_FAIL;
}
return AT_READ_OK;

View file

@ -5,10 +5,7 @@
#include <stream.h>
#define INTPAK_VERSION 329 /* in binary, ints can get packed. starting with E2/572 */
#define NOZEROIDS_VERSION 330 /* 2008-05-16 zero is not a valid ID for anything (including factions) */
#define NOBORDERATTRIBS_VERSION 331 /* 2008-05-17 connection::attribs has been moved to userdata */
#define UIDHASH_VERSION 332 /* 2008-05-22 borders use the region.uid to store */
#define UIDHASH_VERSION 332 /* 2008-05-22 = 572 borders use the region.uid to store */
#define REGIONOWNER_VERSION 333 /* 2009-05-14 regions have owners and morale */
#define ALLIANCELEADER_VERSION 333 /* alliances have a leader */
#define CURSEFLOAT_VERSION 334 /* all curse-effects are float */
@ -36,12 +33,14 @@
#define NOLANDITEM_VERSION 356 /* land_region has no items */
#define NORCSPELL_VERSION 357 /* data contains no RC_SPELL units */
#define SORTKEYS_VERSION 358 /* at_keys is sorted */
#define FAMILIAR_FIX_VERSION 359 /* at_keys is sorted */
#define FAMILIAR_FIX_VERSION 359 /* familiar links are fixed */
#define SKILLSORT_VERSION 360 /* u->skills is sorted */
#define LANDDISPLAY_VERSION 360 /* r.display is now in r.land.display */
/* unfinished: */
#define CRYPT_VERSION 400 /* passwords are encrypted */
#define RELEASE_VERSION FAMILIAR_FIX_VERSION /* current datafile */
#define MIN_VERSION INTPAK_VERSION /* minimal datafile we support */
#define RELEASE_VERSION SKILLSORT_VERSION /* current datafile */
#define MIN_VERSION UIDHASH_VERSION /* minimal datafile we support */
#define MAX_VERSION RELEASE_VERSION /* change this if we can need to read the future datafile, and we can do so */
#define STREAM_VERSION 2 /* internal encoding of binary files */

View file

@ -17,80 +17,85 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
**/
#include <platform.h>
#include <selist.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "resolve.h"
#include "storage.h"
#include "variant.h"
typedef struct unresolved {
void *ptrptr;
/* address to pass to the resolve-function */
variant data;
int id;
/* information on how to resolve the missing object */
resolve_fun resolve;
/* function to resolve the unknown object */
selist *addrs;
/* address to pass to the resolve-function */
} unresolved;
#define BLOCKSIZE 1024
static unresolved *ur_list;
static unresolved *ur_begin;
static unresolved *ur_current;
#define HASHSIZE 1024 /* must be a power of 2 */
static unresolved ur_hash[HASHSIZE];
variant read_int(struct storage *store)
{
variant var;
READ_INT(store, &var.i);
return var;
int ur_key(int id) {
int h = id ^ (id >> 16);
return h & (HASHSIZE - 1);
}
int
read_reference(void *address, struct gamedata * data, read_fun reader,
resolve_fun resolver)
void ur_add(int id, void **addr, resolve_fun fun)
{
variant var = reader(data);
int result = resolver(var, address);
if (result != 0) {
ur_add(var, address, resolver);
}
return result;
}
int h, i;
void ur_add(variant data, void *ptrptr, resolve_fun fun)
{
assert(ptrptr);
if (ur_list == NULL) {
ur_list = malloc(BLOCKSIZE * sizeof(unresolved));
ur_begin = ur_current = ur_list;
}
else if (ur_current - ur_begin == BLOCKSIZE - 1) {
ur_begin = malloc(BLOCKSIZE * sizeof(unresolved));
ur_current->data.v = ur_begin;
ur_current = ur_begin;
}
ur_current->data = data;
ur_current->resolve = fun;
ur_current->ptrptr = ptrptr;
++ur_current;
ur_current->resolve = NULL;
ur_current->data.v = NULL;
}
void resolve(void)
{
unresolved *ur = ur_list;
while (ur) {
if (ur->resolve == NULL) {
ur = ur->data.v;
free(ur_list);
ur_list = ur;
continue;
assert(id > 0);
assert(addr);
assert(!*addr);
h = ur_key(id);
for (i = 0; i != HASHSIZE; ++i) {
int k = h + i;
if (k >= HASHSIZE) k -= HASHSIZE;
if (ur_hash[k].id <= 0) {
ur_hash[k].id = id;
ur_hash[k].resolve = fun;
selist_push(&ur_hash[k].addrs, addr);
return;
}
if (ur_hash[k].id == id && ur_hash[k].resolve == fun) {
ur_hash[k].resolve = fun;
selist_push(&ur_hash[k].addrs, addr);
return;
}
}
assert(!"hash table is full");
}
static bool addr_cb(void *data, void *more) {
void **addr = (void **)data;
*addr = more;
return true;
}
void resolve(int id, void *data)
{
int h, i;
h = ur_key(id);
for (i = 0; i != HASHSIZE; ++i) {
int k = h + i;
if (k >= HASHSIZE) k -= HASHSIZE;
if (ur_hash[k].id == 0) break;
else if (ur_hash[k].id == id) {
if (ur_hash[k].resolve) {
data = ur_hash[k].resolve(id, data);
}
selist_foreach_ex(ur_hash[k].addrs, addr_cb, data);
selist_free(ur_hash[k].addrs);
ur_hash[k].addrs = NULL;
ur_hash[k].id = -1;
}
assert(ur->ptrptr);
ur->resolve(ur->data, ur->ptrptr);
++ur;
}
free(ur_list);
ur_list = NULL;
}

View file

@ -19,7 +19,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#ifndef RESOLVE_H
#define RESOLVE_H
#include "variant.h"
struct storage;
struct gamedata;
@ -27,15 +26,11 @@ struct gamedata;
extern "C" {
#endif
typedef int(*resolve_fun) (variant data, void *address);
typedef variant(*read_fun) (struct gamedata * data);
extern int read_reference(void *address, struct gamedata *data,
read_fun reader, resolve_fun resolver);
typedef void *(*resolve_fun) (int id, void *data);
typedef int(*read_fun) (struct gamedata * data);
extern void ur_add(variant data, void *address, resolve_fun fun);
extern void resolve(void);
extern variant read_int(struct storage *store);
void ur_add(int id, void **addr, resolve_fun fun);
void resolve(int id, void *data);
#ifdef __cplusplus
}

View file

@ -71,7 +71,7 @@ void opstack_push(opstack ** stackp, variant data)
** static buffer malloc
**/
#define BBUFSIZE 0x20000
#define BBUFSIZE 0x10000
static struct {
char *begin;
char *end;
@ -81,16 +81,13 @@ static struct {
char *balloc(size_t size)
{
static int init = 0; /* STATIC_XCALL: used across calls */
static int init = 0;
if (!init) {
init = 1;
buffer.current = buffer.begin = malloc(BBUFSIZE * sizeof(char));
buffer.end = buffer.begin + BBUFSIZE;
}
if (buffer.current + size > buffer.end) {
/* out of memory! */
return NULL;
}
assert(buffer.current + size <= buffer.end || !"balloc is out of memory");
buffer.last = buffer.current;
buffer.current += size;
return buffer.last;
@ -99,6 +96,7 @@ char *balloc(size_t size)
void bfree(char *c)
/* only release this memory if it was part of the last allocation
* that's a joke, but who cares.
* I'm afraid I don't get the joke.
*/
{
if (c >= buffer.last && c < buffer.current)

View file

@ -21,6 +21,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "assert.h"
#include "log.h"
#include "bsdstring.h"
#include "unicode.h"
#include <ctype.h>
@ -211,7 +212,7 @@ void addtoken(tnode ** root, const char *str, variant id)
if (lcs == replace[i].ucs) {
char zText[1024];
memcpy(zText, replace[i].str, 3);
strcpy(zText + 2, (const char *)str + len);
strlcpy(zText + 2, (const char *)str + len, sizeof(zText)-2);
addtoken(root, zText, id);
break;
}

View file

@ -96,36 +96,15 @@ static void wormhole_write(const struct attrib *a, const void *owner, struct sto
write_region_reference(exit, store);
}
/** conversion code, turn 573, 2008-05-23 */
static int resolve_exit(variant id, void *address)
{
building *b = findbuilding(id.i);
region **rp = address;
if (b) {
*rp = b->region;
return 0;
}
*rp = NULL;
return -1;
}
static int wormhole_read(struct attrib *a, void *owner, struct gamedata *data)
{
storage *store = data->store;
resolve_fun resolver = (data->version < UIDHASH_VERSION)
? resolve_exit : resolve_region_id;
read_fun reader = (data->version < UIDHASH_VERSION)
? read_building_reference : read_region_reference;
int id;
if (data->version < ATTRIBOWNER_VERSION) {
READ_INT(store, NULL);
READ_INT(data->store, NULL);
}
if (read_reference(&a->data.v, data, reader, resolver) == 0) {
if (!a->data.v) {
return AT_READ_FAIL;
}
}
return AT_READ_OK;
id = read_region_reference(data, (region **)&a->data.v, NULL);
return (id <= 0) ? AT_READ_FAIL : AT_READ_OK;
}
static attrib_type at_wormhole = {