"buildings and ships are leaking memory"
- remove_building and remove_ship work like their region/unit counterparts
This commit is contained in:
Enno Rehling 2008-05-23 09:25:41 +00:00
parent 43d73a6b45
commit f0c56346d9
18 changed files with 206 additions and 180 deletions

View File

@ -978,41 +978,41 @@ maintain(building * b, boolean first)
static void
gebaeude_stuerzt_ein(region * r, building * b)
{
unit *u;
int n, i;
int opfer = 0;
int road = 0;
struct message * msg;
unit *u;
int n, i;
int opfer = 0;
int road = 0;
struct message * msg;
for (u = r->units; u; u = u->next) {
if (u->building == b) {
int loss = 0;
for (u = r->units; u; u = u->next) {
if (u->building == b) {
int loss = 0;
fset(u->faction, FFL_MARK);
freset(u, UFL_OWNER);
leave(r,u);
n = u->number;
for (i = 0; i < n; i++) {
if (rng_double() >= COLLAPSE_SURVIVAL) {
++loss;
}
}
scale_number(u, u->number - loss);
opfer += loss;
}
}
fset(u->faction, FFL_MARK);
freset(u, UFL_OWNER);
leave(r,u);
n = u->number;
for (i = 0; i < n; i++) {
if (rng_double() >= COLLAPSE_SURVIVAL) {
++loss;
}
}
scale_number(u, u->number - loss);
opfer += loss;
}
}
msg = msg_message("buildingcrash", "region building opfer road", r, b, opfer, road);
add_message(&r->msgs, msg);
for (u=r->units; u; u=u->next) {
faction * f = u->faction;
if (fval(f, FFL_MARK)) {
freset(u->faction, FFL_MARK);
add_message(&f->msgs, msg);
}
}
msg_release(msg);
destroy_building(b);
msg = msg_message("buildingcrash", "region building opfer road", r, b, opfer, road);
add_message(&r->msgs, msg);
for (u=r->units; u; u=u->next) {
faction * f = u->faction;
if (fval(f, FFL_MARK)) {
freset(u->faction, FFL_MARK);
add_message(&f->msgs, msg);
}
}
msg_release(msg);
remove_building(&r->buildings, b);
}
void

View File

@ -2485,7 +2485,7 @@ sinkships(region * r)
damage_ship(sh, 0.05);
}
if (sh->damage >= sh->size * DAMAGE_SCALE) {
destroy_ship(sh);
remove_ship(shp, sh);
}
if (*shp==sh) shp=&sh->next;
}

View File

