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

View File

@ -21,8 +21,6 @@
extern "C" {
#endif
#define BMAXHASH 8191
extern unsigned int nextborder;
typedef struct border {
@ -30,7 +28,6 @@ extern "C" {
struct border * next; /* next border between these regions */
struct border * nexthash; /* next border between these regions */
struct region * from, * to; /* borders can be directed edges */
struct attrib * attribs;
variant data;
unsigned int id; /* unique id */
} border;
@ -84,12 +81,15 @@ extern "C" {
*/
struct region * (*move)(const border *, struct unit * u, struct region * from, struct region * to, boolean routing);
/* 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 */
} border_type;
extern border * find_border(unsigned int id);
void resolve_borderid(variant data, void * addr);
extern void free_borders(void);
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 */

View File

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

View File

@ -124,13 +124,19 @@ at_group = { /* attribute for units assigned to a group */
void
free_group(group * g)
{
while (g->allies) {
ally * a = g->allies;
g->allies = a->next;
free(a);
}
free(g->name);
free(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) {
ally * a = g->allies;
g->allies = a->next;
free(a);
}
free(g->name);
free(g);
}
void

View File

@ -959,6 +959,8 @@ free_regions(void)
runhash(r);
free_region(r);
}
max_index = 0;
last = NULL;
}
/** 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);
global.data_turn = turn = store->r_int(store);
rng_init(turn);
store->r_int(store); /* max_unique_id = */
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 INTPAK_VERSION 329 /* in binary, ints can get packed */
#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 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
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
@ -2791,6 +2793,9 @@ wall_read(border * b, storage * store)
read_unit_reference(&fd->mage, store);
}
fd->force = store->r_int(store);
if (store->version>=NOBORDERATTRIBS_VERSION) {
fd->countdown = store->r_int(store);
}
fd->active = true;
}
@ -2800,6 +2805,17 @@ wall_write(const border * b, storage * store)
wall_data * fd = (wall_data*)b->data.v;
write_unit_reference(fd->mage, store);
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 *
@ -2836,7 +2852,8 @@ border_type bt_firewall = {
b_finvisible, /* fvisible */
b_uinvisible, /* uvisible */
NULL,
wall_move
wall_move,
wall_age
};
static int
@ -2844,7 +2861,6 @@ sp_firewall(castorder *co)
{
border * b;
wall_data * fd;
attrib * a;
region *r = co->rt;
unit *mage = co->magician.u;
int cast_level = co->level;
@ -2877,17 +2893,11 @@ sp_firewall(castorder *co)
fd->force = (int)(force/2+0.5);
fd->mage = mage;
fd->active = false;
fd->countdown = cast_level+1;
} else {
fd = (wall_data*)b->data.v;
fd->force = (int)max(fd->force, force/2+0.5);
}
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);
fd->countdown = max(fd->countdown, cast_level+1);
}
/* melden, 1x pro Partei */
@ -2997,8 +3007,7 @@ sp_wisps(castorder *co)
fd->force = (int)(force/2+0.5);
fd->mage = mage;
fd->active = false;
a_add(&b->attribs, a_new(&at_countdown))->data.i = cast_level;
fd->countdown = cast_level+1;
/* melden, 1x pro Partei */
{

View File

@ -33,6 +33,7 @@ extern "C" {
struct unit * mage;
int force;
boolean active;
int countdown;
} wall_data;
#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
fix_otherfaction(void)
{
@ -613,19 +577,20 @@ fix_astralplane(void)
extern border *borders[];
#define BORDER_MAXHASH 8191
static void
fix_road_borders(void)
{
#define MAXDEL 10000
border *deleted[MAXDEL];
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;
for (blist=borders[hash];blist && i!=MAXDEL;blist=blist->nexthash) {
for (blist=borders[hash];blist && fixes!=MAXDEL;blist=blist->nexthash) {
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) {
short x1, x2, y1, y2;
region *r1, *r2;
@ -642,16 +607,17 @@ fix_road_borders(void)
|| r1->terrain->max_road<=0
|| r2->terrain->max_road<=0)
{
deleted[i++] = b;
deleted[fixes++] = b;
}
}
}
}
}
while (i>0) {
i--;
erase_border(deleted[i]);
log_printf("fixed %d roads.\n", fixes);
while (fixes>0) {
fixes--;
erase_border(deleted[fixes]);
}
}
@ -931,7 +897,6 @@ korrektur(void)
do_once("atrx", &fix_attribflags);
do_once("asfi", &fix_astral_firewalls);
fix_astralplane();
fix_firewalls();
fix_toads();
/* fix_heroes(); */
verify_owners(false);

View File

@ -144,11 +144,6 @@ extern "C" {
extern boolean battledebug;
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;
}

View File

@ -9,10 +9,59 @@ function test_locales()
return 0
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()
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()
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
print(elapsed)
-- text: 50.574