implementing free_gamedata():

- fixed freeing of borders
- fixed freeing of global.attribs
- more static-variable reinitialization
- reseting the RNG

removed border.attribs:
- new savegame-version
This commit is contained in:
Enno Rehling 2008-05-22 14:40:21 +00:00
parent 1052e46613
commit 644d0d9a4a
12 changed files with 162 additions and 118 deletions

View File

@ -20,6 +20,9 @@
#include "save.h" #include "save.h"
#include "terrain.h" #include "terrain.h"
#include "unit.h" #include "unit.h"
#include "version.h"
#include <spells/spells.h> /* for backward compat reading of bt_firewall */
#include <util/attrib.h> #include <util/attrib.h>
#include <util/log.h> #include <util/log.h>
@ -33,7 +36,8 @@
unsigned int nextborder = 0; unsigned int nextborder = 0;
border * borders[BMAXHASH]; #define BORDER_MAXHASH 8191
border * borders[BORDER_MAXHASH];
border_type * bordertypes; border_type * bordertypes;
@ -41,8 +45,20 @@ void
free_borders(void) free_borders(void)
{ {
int i; int i;
for (i=0;i!=BMAXHASH;++i) { for (i=0;i!=BORDER_MAXHASH;++i) {
borders[i] = NULL; while (borders[i]) {
border * b = borders[i];
borders[i] = b->nexthash;
while (b) {
border * bf = b;
b = b->next;
assert(b==NULL || b->nexthash==NULL);
if (bf->type->destroy) {
bf->type->destroy(bf);
}
free(bf);
}
}
} }
} }
@ -50,7 +66,7 @@ border *
find_border(unsigned int id) find_border(unsigned int id)
{ {
int key; int key;
for (key=0;key!=BMAXHASH;key++) { for (key=0;key!=BORDER_MAXHASH;key++) {
border * bhash; border * bhash;
for (bhash=borders[key];bhash!=NULL;bhash=bhash->nexthash) { for (bhash=borders[key];bhash!=NULL;bhash=bhash->nexthash) {
border * b; border * b;
@ -74,7 +90,7 @@ get_borders_i(const region * r1, const region * r2)
int key = reg_hashkey(r1); int key = reg_hashkey(r1);
int k2 = reg_hashkey(r2); int k2 = reg_hashkey(r2);
key = min(k2, key) % BMAXHASH; key = min(k2, key) % BORDER_MAXHASH;
bp = &borders[key]; bp = &borders[key];
while (*bp) { while (*bp) {
border * b = *bp; border * b = *bp;
@ -113,10 +129,6 @@ new_border(border_type * type, region * from, region * to)
void void
erase_border(border * b) erase_border(border * b)
{ {
attrib ** ap = &b->attribs;
while (*ap) a_remove(&b->attribs, *ap);
if (b->from && b->to) { if (b->from && b->to) {
border ** bp = get_borders_i(b->from, b->to); border ** bp = get_borders_i(b->from, b->to);
assert(*bp!=NULL || !"error: border is not registered"); assert(*bp!=NULL || !"error: border is not registered");
@ -136,7 +148,9 @@ erase_border(border * b)
*bp = b->next; *bp = b->next;
} }
} }
if (b->type->destroy) b->type->destroy(b); if (b->type->destroy) {
b->type->destroy(b);
}
free(b); free(b);
} }
@ -210,23 +224,16 @@ boolean b_rinvisible(const border * b, const region * r) { unused(r); unused(b);
boolean b_finvisible(const border * b, const struct faction * f, const region * r) { unused(r); unused(f); unused(b); return false; } boolean b_finvisible(const border * b, const struct faction * f, const region * r) { unused(r); unused(f); unused(b); return false; }
boolean b_uinvisible(const border * b, const unit * u) { unused(u); unused(b); return false; } boolean b_uinvisible(const border * b, const unit * u) { unused(u); unused(b); return false; }
/*********************/ /**************************************/
/* at_countdown */ /* at_countdown - legacy, do not use */
/*********************/ /**************************************/
static int
a_agecountdown(attrib * a)
{
a->data.i = max(a->data.i-1, 0);
return a->data.i;
}
attrib_type at_countdown = { attrib_type at_countdown = {
"countdown", "countdown",
DEFAULT_INIT, DEFAULT_INIT,
DEFAULT_FINALIZE, DEFAULT_FINALIZE,
a_agecountdown, NULL,
a_writeint, NULL,
a_readint a_readint
}; };
@ -236,25 +243,13 @@ age_borders(void)
border_list * deleted = NULL; border_list * deleted = NULL;
int i; int i;
for (i=0;i!=BMAXHASH;++i) { for (i=0;i!=BORDER_MAXHASH;++i) {
border * bhash = borders[i]; border * bhash = borders[i];
for (;bhash;bhash=bhash->nexthash) { for (;bhash;bhash=bhash->nexthash) {
border * b = bhash; border * b = bhash;
for (;b;b=b->next) { for (;b;b=b->next) {
attrib ** ap = &b->attribs; if (b->type->age) {
while (*ap) { b->type->age(b);
attrib * a = *ap;
if (a->type->age && a->type->age(a)==0) {
if (a->type == &at_countdown) {
border_list * bnew = malloc(sizeof(border_list));
bnew->next = deleted;
bnew->data = b;
deleted = bnew;
break;
}
a_remove(&b->attribs, a);
}
else ap=&a->next;
} }
} }
} }
@ -517,7 +512,7 @@ void
write_borders(struct storage * store) write_borders(struct storage * store)
{ {
int i; int i;
for (i=0;i!=BMAXHASH;++i) { for (i=0;i!=BORDER_MAXHASH;++i) {
border * bhash; border * bhash;
for (bhash=borders[i];bhash;bhash=bhash->nexthash) { for (bhash=borders[i];bhash;bhash=bhash->nexthash) {
border * b; border * b;
@ -531,7 +526,6 @@ write_borders(struct storage * store)
store->w_int(store, b->to->y); store->w_int(store, b->to->y);
if (b->type->write) b->type->write(b, store); if (b->type->write) b->type->write(b, store);
a_write(store, b->attribs);
store->w_brk(store); store->w_brk(store);
} }
} }
@ -549,7 +543,6 @@ read_borders(struct storage * store)
border * b; border * b;
region * from, * to; region * from, * to;
border_type * type; border_type * type;
int result;
store->r_tok_buf(store, zText, sizeof(zText)); store->r_tok_buf(store, zText, sizeof(zText));
if (!strcmp(zText, "end")) break; if (!strcmp(zText, "end")) break;
@ -587,8 +580,18 @@ read_borders(struct storage * store)
b->id = bid; b->id = bid;
assert(bid<=nextborder); assert(bid<=nextborder);
if (type->read) type->read(b, store); if (type->read) type->read(b, store);
result = a_read(store, &b->attribs); if (store->version<NOBORDERATTRIBS_VERSION) {
attrib * a = NULL;
int result = a_read(store, &a);
while (a) {
if (type==&bt_firewall && a->type==&at_countdown) {
wall_data * fd = (wall_data *)b->data.v;
fd->countdown = a->data.i;
}
a_remove(&a, a);
}
if (result<0) return result; if (result<0) return result;
}
if (!to || !from) { if (!to || !from) {
erase_border(b); erase_border(b);
} }

View File

@ -21,8 +21,6 @@
extern "C" { extern "C" {
#endif #endif
#define BMAXHASH 8191
extern unsigned int nextborder; extern unsigned int nextborder;
typedef struct border { typedef struct border {
@ -30,7 +28,6 @@ extern "C" {
struct border * next; /* next border between these regions */ struct border * next; /* next border between these regions */
struct border * nexthash; /* next border between these regions */ struct border * nexthash; /* next border between these regions */
struct region * from, * to; /* borders can be directed edges */ struct region * from, * to; /* borders can be directed edges */
struct attrib * attribs;
variant data; variant data;
unsigned int id; /* unique id */ unsigned int id; /* unique id */
} border; } border;
@ -84,12 +81,15 @@ extern "C" {
*/ */
struct region * (*move)(const border *, struct unit * u, struct region * from, struct region * to, boolean routing); struct region * (*move)(const border *, struct unit * u, struct region * from, struct region * to, boolean routing);
/* executed when the units traverses this border */ /* executed when the units traverses this border */
int (*age)(struct border *);
/* return 0 if border needs to be removed. >0 if still aging, <0 if not aging */
struct border_type * next; /* for internal use only */ struct border_type * next; /* for internal use only */
} border_type; } border_type;
extern border * find_border(unsigned int id); extern border * find_border(unsigned int id);
void resolve_borderid(variant data, void * addr); void resolve_borderid(variant data, void * addr);
extern void free_borders(void);
extern border * get_borders(const struct region * r1, const struct region * r2); extern border * get_borders(const struct region * r1, const struct region * r2);
/* returns the list of borders between r1 and r2 or r2 and r1 */ /* returns the list of borders between r1 and r2 or r2 and r1 */

View File

@ -679,6 +679,11 @@ stripfaction (faction * f)
free(bm); free(bm);
} }
while (f->groups) {
group * g = f->groups;
f->groups = g->next;
free_group(g);
}
freelist(f->allies); freelist(f->allies);
free(f->email); free(f->email);
@ -687,7 +692,9 @@ stripfaction (faction * f)
free(f->override); free(f->override);
free(f->name); free(f->name);
while (f->attribs) a_remove (&f->attribs, f->attribs); while (f->attribs) {
a_remove (&f->attribs, f->attribs);
}
i_freeall(&f->items); i_freeall(&f->items);
@ -3005,6 +3012,7 @@ free_gamedata(void)
{ {
free_units(); free_units();
free_regions(); free_regions();
free_borders();
while (factions) { while (factions) {
faction * f = factions; faction * f = factions;
@ -3019,4 +3027,8 @@ free_gamedata(void)
free(pl->name); free(pl->name);
free(pl); free(pl);
} }
while (global.attribs) {
a_remove(&global.attribs, global.attribs);
}
} }

View File

@ -124,6 +124,12 @@ at_group = { /* attribute for units assigned to a group */
void void
free_group(group * g) free_group(group * g)
{ {
int index = g->gid % GMAXHASH;
group ** g_ptr = ghash+index;
while (*g_ptr && (*g_ptr)->gid!=g->gid) g_ptr = &(*g_ptr)->nexthash;
assert(*g_ptr==g);
*g_ptr = g->nexthash;
while (g->allies) { while (g->allies) {
ally * a = g->allies; ally * a = g->allies;
g->allies = a->next; g->allies = a->next;

View File

@ -959,6 +959,8 @@ free_regions(void)
runhash(r); runhash(r);
free_region(r); free_region(r);
} }
max_index = 0;
last = NULL;
} }
/** creates a name for a region /** creates a name for a region

View File

@ -1410,6 +1410,7 @@ readgame(const char * filename, int mode, int backup)
} }
a_read(store, &global.attribs); a_read(store, &global.attribs);
global.data_turn = turn = store->r_int(store); global.data_turn = turn = store->r_int(store);
rng_init(turn);
store->r_int(store); /* max_unique_id = */ store->r_int(store); /* max_unique_id = */
nextborder = store->r_int(store); nextborder = store->r_int(store);

View File

@ -56,6 +56,7 @@
#define STORAGE_VERSION 328 /* with storage.h, some things are stored smarter (ids as base36, fractions as float) */ #define STORAGE_VERSION 328 /* with storage.h, some things are stored smarter (ids as base36, fractions as float) */
#define INTPAK_VERSION 329 /* in binary, ints can get packed */ #define INTPAK_VERSION 329 /* in binary, ints can get packed */
#define NOZEROIDS_VERSION 330 /* zero is not a valid ID for anything (including factions) */ #define NOZEROIDS_VERSION 330 /* zero is not a valid ID for anything (including factions) */
#define NOBORDERATTRIBS_VERSION 331 /* border::attribs has been moved to userdata */
#define MIN_VERSION CURSETYPE_VERSION /* minimal datafile we support */ #define MIN_VERSION CURSETYPE_VERSION /* minimal datafile we support */
#define RELEASE_VERSION NOZEROIDS_VERSION /* current datafile */ #define RELEASE_VERSION NOBORDERATTRIBS_VERSION /* current datafile */

View File

@ -2766,7 +2766,9 @@ b_namefirewall(const border * b, const region * r, const faction * f, int gflags
static void static void
wall_init(border * b) wall_init(border * b)
{ {
b->data.v = calloc(sizeof(wall_data), 1); wall_data * fd = (wall_data*)calloc(sizeof(wall_data), 1);
fd->countdown = -1; /* infinite */
b->data.v = fd;
} }
static void static void
@ -2791,6 +2793,9 @@ wall_read(border * b, storage * store)
read_unit_reference(&fd->mage, store); read_unit_reference(&fd->mage, store);
} }
fd->force = store->r_int(store); fd->force = store->r_int(store);
if (store->version>=NOBORDERATTRIBS_VERSION) {
fd->countdown = store->r_int(store);
}
fd->active = true; fd->active = true;
} }
@ -2800,6 +2805,17 @@ wall_write(const border * b, storage * store)
wall_data * fd = (wall_data*)b->data.v; wall_data * fd = (wall_data*)b->data.v;
write_unit_reference(fd->mage, store); write_unit_reference(fd->mage, store);
store->w_int(store, fd->force); store->w_int(store, fd->force);
store->w_int(store, fd->countdown);
}
static int
wall_age(border * b)
{
wall_data * fd = (wall_data*)b->data.v;
if (fd->countdown>0) {
if (--fd->countdown==0) return 0;
}
return fd->countdown;
} }
static region * static region *
@ -2836,7 +2852,8 @@ border_type bt_firewall = {
b_finvisible, /* fvisible */ b_finvisible, /* fvisible */
b_uinvisible, /* uvisible */ b_uinvisible, /* uvisible */
NULL, NULL,
wall_move wall_move,
wall_age
}; };
static int static int
@ -2844,7 +2861,6 @@ sp_firewall(castorder *co)
{ {
border * b; border * b;
wall_data * fd; wall_data * fd;
attrib * a;
region *r = co->rt; region *r = co->rt;
unit *mage = co->magician.u; unit *mage = co->magician.u;
int cast_level = co->level; int cast_level = co->level;
@ -2877,17 +2893,11 @@ sp_firewall(castorder *co)
fd->force = (int)(force/2+0.5); fd->force = (int)(force/2+0.5);
fd->mage = mage; fd->mage = mage;
fd->active = false; fd->active = false;
fd->countdown = cast_level+1;
} else { } else {
fd = (wall_data*)b->data.v; fd = (wall_data*)b->data.v;
fd->force = (int)max(fd->force, force/2+0.5); fd->force = (int)max(fd->force, force/2+0.5);
} fd->countdown = max(fd->countdown, cast_level+1);
a = a_find(b->attribs, &at_countdown);
if (a==NULL) {
a = a_add(&b->attribs, a_new(&at_countdown));
a->data.i = cast_level+1;
} else {
a->data.i = max(a->data.i, cast_level+1);
} }
/* melden, 1x pro Partei */ /* melden, 1x pro Partei */
@ -2997,8 +3007,7 @@ sp_wisps(castorder *co)
fd->force = (int)(force/2+0.5); fd->force = (int)(force/2+0.5);
fd->mage = mage; fd->mage = mage;
fd->active = false; fd->active = false;
fd->countdown = cast_level+1;
a_add(&b->attribs, a_new(&at_countdown))->data.i = cast_level;
/* melden, 1x pro Partei */ /* melden, 1x pro Partei */
{ {

View File

@ -33,6 +33,7 @@ extern "C" {
struct unit * mage; struct unit * mage;
int force; int force;
boolean active; boolean active;
int countdown;
} wall_data; } wall_data;
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -265,42 +265,6 @@ fix_age(void)
} }
} }
static void
fix_firewalls(void)
{
region * r = regions;
int fixes = 0;
while (r) {
direction_t d;
for (d=0;d!=MAXDIRECTIONS;++d) {
region * r2 = rconnect(r, d);
if (r2) {
border * b = get_borders(r, r2);
while (b) {
if (b->type==&bt_firewall) {
attrib * a = a_find(b->attribs, &at_countdown);
if (a==NULL || a->data.i <= 0) {
erase_border(b);
log_warning(("firewall between regions %s and %s was bugged. removed.\n",
regionname(r, NULL), regionname(r2, NULL)));
b = get_borders(r, r2);
++fixes;
} else {
b = b->next;
}
} else {
b = b->next;
}
}
}
}
r = r->next;
}
log_printf("fixed %d firewalls.\n", fixes);
}
static void static void
fix_otherfaction(void) fix_otherfaction(void)
{ {
@ -613,19 +577,20 @@ fix_astralplane(void)
extern border *borders[]; extern border *borders[];
#define BORDER_MAXHASH 8191
static void static void
fix_road_borders(void) fix_road_borders(void)
{ {
#define MAXDEL 10000 #define MAXDEL 10000
border *deleted[MAXDEL]; border *deleted[MAXDEL];
int hash; int hash;
int i = 0; int fixes = 0;
for (hash=0; hash<BMAXHASH && i!=MAXDEL; hash++) { for (hash=0; hash<BORDER_MAXHASH && fixes!=MAXDEL; hash++) {
border * blist; border * blist;
for (blist=borders[hash];blist && i!=MAXDEL;blist=blist->nexthash) { for (blist=borders[hash];blist && fixes!=MAXDEL;blist=blist->nexthash) {
border * b; border * b;
for (b=blist;b && i!=MAXDEL;b=b->next) { for (b=blist;b && fixes!=MAXDEL;b=b->next) {
if (b->type == &bt_road) { if (b->type == &bt_road) {
short x1, x2, y1, y2; short x1, x2, y1, y2;
region *r1, *r2; region *r1, *r2;
@ -642,16 +607,17 @@ fix_road_borders(void)
|| r1->terrain->max_road<=0 || r1->terrain->max_road<=0
|| r2->terrain->max_road<=0) || r2->terrain->max_road<=0)
{ {
deleted[i++] = b; deleted[fixes++] = b;
} }
} }
} }
} }
} }
while (i>0) { log_printf("fixed %d roads.\n", fixes);
i--; while (fixes>0) {
erase_border(deleted[i]); fixes--;
erase_border(deleted[fixes]);
} }
} }
@ -931,7 +897,6 @@ korrektur(void)
do_once("atrx", &fix_attribflags); do_once("atrx", &fix_attribflags);
do_once("asfi", &fix_astral_firewalls); do_once("asfi", &fix_astral_firewalls);
fix_astralplane(); fix_astralplane();
fix_firewalls();
fix_toads(); fix_toads();
/* fix_heroes(); */ /* fix_heroes(); */
verify_owners(false); verify_owners(false);

View File

@ -144,11 +144,6 @@ extern "C" {
extern boolean battledebug; extern boolean battledebug;
extern int loadplane; extern int loadplane;
extern void debug_messagetypes(FILE * out);
extern void free_region(region * r);
extern void render_init(void);
extern void free_borders(void);
extern boolean opt_cr_absolute_coords; extern boolean opt_cr_absolute_coords;
} }

View File

@ -9,10 +9,59 @@ function test_locales()
return 0 return 0
end end
function loadscript(name)
local script = scriptpath .. "/" .. name
print("- loading " .. script)
if pcall(dofile, script)==0 then
print("Could not load " .. script)
end
end
function run_scripts()
scripts = {
"spells.lua",
"extensions.lua",
"familiars.lua",
}
for index, value in pairs(scripts) do
loadscript(value)
end
end
--test_locales() --test_locales()
function run_turn()
plan_monsters()
process_orders()
spawn_dragons()
spawn_undead()
spawn_braineaters(0.25)
autoseed(basepath .. "/newfactions", false)
end
function test_free()
read_game("571.dat", "binary")
read_orders("orders.571")
run_turn()
free_game()
read_game("570.dat", "binary")
read_orders("orders.570")
run_turn()
free_game()
end
loadscript("default.lua")
run_scripts()
-- go
local now = os.clock() local now = os.clock()
read_game("572.dat", "binary") -- test_free()
read_game("571.dat", "binary")
write_game("571.txt.1", "text")
free_game()
read_game("570.dat", "binary")
free_game()
read_game("571.dat", "binary")
write_game("571.txt.2", "text")
local elapsed = os.clock() - now local elapsed = os.clock() - now
print(elapsed) print(elapsed)
-- text: 50.574 -- text: 50.574