@ -427,7 +427,6 @@ void
chaos(region * r)
{
unit *u = NULL, *u2;
building *b, *b2;
if (rng_int() % 100 < 8) {
switch (rng_int() % 3) {
@ -474,7 +473,9 @@ chaos(region * r)
while (sh) {
ship * nsh = sh->next;
damage_ship(sh, 0.50);
if (sh->damage >= sh->size * DAMAGE_SCALE) destroy_ship(sh);
if (sh->damage >= sh->size * DAMAGE_SCALE) {
remove_ship(&sh->region->ships, sh);
}
sh = nsh;
}
@ -487,10 +488,8 @@ chaos(region * r)
}
ADDMSG(&r->msgs, msg_message("tidalwave", "region", r));
for (b = rbuildings(r); b;) {
b2 = b->next;
destroy_building(b);
b = b2;
while (r->buildings) {
remove_building(&r->buildings, r->buildings);
}
terraform(r, T_OCEAN);
}
@ -760,7 +759,6 @@ melt_iceberg(region *r)
{
attrib *a;
unit *u;
building *b, *b2;
for (u=r->units; u; u=u->next) freset(u->faction, FFL_SELECT);
for (u=r->units; u; u=u->next) if (!fval(u->faction, FFL_SELECT)) {
@ -773,10 +771,9 @@ melt_iceberg(region *r)
if (a) a_remove(&r->attribs, a);
/* Gebäude löschen */
for (b = rbuildings(r); b; b = b2) {
b2 = b->next;
destroy_building(b);
}
while (r->buildings) {
remove_building(&r->buildings, r->buildings);
}
/* in Ozean wandeln */
terraform(r, T_OCEAN);
@ -875,7 +872,7 @@ move_iceberg(region *r)
ADDMSG(&u->faction->msgs, msg_message("overrun_by_iceberg_des",
"ship", sh));
}
destroy_ship(sh);
remove_ship(&sh->region->ships, sh);
} else if (u!=NULL) {
ADDMSG(&u->faction->msgs, msg_message("overrun_by_iceberg",
"ship", sh));
@ -985,7 +982,7 @@ godcurse(void)
unit * u = shipowner(sh);
if (u) ADDMSG(&u->faction->msgs,
msg_message("godcurse_destroy_ship", "ship", sh));
destroy_ship(sh);
remove_ship(&sh->region->ships, sh);
}
sh = shn;
}
@ -1122,11 +1119,10 @@ void
randomevents(void)
{
#if KARMA_MODULE
faction *f;
faction *f;
#endif /* KARMA_MODULE */
region *r;
building *b, *b2;
unit *u;
region *r;
unit *u;
icebergs();
godcurse();
@ -1191,14 +1187,16 @@ randomevents(void)
/* Monumente zerfallen, Schiffe verfaulen */
for (r = regions; r; r = r->next) {
for (b = rbuildings(r); b; b = b2) {
b2 = b->next;
building ** blist = &r->buildings;
while (*blist) {
building * b = *blist;
if (fval(b->type, BTF_DECAY) && !buildingowner(r, b)) {
b->size -= max(1, (b->size * 20) / 100);
if (b->size == 0) {
destroy_building(b);
remove_building(blist, r->buildings);
}
}
if (*blist==b) blist=&b->next;
}
}
@ -1213,7 +1211,7 @@ randomevents(void)
"unit region", u, r));
u_setfaction(u, get_monsters());
}
}
}
}
}
@ -1226,7 +1224,7 @@ randomevents(void)
for(u = f->units; u; u=u->nextF) {
if (rng_int()%100 < 2*level) {
ADDMSG(&u->faction->msgs,
msg_message("becomewere", "unit region", u, u->region));
msg_message("becomewere", "unit region", u, u->region));
fset(u, UFL_WERE);
}
}
@ -1245,16 +1243,16 @@ randomevents(void)
if (!i) continue;
chaoscounts(r, -(int) (i * ((double) (rng_int() % 10)) / 100.0));
}
#ifdef HERBS_ROT
/* Kräuter verrotten */
for (r = regions; r; r = r->next) {
for (u = r->units; u; u=u->next) {
item **itmp = &u->items, *hbag = *i_find(&u->items, olditemtype[I_SACK_OF_CONSERVATION]);
int rot_chance = HERBROTCHANCE;
if (hbag) rot_chance = (HERBROTCHANCE*2)/5;
while (*itmp) {
item * itm = *itmp;
int n = itm->number;
@ -1270,7 +1268,7 @@ randomevents(void)
}
}
#endif
dissolve_units();
check_split();
#if KARMA_MODULE

View File

@ -566,7 +566,7 @@ sink_ship(region * r, ship * sh, const char *name, char spy, unit * saboteur)
if (enemy_discovers_spy_msg) msg_release(enemy_discovers_spy_msg);
if (sink_msg) msg_release(sink_msg);
/* finally, get rid of the ship */
destroy_ship(sh);
remove_ship(&sh->region->ships, sh);
vset_destroy(&informed);
vset_destroy(&survivors);
}

View File

@ -2572,7 +2572,7 @@ aftermath(battle * b)
ship * sh = *sp;
freset(sh, SF_DAMAGED);
if (sh->damage >= sh->size * DAMAGE_SCALE) {
destroy_ship(sh);
remove_ship(sp, sh);
}
if (*sp==sh) sp=&sh->next;
}

View File

@ -384,7 +384,7 @@ destroy_cmd(unit * u, struct order * ord)
ADDMSG(&u->faction->msgs, msg_message("destroy",
"building unit", b, u));
con = b->type->construction;
destroy_building(b);
remove_building(&r->buildings, b);
} else {
/* partial destroy */
b->size -= n;
@ -411,7 +411,7 @@ destroy_cmd(unit * u, struct order * ord)
ADDMSG(&u->faction->msgs, msg_message("shipdestroy",
"unit region ship", u, r, sh));
con = sh->type->construction;
destroy_ship(sh);
remove_ship(&sh->region->ships, sh);
} else {
/* partial destroy */
sh->size -= (sh->type->construction->maxsize * n)/100;

View File

@ -394,7 +394,7 @@ read_building_reference(struct building ** b, struct storage * store)
*b = findbuilding(var.i);
if (*b==NULL) ur_add(var, (void**)b, resolve_building);
return AT_READ_OK;
}
}
}
void
@ -452,8 +452,13 @@ new_building(const struct building_type * btype, region * r, const struct locale
return b;
}
static building * deleted_buildings;
/** remove a building from the region.
* remove_building lets units leave the building
*/
void
destroy_building(building * b)
remove_building(building ** blist, building * b)
{
unit *u;
direction_t d;
@ -467,7 +472,9 @@ destroy_building(building * b)
bt_tunnel = bt_find("tunnel");
}
if (!bfindhash(b->no)) return;
assert(bfindhash(b->no));
handle_event(b->attribs, "destroy", b);
for (u=b->region->units; u; u=u->next) {
if (u->building == b) leave(b->region, u);
}
@ -486,8 +493,29 @@ destroy_building(building * b)
}
/* Stattdessen nur aus Liste entfernen, aber im Speicher halten. */
choplist(&b->region->buildings, b);
handle_event(b->attribs, "destroy", b);
while (*blist && *blist!=b) blist = &(*blist)->next;
*blist = b->next;
b->region = NULL;
b->next = deleted_buildings;
deleted_buildings = b;
}
void
free_building(building * b)
{
while (b->attribs) a_remove (&b->attribs, b->attribs);
free(b->name);
free(b->display);
free(b);
}
void
free_buildings(void)
{
while (deleted_buildings) {
building * b = deleted_buildings;
deleted_buildings = b->next;
}
}
extern struct attrib_type at_icastle;

View File

@ -123,7 +123,10 @@ int buildingeffsize(const building * b, boolean img);
void bhash(struct building * b);
void bunhash(struct building * b);
int buildingcapacity(const struct building * b);
void destroy_building(struct building * b);
extern void remove_building(struct building * *blist, struct building * b);
extern void free_building(struct building * b);
extern void free_buildings(void);
const struct building_type * findbuildingtype(const char * name, const struct locale * lang);

View File

@ -144,17 +144,17 @@ a_writeicastle(const attrib * a, struct storage * store)
static int
a_ageicastle(struct attrib * a)
{
icastle_data * data = (icastle_data*)a->data.v;
if (data->time<=0) {
building * b = data->building;
region * r = b->region;
icastle_data * data = (icastle_data*)a->data.v;
if (data->time<=0) {
building * b = data->building;
region * r = b->region;
ADDMSG(&r->msgs, msg_message("icastle_dissolve", "building", b));
/* destroy_building lets units leave the building */
destroy_building(b);
return 0;
}
else data->time--;
return 1;
/* remove_building lets units leave the building */
remove_building(&r->buildings, b);
return 0;
}
else data->time--;
return 1;
}
static void

View File

@ -481,23 +481,24 @@ static ship *
do_maelstrom(region *r, unit *u)
{
int damage;
ship * sh = u->ship;
damage = rng_int()%150 - eff_skill(u, SK_SAILING, r)*5;
if (damage <= 0) {
return u->ship;
return sh;
}
damage_ship(u->ship, 0.01*damage);
if (u->ship->damage >= u->ship->size * DAMAGE_SCALE) {
if (sh->damage >= sh->size * DAMAGE_SCALE) {
ADDMSG(&u->faction->msgs, msg_message("entermaelstrom",
"region ship damage sink", r, u->ship, damage, 1));
destroy_ship(u->ship);
"region ship damage sink", r, sh, damage, 1));
remove_ship(&sh->region->ships, sh);
return NULL;
}
ADDMSG(&u->faction->msgs, msg_message("entermaelstrom",
"region ship damage sink", r, u->ship, damage, 0));
"region ship damage sink", r, sh, damage, 0));
return u->ship;
}
@ -776,7 +777,7 @@ drifting_ships(region * r)
damage_ship(sh, 0.02);
if (sh->damage>=sh->size * DAMAGE_SCALE) {
destroy_ship(sh);
remove_ship(shp, sh);
}
}
@ -1782,7 +1783,7 @@ sail(unit * u, order * ord, boolean move_on_land, region_list **routep)
if (sh->damage>=sh->size * DAMAGE_SCALE) {
ADDMSG(&f->msgs, msg_message("shipsink", "ship", sh));
destroy_ship(sh);
remove_ship(&sh->region->ships, sh);
sh = NULL;
}
@ -2322,7 +2323,7 @@ destroy_damaged_ships(void)
for(sh=r->ships;sh;) {
shn = sh->next;
if (sh->damage>=sh->size * DAMAGE_SCALE) {
destroy_ship(sh);
remove_ship(&sh->region->ships, sh);
}
sh = shn;
}

View File

@ -951,19 +951,15 @@ free_region(region * r)
while (r->buildings) {
building * b = r->buildings;
r->buildings = b->next;
bunhash(b);
free(b->name);
free(b->display);
free(b);
bunhash(b); /* must be done here, because remove_building does it, and wasn't called */
free_building(b);
}
while (r->ships) {
ship * s = r->ships;
r->ships = s->next;
sunhash(s);
free(s->name);
free(s->display);
free(s);
free_ship(s);
}
free(r);

View File

@ -24,6 +24,7 @@
#include "skill.h"
/* util includes */
#include <util/attrib.h>
#include <util/base36.h>
#include <util/event.h>
#include <util/language.h>
@ -162,32 +163,33 @@ captain(ship *sh, region *r)
}
/* Alte Schiffstypen: */
static ship * deleted_ships;
ship *
new_ship(const ship_type * stype, const struct locale * lang, region * r)
{
static char buffer[7 + IDSIZE + 1];
ship *sh = (ship *) calloc(1, sizeof(ship));
static char buffer[7 + IDSIZE + 1];
ship *sh = (ship *) calloc(1, sizeof(ship));
sh->no = newcontainerid();
sh->coast = NODIRECTION;
sh->type = stype;
sh->region = r;
sh->no = newcontainerid();
sh->coast = NODIRECTION;
sh->type = stype;
sh->region = r;
sprintf(buffer, "%s %s", LOC(lang, stype->name[0]), shipid(sh));
sh->name = strdup(buffer);
shash(sh);
sprintf(buffer, "%s %s", LOC(lang, stype->name[0]), shipid(sh));
sh->name = strdup(buffer);
shash(sh);
addlist(&r->ships, sh);
return sh;
return sh;
}
void
destroy_ship(ship * sh)
remove_ship(ship ** slist, ship * sh)
{
region * r = sh->region;
unit * u = r->units;
handle_event(sh->attribs, "destroy", sh);
while (u) {
if (u->ship == sh) {
leave_ship(u);
@ -195,8 +197,28 @@ destroy_ship(ship * sh)
u = u->next;
}
sunhash(sh);
choplist(&r->ships, sh);
handle_event(sh->attribs, "destroy", sh);
while (*slist && *slist!=sh) slist = &(*slist)->next;
*slist = sh->next;
sh->next = deleted_ships;
deleted_ships = sh;
}
void
free_ship(ship * s)
{
while (s->attribs) a_remove(&s->attribs, s->attribs);
free(s->name);
free(s->display);
free(s);
}
void
free_ships(void)
{
while (deleted_ships) {
ship * s = deleted_ships;
deleted_ships = s->next;
}
}
const char *

View File

@ -97,7 +97,10 @@ extern const struct ship_type * findshiptype(const char *s, const struct locale
extern void register_ships(void);
extern void write_ship_reference(const struct ship * sh, struct storage * store);
extern void destroy_ship(struct ship * s);
extern void remove_ship(struct ship ** slist, struct ship * s);
extern void free_ship(struct ship * s);
extern void free_ships(void);
#ifdef __cplusplus
}

View File

@ -23,10 +23,12 @@
#include <kernel/plane.h>
#include <kernel/region.h>
#include <kernel/unit.h>
#include <kernel/version.h>
/* util includes */
#include <util/attrib.h>
#include <util/rng.h>
#include <util/resolve.h>
#include <util/storage.h>
/* libc includes */
@ -51,7 +53,7 @@ cmp_age(const void * v1, const void *v2)
typedef struct wormhole_data {
building * entry;
building * exit;
region * exit;
} wormhole_data;
static void
@ -80,10 +82,10 @@ wormhole_age(struct attrib * a)
if (u->number>maxtransport || has_limited_skills(u)) {
m = msg_message("wormhole_requirements", "unit region", u, u->region);
} else if (data->exit!=NULL) {
move_unit(u, data->exit->region, NULL);
move_unit(u, data->exit, NULL);
maxtransport -= u->number;
m = msg_message("wormhole_exit", "unit region", u, data->exit->region);
add_message(&data->exit->region->msgs, m);
m = msg_message("wormhole_exit", "unit region", u, data->exit);
add_message(&data->exit->msgs, m);
}
if (m!=NULL) {
add_message(&u->faction->msgs, m);
@ -92,11 +94,8 @@ wormhole_age(struct attrib * a)
}
}
/* it's important that destroy_building doesn't change b->region, because
* otherwise the tunnel would no longer be bi-directional after this */
destroy_building(data->entry);
remove_building(&r->buildings, data->entry);
ADDMSG(&r->msgs, msg_message("wormhole_dissolve", "region", r));
assert(data->entry->region==r);
/* age returns 0 if the attribute needs to be removed, !=0 otherwise */
return -1;
@ -140,8 +139,10 @@ make_wormhole(const building_type * bt_wormhole, region * r1, region * r2)
attrib * a2 = a_add(&b2->attribs, a_new(&at_wormhole));
wormhole_data * d1 = (wormhole_data*)a1->data.v;
wormhole_data * d2 = (wormhole_data*)a2->data.v;
d1->entry = d2->exit = b1;
d2->entry = d1->exit = b2;
d1->entry = b1;
d2->entry = b2;
d1->exit = b2->region;
d2->exit = b1->region;
b1->size = bt_wormhole->maxsize;
b2->size = bt_wormhole->maxsize;
ADDMSG(&r1->msgs, msg_message("wormhole_appear", "region", r1));

View File

@ -1604,7 +1604,6 @@ destroy_all_roads(region *r)
static int
sp_great_drought(castorder *co)
{
building *b, *b2;
unit *u;
boolean terraform = false;
region *r = co->rt;
@ -1664,10 +1663,8 @@ sp_great_drought(castorder *co)
set_number(u, 0);
}
}
for (b = r->buildings; b;) {
b2 = b->next;
destroy_building(b);
b = b2;
while (r->buildings) {
remove_building(&r->buildings, r->buildings);
}
}
break;
@ -2271,39 +2268,28 @@ static int
sp_earthquake(castorder *co)
{
int kaputt;
building *burg;
unit *u;
region *r = co->rt;
unit *mage = co->magician.u;
int cast_level = co->level;
message * msg;
building **blist = &r->buildings;
for (burg = r->buildings; burg; burg = burg->next) {
if (burg->size == 0 )
continue;
while (*blist) {
building * burg = *blist;
/* Schutzzauber */
if (is_cursed(burg->attribs, C_MAGICWALLS, 0))
continue;
/* Magieresistenz */
if (target_resists_magic(mage, burg, TYP_BUILDING, 0))
continue;
kaputt = min(10 * cast_level, burg->size / 4);
kaputt = max(kaputt, 1);
burg->size -= kaputt;
if (burg->size == 0 ) {
/* alle Einheiten hinausbefördern */
for(u = r->units; u; u = u->next ) {
if (u->building == burg ) {
u->building = 0;
freset(u, UFL_OWNER);
if (burg->size != 0 && !is_cursed(burg->attribs, C_MAGICWALLS, 0)) {
/* Magieresistenz */
if (!target_resists_magic(mage, burg, TYP_BUILDING, 0)) {
kaputt = min(10 * cast_level, burg->size / 4);
kaputt = max(kaputt, 1);
burg->size -= kaputt;
if (burg->size == 0) {
/* TODO: sollten die Insassen nicht Schaden nehmen? */
remove_building(blist, burg);
}
}
/* TODO: sollten die Insassen nicht Schaden nehmen? */
destroy_building(burg);
}
if (*blist==burg) blist=&burg->next;
}
/* melden, 1x pro Partei */
@ -3198,11 +3184,16 @@ dc_read_compat(struct attrib * a, storage * store)
variant var;
int duration = store->r_int(store);
double strength = store->r_flt(store);
short rx, ry;
var.i = store->r_id(store);
u = findunit(var.i);
read_region_reference(&r, store);
/* this only affects really old data. no need to change: */
rx = store->r_int(store);
ry = store->r_int(store);
r = findregion(rx, ry);
if (r!=NULL) {
variant effect;
curse * c;

View File

@ -87,16 +87,6 @@ insertlist(void_list ** l, void_list * p)
}
void
promotelist(void *l, void *p)
{
/* remove entry p from list l; insert p again at the beginning of l */
choplist(l, p);
insertlist((void_list **)l, (void_list *)p);
}
void
removelist(void *l, void *p)
{
@ -124,21 +114,6 @@ freelist(void *p1)
}
}
void
invert_list(void * heap)
{
void_list * x = NULL;
void_list * m = *(void_list**)heap;
while (m)
{
void_list * d = m;
m = m->next;
d->next = x;
x = d;
}
*(void **)heap = x;
}
unsigned int
listlen(void *l)
{

View File

@ -39,7 +39,6 @@ typedef struct void_list {
void addlist(void *l1, void *p1);
void choplist(void * l, void * p);
void translist(void *l1, void *l2, void *p);
void promotelist(void *l, void *p);
#ifndef MALLOCDBG
void freelist(void *p1);
void removelist(void *l, void *p);
@ -49,7 +48,6 @@ void removelist(void *l, void *p);
#endif
unsigned int listlen(void *l);
void invert_list(void * heap);
#define addlist2(l, p) (*l = p, l = &p->next)
void *listelem(void *l, int n);

View File

@ -118,11 +118,21 @@ building_getregion(const building& b)
}
static void
building_setregion(building& b, region& r)
building_setregion(building& bld, region& r)
{
choplist(&b.region->buildings, &b);
addlist(&r.buildings, &b);
b.region = &r;
building * b = &bld;
building ** blist = &b->region->buildings;
while (*blist && *blist!=b) {
blist = &(*blist)->next;
}
*blist = b->next;
b->next = NULL;
blist = &r.buildings;
while (*blist && *blist!=b) blist = &(*blist)->next;
*blist = b;
b->region = &r;
}
static std::ostream&