#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include "defs.h" #include "flag.h" #include "io.h" #include "lf.h" #include "map.h" #include "move.h" #include "nexus.h" #include "objects.h" #include "save.h" #include "text.h" #include "vault.h" extern long curtime; extern lifeform_t *player; extern map_t *firstmap; extern race_t *firstrace; extern knowledge_t *knowledge; extern region_t *firstregion,*lastregion; extern regionoutline_t *firstregionoutline,*lastregionoutline; extern map_t *heaven; extern long curtime, gamedays, gamesecs; extern enum GAMEMODE gamemode; void inithiscores() { char filename[BUFLEN]; int ok = B_FALSE; // open database snprintf(filename, BUFLEN, "%s/hiscores.db", DATADIR); if (access(filename, F_OK ) == -1 ) { char *cmd, *errmsg = NULL; int rc; sqlite3 *db; // create a new hiscores db rc = sqlite3_open(filename, &db); if (rc) { msg("failed to open hiscore file %s!\n", filename); dblog("failed to open hiscore file %s!\n", filename); exit(1); } asprintf(&cmd, "create table hiscores(id int primary key, score longint, name varchar, job varchar, killedby varchar);"); rc = sqlite3_exec(db, cmd, NULL, NULL, &errmsg); if (rc == SQLITE_OK) { ok = B_TRUE; } else { msg("failed to create hiscore table in %s! %s\n", filename, errmsg); dblog("failed to create hiscore table in %s! %s\n", filename, errmsg); sqlite3_free(errmsg); } free(cmd); sqlite3_close(db); } else { ok = B_TRUE; } if (ok != B_TRUE) { exit(1); } } // returns TRUE if we successfully loaded a save file int loadall(void) { //int db = B_FALSE; int foundsavegame = B_FALSE; region_t *heavenregion; gamemode = GM_LOADING; if (loadsavegame()) { // update fixed region pointers heavenregion = findregionbytype(BH_HEAVEN); heaven = findregionmap(heavenregion->id, 1); foundsavegame = B_TRUE; } gamemode = GM_LOADED; return foundsavegame; } int loadflagpile(FILE *f, flagpile_t *fp) { flag_t tempflag; flag_t *fl; char line[BUFLEN]; char buf[BUFLEN]; int rv; int skid = -9999; int db = B_FALSE; fscanf(f, "flags:\n"); fgets(line, BUFLEN, f); rv = sscanf(line, "%d,%d,%d,%d,%d,%d,%d,%ld,%d\n", &tempflag.id, &tempflag.nvals, &tempflag.val[0], &tempflag.val[1], &tempflag.val[2],&tempflag.lifetime, &tempflag.known,&tempflag.obfrom,&skid); assert(rv == 9); assert(skid != -9999); while (tempflag.id != -1) { dblog("got flag id=%d\n",tempflag.id); // get flag text fgets(buf, BUFLEN, f); buf[strlen(buf)-1] = '\0'; // strip newline fl = addflag_real(fp, tempflag.id, tempflag.val[0], tempflag.val[1], tempflag.val[2], strcmp(buf, "^^^") ? buf : NULL, tempflag.lifetime, tempflag.known, tempflag.obfrom); fl->skillfrom = findskill((enum SKILL)skid); if (db) { dblog("--> added flag id=%d. v0=%d, v1=%d, v2=%d, text=%s, lifetime=%d, known=%d, obfrom=%ld\n",fl->id, fl->val[0], fl->val[1], fl->val[2], fl->text ? fl->text : "(null)", fl->lifetime, fl->known,fl->obfrom); } // load next one fgets(line, BUFLEN, f); rv = sscanf(line, "%d,%d,%d,%d,%d,%d,%d,%ld,%d\n", &tempflag.id, &tempflag.nvals, &tempflag.val[0], &tempflag.val[1], &tempflag.val[2],&tempflag.lifetime, &tempflag.known,&tempflag.obfrom,&skid); //dblog("fscanf returned %d\n",rv); } return B_FALSE; } int loadknowledge(FILE *f) { int db = B_FALSE; char buf[BUFLEN]; char line[BUFLEN]; int otid,known; char hiddenname[BUFLEN]; char *p,*dummy; if (db) dblog("--> Loading knowledge...\n"); fscanf(f, "startknowledge\n"); fgets(buf, BUFLEN, f); buf[strlen(buf)-1] = '\0'; // strip newline while (strcmp(buf, "endknowledge")) { //sscanf(buf, "%d^%s^%d",&otid, hiddenname, &known); strcpy(line, buf); p = strtok_r(line, "^", &dummy); otid = atoi(p); p = strtok_r(NULL, "^", &dummy); strcpy(hiddenname, p); p = strtok_r(NULL, "^", &dummy); known = atoi(p); addknowledge(otid, hiddenname, known); // get next line fgets(buf, BUFLEN, f); buf[strlen(buf)-1] = '\0'; // strip newline } return B_FALSE; } int loadvars(FILE *f) { int id; int db = B_FALSE; race_t *r; if (db) dblog("--> Loading knowledge...\n"); fscanf(f, "startvars\n"); fscanf(f, "curtime:%ld\n",&curtime); fscanf(f, "endvars\n"); fscanf(f, "startknownraces\n"); fscanf(f, "%d\n", &id); while (id != -1) { r = findrace(id); r->known = B_TRUE; fscanf(f, "%d\n", &id); } fscanf(f, "endknownraces\n"); return B_FALSE; } // load and allocate one lifeform from given file lifeform_t *loadlf(FILE *f, cell_t *where) { lifeform_t *l; int lfid, lfraceid; long obid; int rv; int i,b; char buf[BUFLEN]; int obcount; int mapid; map_t *m; int x,y,level,newlevel; int db = B_TRUE; int matid; if (db) dblog("--> Loading lifeform...\n"); //fscanf(f, "startlf\n"); fscanf(f, "lfid: %d\n",&lfid); fscanf(f, "race: %d\n",&lfraceid); fscanf(f, "map: %d\n",&mapid); fscanf(f, "pos: %d,%d\n",&x, &y); fscanf(f, "level: %d\n",&level); fscanf(f, "newlevel: %d\n",&newlevel); // find the map m = findmap(mapid); if (!m) { dblog("ERROR loading lf id %d: can't find map id %d\n",lfid,mapid); exit(1); } if (where == NULL) { where = getcellat(m, x, y); } if (!m) { dblog("ERROR loading lf id %d: can't find cell at %d,%d on map id %d\n",lfid,x,y,mapid); exit(1); } l = addlf(where, lfraceid,level); l->id = lfid; l->x = x; l->y = y; l->newlevel = newlevel; // load rest of this lf fscanf(f, "str: %d/%d\n",&l->att[A_STR],&l->baseatt[A_STR]); fscanf(f, "dex: %d/%d\n",&l->att[A_AGI],&l->baseatt[A_AGI]); fscanf(f, "int: %d/%d\n",&l->att[A_IQ],&l->baseatt[A_IQ]); fscanf(f, "xp: %ld\n",&l->xp); fscanf(f, "skillxp: %ld\n",&l->skillxp); fscanf(f, "totskillpoints: %ld\n",&l->totskillpoints); fscanf(f, "skp: %d\n",&l->skillpoints); fscanf(f, "contr: %d\n",&l->controller); fscanf(f, "hp: %d/%d\n",&l->hp, &l->maxhp); fscanf(f, "mp: %d/%d\n",&l->mp, &l->maxmp); fscanf(f, "stamina: %f\n",&l->stamina); fscanf(f, "alive: %d\n",&l->alive); fscanf(f, "lastdamtype: %d\n",(int *)&l->lastdamtype); fgets(buf, BUFLEN, f); // lastdam buf[strlen(buf)-1] = '\0'; // strip newline l->lastdam = strdup(buf + 9); // after 'lastdam: ' fscanf(f, "material: %d\n",&matid); l->material = findmaterial(matid); fscanf(f, "timespent: %d\n",&l->timespent); fscanf(f, "sorted: %d\n",&l->sorted); fscanf(f, "polyrevert: %d\n",&l->polyrevert); fscanf(f, "forgettimer: %f\n",&l->forgettimer); //fscanf(f, "eyeadj: %d\n",&l->eyeadjustment); fscanf(f, "facing: %d\n",&l->facing); fscanf(f, "turncounter: %d\n",&l->turncounter); fscanf(f, "rotated: %d\n",&l->rotated); if (db) dblog("--> Got hp=%d/%d. timespend=%d. sorted=%d. Now loading flags.",l->hp,l->maxhp,l->timespent,l->sorted); // clear existing flags from addlf foreach_bucket(b) { while (l->flags->first[b]) { killflag(l->flags->first[b]); } } // load lf flags loadflagpile(f, l->flags); if (db) dblog("--> now loading objects"); // load object list obcount = 0; obid = 9999; // for testing rv = fscanf(f, "ob:%ld\n",&obid); while (obid != -1) { if (db) dblog("--> Load ob id %d into list...",obid); l->pack->oblist[obcount] = obid; obcount++; fscanf(f, "ob:%ld\n",&obid); } // terminate with -1s! for (i = obcount ; i < MAXPILEOBS; i++) { l->pack->oblist[i] = -1; } if (db) dblog("--> Finished oblist. Found %d objects.",obcount); // now load object defs for this player! fscanf(f, "obdefs\n"); for (i = 0; i < obcount; i++) { long thisid; if (db) dblog("--> Creating ob #%d for lf.",i); //if (db) dblog("-----> ob %d/%d...\n",i+1,obcount); if (loadob(f, l->pack, &thisid)) { dblog("Error - can't create object %d/%d!\n",i+1,obcount); exit(1); } if (db) dblog("----> done (id=%ld)",thisid); } // now repeat the above for polypack... obcount = 0; obid = 9998; // for testing rv = fscanf(f, "polyob:%ld\n",&obid); while (obid != -1) { if (db) dblog("--> Load ob id %d into polypack list...",obid); l->polypack->oblist[obcount] = obid; obcount++; fscanf(f, "polyob:%ld\n",&obid); } // terminate with -1s! for (i = obcount ; i < MAXPILEOBS; i++) { l->polypack->oblist[i] = -1; } if (db) dblog("--> Finished polypack oblist. Found %d objects.",obcount); // now load object defs for this lf's pack! fscanf(f, "polyobdefs\n"); for (i = 0; i < obcount; i++) { long thisid; if (db) dblog("--> Creating polypack ob #%d for lf.",i); //if (db) dblog("-----> ob %d/%d...\n",i+1,obcount); if (loadob(f, l->polypack, &thisid)) { dblog("Error - can't create object %d/%d!\n",i+1,obcount); exit(1); } if (db) dblog("----> done (id=%ld)",thisid); } // is this the player? if (l->controller == C_PLAYER) { player = l; } sortlf(l->cell->map, l); return l; } map_t *loadmap(FILE *f) { char buf[BUFLEN]; int obcount; int i; int x,y; int db = B_TRUE; enum HABITAT habitatid; int illum; lifeform_t *l; object_t *o; map_t *m; cell_t *dummycell; int regionid; // create map m = addmap(); dummycell = malloc(sizeof(cell_t)); dummycell->obpile = addobpile(NULL, dummycell, NULL); dummycell->map = m; dummycell->type = (celltype_t *)DUMMYCELLTYPE; // for debugging if (!m) { printf("Error creating map while loading."); return NULL; } // load map info if (db) dblog("--> Loading map info...\n"); fscanf(f, "id:%d\n",&m->id); // map id fscanf(f, "region:%d\n",®ionid); // region id m->region = findregion(regionid); fscanf(f, "depth:%d\n",&m->depth); // map depth fgets(buf, BUFLEN, f); // map name buf[strlen(buf)-1] = '\0'; // strip newline m->name = strdup(buf + 5); // after 'name:' fscanf(f, "habitat:%d\n",(int *)&habitatid); // habitat m->habitat = findhabitat(habitatid); fscanf(f, "seed:%u\n",&m->seed); // seed fscanf(f, "lastplayervisit:%ld\n",&m->lastplayervisit); fscanf(f, "dims:%d,%d\n",&m->w, &m->h); // map dimensons fscanf(f, "illumination:%d\n",&illum); m->illumination = illum; fscanf(f, "nextmaps:\n"); for (i = 0; i < MAXDIR_ORTH; i++) { fscanf(f, "%d\n",&m->nextmap[i]); // map dimensons } if (db) dblog("--> Finished map info. name='%s', dims=%d x %d\n",m->name, m->w, m->h); fscanf(f, "beingcreated:%d\n",&m->beingcreated); fscanf(f, "id:%d\n",&m->id); // map id // load lifeforms if (db) dblog("--> Loading lifeforms...\n"); fscanf(f, "lifeforms:\n"); fscanf(f, "%s\n",buf); while (!strcmp(buf ,"startlf")) { loadlf(f, dummycell); // check for more lifeforms... fscanf(f, "%s\n",buf); } // load room defs fscanf(f, "nrooms:%d\n",&m->nrooms); for (i = 0; i < m->nrooms; i++) { char line[BUFLEN]; fgets(line, BUFLEN, f); //if (line[strlen(line)-1] == '\n') line[strlen(line)-1] = '\0'; sscanf(line, "%d,%d,%d,%d,%d,%[ a-zA-Z_0-9+'*/-]\n",&m->room[i].id, &m->room[i].x1, &m->room[i].y1, &m->room[i].x2, &m->room[i].y2, buf); m->room[i].vault = findvault(buf); } // load cells if (db) dblog("--> Loading map cells...\n"); fscanf(f, "cells:\n"); for (y = 0; y < m->h; y++) { for (x = 0; x < m->w; x++) { cell_t *c; celltype_t *ct; int celltypeid; long obid; int temphab; int roomid; //if (db) dblog("cell %d,%d...",x,y); // allocate this cell c = addcell(m, x, y); // cell info fscanf(f, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", &roomid, &celltypeid,(int *) &c->known, &c->knowntime, &c->knownglyph.ch, &c->knownglyph.colour, &c->visited, &c->locked, &temphab, &c->isroomwall, &c->temperature); c->habitat = findhabitat(temphab); c->room = findroom(m, roomid); ct = findcelltype(celltypeid); if (ct) { c->type = ct; } else { dblog("ERROR loading map cells - can't find celltype id %ld\n",celltypeid); exit(1); } // cell objects obcount = 0; fscanf(f, "ob:%ld\n",&obid); while (obid != -1) { c->obpile->oblist[obcount] = obid; obcount++; fscanf(f, "ob:%ld\n",&obid); } // terminate with -1s! for (i = obcount ; i < MAXPILEOBS; i++) { c->obpile->oblist[i] = -1; } } } // load object definitions if (db) dblog("--> Loading object definitions for map obs...\n"); fscanf(f, "MAPOBS:%d\n",&obcount); // how many obs? // create all objects in a dummy cell for (i = 0; i < obcount; i++) { long thisid; if (db) dblog("-----> loading into dummycell: mapob %d/%d...\n",i+1,obcount); if (loadob(f, dummycell->obpile, &thisid)) { dblog("Error - can't create object %d/%d!\n",i+1,obcount); exit(1); } if (db) dblog("----------> got obid %ld\n",thisid); // check! if (!hasobid(dummycell->obpile, thisid)) { dblog("Error: after loading obid %ld, can't find it in dummycell!\n",thisid); exit(1); } } // hand out the objects to lifeforms... /* for (l = m->lf ; l ; l = l->next) { int curob = 0; long obid; obid = l->pack->oblist[curob]; while (obid != -1) { int found = B_FALSE; // find this ob id in the dummycell for (o = dummycell->obpile->first ; o ; o = nexto) { nexto = o->next; if (o->id == obid) { relinkob(o, l->pack); found = B_TRUE; break; } } if (!found) { dblog("Error loading obs - lf %d should have obid %ld but can't find it in dummycell.\n",l->id, obid); exit(1); } // next one curob++; obid = l->pack->oblist[curob]; } // clear the oblist for (i = 0; i < MAXPILEOBS; i++) { l->pack->oblist[i] = -1; } } */ // hand out objects to cells for (y = 0; y < m->h; y++) { for (x = 0; x < m->w; x++) { cell_t *c; long obid; int curob = 0; c = m->cell[y * m->w + x]; obid = c->obpile->oblist[curob]; dblog("Handing out objects to cell %d,%d\n",x,y); while (obid != -1) { dblog(" Looking for obid %ld in dummycell...",obid); // find this ob id in the dummycell o = hasobid(dummycell->obpile, obid); if (o) { dblog(" Got it."); relinkob(o, c->obpile); } else { dblog(" Error loading obs - cell %d,%d should have obid %ld but can't find it.\n",x,y, obid); exit(1); } // next one curob++; obid = c->obpile->oblist[curob]; } // clear the oblist for (i = 0; i < MAXPILEOBS; i++) { c->obpile->oblist[i] = -1; } } } // load flags loadflagpile(f, m->flags); // we are now finished loading from the file. // move lifeforms to their proper locations for (l = m->lf ; l ; l = l->next) { cell_t *c; c = getcellat(m, l->x, l->y); if (!c) { dblog("Error loading map - Can't find cell at %d,%d to place lifeform id %d.\n", l->x, l->y, l->id); exit(1); } movelf(l, c, B_FALSE); //dblog("Moving lf %d to %d,%d\n",l->id, l->x, l->y); } free(dummycell); return m; } int loadob(FILE *f, obpile_t *op, long *id) { objecttype_t *ot; object_t *o; material_t *mat; long obid; int otid,matid,b; char buf[BUFLEN]; int db = B_TRUE; fscanf(f, "id:%ld\n",&obid); fscanf(f, "type:%d\n",&otid); if (db) dblog("... loading object id %ld",obid); if (id) { *id = obid; } ot = findot(otid); if (!ot) { dblog("ERROR loading objects - can't find obtype id %d (obj id %ld)\n",otid,obid); return B_TRUE; } // create the object o = addobject(op, NULL, B_NOSTACK, B_FALSE, ot->id); // no stacking! // overwrite ob parameters o->id = obid; fscanf(f, "material:%d\n",&matid); mat = findmaterial(matid); if (!mat) { dblog("ERROR loading objects - can't find material %d\n",matid); return B_TRUE; } o->material = mat; fscanf(f, "weight:%f\n",&o->mass); fgets(buf, BUFLEN, f); // inscription buf[strlen(buf)-1] = '\0'; // strip newline o->inscription = strdup(buf + 6); // after 'inscr:' if (!strcmp(o->inscription, "^^^")) { // ie. if equal to ^^^... free(o->inscription); o->inscription = NULL; } fscanf(f, "letter:%c\n",&o->letter); fscanf(f, "bless:%d\n",&o->blessed); fscanf(f, "blessknown:%d\n",&o->blessknown); fscanf(f, "amt:%d\n",&o->amt); fscanf(f, "birthtime:%ld\n",&o->birthtime); // now remove ALL obejct flags (which were inherited // from the obtype during addobject() ). these will be // loaded in instead. foreach_bucket(b) { while (o->flags->first[b]) { killflag(o->flags->first[b]); } } dblog("About to start loading object flags..."); loadflagpile(f, o->flags); fgets(buf, BUFLEN, f);// either 'obcontents:xx' or 'endob' if (strstarts(buf, "obcontents")) { // load this object's contents... char *p; char buf2[BUFLEN]; int ncontents; int i; //dblog("got obcontents"); // strip newline buf[strlen(buf)-1] = '\0'; p = readuntil(buf2, buf, ':'); // ignore bit before : p = readuntil(buf2, p, ')'); // ) will really be eol ncontents = atoi(buf2); for (i = 0 ; i < ncontents; i++) { loadob(f, o->contents, NULL); } fgets(buf, BUFLEN, f);// 'endobcontents' //dblog("want endobcontents, got: '%s'", buf); fgets(buf, BUFLEN, f);// 'endob' //dblog("want endob, got: '%s'", buf); } if (strstarts(buf, "endob")) { // we got 'endob' } else { dblog("ERROR loading objects - expecting 'endob' but got '%s'\n",buf); exit(1); } //fscanf(f, "endob\n"); return B_FALSE; } int loadregions(FILE *f) { int rtid,nthings,i,n; int numoutlines,numregions; int db = B_TRUE; int depthmod; fscanf(f, "start_regions\n"); fscanf(f, "numoutlines:%d\n",&numoutlines); if (db) dblog("Found %d region outlines.\n",numoutlines); for (n = 0; n < numoutlines; n++) { regionthing_t *thing; if (db) dblog(" loading regionoutline #%d / %d",n+1, numoutlines); fscanf(f, "startro\n"); fscanf(f, "rtypeid:%d\n",&rtid); // region type id addregionoutline(rtid); fscanf(f, "nthings:%d\n",&nthings); for (i = 0; i < nthings; i++) { int depth,x,y,val,id; enum REGIONTHING whatkind; char buf[BUFLEN]; fscanf(f, "startthing\n"); fscanf(f, " thingid:%d\n",&id); fscanf(f, " thingdepth:%d,%d,%d\n",&depth, &x, &y); fscanf(f, " thingkind:%d\n",(int *)&whatkind); fscanf(f, " thingval:%d\n",&val); fscanf(f, " thingwhat:%[ a-zA-Z_0-9+'*/-]\n",buf); fscanf(f, "endthing\n"); // replace ^ with ' ' in thingwhat /* for (p = buf ; *p; p++) { if (*p == '^') *p = ' '; } */ if (db) dblog(" got regionthing: [%s]", buf); thing = addregionthing(lastregionoutline, depth, x, y, whatkind, val, streq(buf, "NULL") ? NULL : buf); thing->id = id; } fscanf(f, "endro\n"); if (db) dblog("Loaded regionoutline #%d / %d",n+1, numoutlines); } // now load in the actual region->outline mappings fscanf(f, "numregions:%d\n",&numregions); if (db) dblog("Found %d regions.\n",numregions); for (n = 0; n < numregions; n++) { region_t *r; enum BRANCH rtid; int rid; int outlineid,parentid,nthings,createdby; fscanf(f, "startregion\n"); fscanf(f, " rid:%d\n",(int *)&rid); fscanf(f, " rtypeid:%d\n",(int *)&rtid); fscanf(f, " outline:%d\n",&outlineid); fscanf(f, " parentregion:%d\n",&parentid); fscanf(f, " nthings:%d\n",&nthings); fscanf(f, " depthmod:%d\n",&depthmod); fscanf(f, " createdby:%d\n",&createdby); fscanf(f, "endregion\n"); r = addregion(rtid, (parentid == -1) ? NULL : findregion(parentid), outlineid, depthmod, createdby); r->id = rid; r->nthings = nthings; if (db) dblog("Loaded region #%d / %d",n+1, numregions); } fscanf(f, "end_regions\n"); return B_FALSE; } // returns TRUE if there was a savegame file. int loadsavegame(void) { char filename[BUFLEN]; FILE *f; int mapcount,i; // check for a save file... snprintf(filename, BUFLEN, "%s/game.sav",SAVEDIR); f = fopen(filename, "rt"); if (!f) { // this isn't an error - just means no savegames dblog("No savegame found."); return B_FALSE; } // load region outlines if (loadregions(f)) { printf("No region data found in savegame file!"); exit(1); } // load maps fscanf(f, "start_maps:%d\n",&mapcount); for (i = 0; i < mapcount; i++) { if (!loadmap(f)) { printf("Error loading map %d of %d!", i+1, mapcount); exit(1); } } fscanf(f, "end_maps\n"); // load world data if (loadworlddata(f)) { printf("Error load world data from save file."); exit(1); } // load player fscanf(f, "startlf\n"); if (!loadlf(f, NULL)) { printf("Error loading player from save file."); exit(1); } // load knowledge if (loadknowledge(f)) { printf("Error loading knowledge from save file."); exit(1); } // load game variables if (loadvars(f)) { printf("Error loading game variables from save file."); exit(1); } // successful load - close and kill the savegame file fclose(f); unlink(filename); return B_TRUE; } int savevars(FILE *f) { int db = B_FALSE; race_t *r; if (db) dblog("--> Saving knowledge...\n"); fprintf(f, "startvars\n"); fprintf(f, "curtime:%ld\n",curtime); fprintf(f, "endvars\n"); fprintf(f, "startknownraces\n"); for (r = firstrace ; r ; r = r->next) { if (r->known) { fprintf(f, "%d\n",r->id); } } fprintf(f, "-1\n"); fprintf(f, "endknownraces\n"); return B_FALSE; } int loadworlddata(FILE *f) { fscanf(f, "timedata:%ld,%ld,%ld\n",&curtime,&gamedays,&gamesecs); return B_FALSE; } int removevaultfile(char *filename) { if (unlink(filename)) { msg("ERROR: Could not unlink bones file after creation ('%s')", filename); dblog("ERROR: Could not unlink bones file after creation ('%s')", filename); return B_TRUE; } return B_FALSE; } // dynamically create a temporary vault file based on the given room. int savebones(map_t *m, room_t *r) { cell_t *c; int x,y; FILE *f; char filename[BUFLEN]; DIR *dp; struct dirent *ep; int maxid = 0, bonesid; celltype_t *ct; char ch; char nextch = 'a'; celltype_t *legendct[MAXCANDIDATES]; char legendch[MAXCANDIDATES]; int nlegends = 0,n; // get list of existing bones files dp = opendir(BONESDIR); if (dp != NULL) { while ((ep = readdir(dp)) != NULL) { char thisname[BUFLEN]; char *p; strcpy(thisname, ep->d_name); p = strstr(thisname, "bones"); if (p) { char numbuf[BUFLEN]; char *np; int thisid; p += 5; for (np = numbuf; isdigit(*p); p++, np++) { *np = *p; } *np = '\0'; thisid = atoi(numbuf); if (thisid > maxid) maxid = thisid; } } closedir(dp); } bonesid = maxid + 1; snprintf(filename, BUFLEN, "%s/bones%d.vlt",BONESDIR, bonesid); f = fopen(filename, "wt"); if (!f) { msg("Could not write bones file '%s'!", filename); return B_TRUE; } fprintf(f, "@id:bones%d\n", bonesid); fprintf(f, "@map\n"); for (y = r->y1; y <= r->y2; y++) { for (x = r->x1; x <= r->x2; x++) { c = getcellat(m, x, y); // do we already ahve a legend entry for this celltype? ct = NULL; ch = '\0'; for (n = 0; n < nlegends; n++ ){ if (legendct[n] == c->type) { ch = legendch[n]; break; } } if (ch == '\0') { ch = nextch; legendct[nlegends] = c->type; legendch[nlegends] = ch; nlegends++; if (nextch == 'z') nextch = 'A'; else if (nextch == 'Z') nextch = '0'; else nextch++; } // wall fprintf(f, "%c", ch); } fprintf(f, "\n"); } fprintf(f, "@end\n"); fprintf(f, "@legend\n"); for (n = 0; n < nlegends; n++){ fprintf(f, "%c:cell:%s\n",legendch[n], legendct[n]->name); } fprintf(f, "@end\n"); fprintf(f, "@flags\n"); // contents... for (y = r->y1; y <= r->y2; y++) { for (x = r->x1; x <= r->x2; x++) { c = getcellat(m, x, y); if (c) { object_t *o; int relx,rely; relx = x - r->x1; rely = y - r->y1; if (c->lf) { if (isplayer(c->lf)) { // the lf's objects will appear in the bones file for (o = c->lf->pack->first; o ; o = o->next) { saveobtobones(o, f, relx, rely); } } else { // the lf will appear in the bones file char lfname[BUFLEN]; // remove props killflagsofid(c->lf->flags, F_PETOF); real_getlfname(c->lf, lfname, NULL, B_SHOWALL, B_REALRACE); fprintf(f, "at(%d,%d) lf:%s\n", relx,rely, lfname); } } for (o = c->obpile->first ; o ; o = o->next) { saveobtobones(o, f, relx, rely); } } } } // other flags. fprintf(f, "tag:bones\n"); fprintf(f, "rarity:frequent\n"); fprintf(f, "goesin:%s\n", m->habitat->name); fprintf(f, "dlevmin:%d\n", m->depth); fprintf(f, "dlevmax:%d\n", m->depth); fprintf(f, "@end\n"); fclose(f); return B_FALSE; } int saveflagpile(FILE *f, flagpile_t *fp) { int b; flag_t *fl; fprintf(f, "flags:\n"); foreach_bucket(b) { for (fl = fp->first[b] ; fl ; fl = fl->next) { assert(!fl->skillfrom || findskill(fl->skillfrom->id)); fprintf(f, "%d,%d,%d,%d,%d,%d,%d,%ld,%d\n", fl->id, fl->nvals, fl->val[0], fl->val[1], fl->val[2],fl->lifetime,fl->known,fl->obfrom, fl->skillfrom ? fl->skillfrom->id : SK_NONE); if (!fl->text || !strcmp(fl->text, "")) { fprintf(f, "%s\n","^^^"); } else { fprintf(f, "%s\n",fl->text); } } } fprintf(f, "-1,-1,-1,-1,-1,-1,-1,-1\n"); return B_FALSE; } int saveknowledge(FILE *f) { int db = B_FALSE; knowledge_t *k; if (db) dblog("--> Saving knowledge...\n"); fprintf(f, "startknowledge\n"); for (k = knowledge; k ; k = k->next) { fprintf(f, "%d^%s^%d\n",k->id, k->hiddenname, k->known); } fprintf(f, "endknowledge\n"); return B_FALSE; } int savelf(FILE *f, lifeform_t *l) { object_t *o; int obcount = 0; // save this lf fprintf(f, "startlf\n"); fprintf(f, "lfid: %d\n",l->id); fprintf(f, "race: %d\n",l->race->id); fprintf(f, "map: %d\n",l->cell->map->id); fprintf(f, "pos: %d,%d\n",l->cell->x, l->cell->y); fprintf(f, "level: %d\n",l->level); fprintf(f, "newlevel: %d\n",l->newlevel); // liefform will be created after loading the above. fprintf(f, "str: %d/%d\n",l->att[A_STR],l->baseatt[A_STR]); fprintf(f, "dex: %d/%d\n",l->att[A_AGI],l->baseatt[A_AGI]); fprintf(f, "int: %d/%d\n",l->att[A_IQ],l->baseatt[A_IQ]); fprintf(f, "xp: %ld\n",l->xp); fprintf(f, "skillxp: %ld\n",l->skillxp); fprintf(f, "totskillpoints: %ld\n",l->totskillpoints); fprintf(f, "skp: %d\n",l->skillpoints); fprintf(f, "contr: %d\n",l->controller); fprintf(f, "hp: %d/%d\n",l->hp, l->maxhp); fprintf(f, "mp: %d/%d\n",l->mp, l->maxmp); fprintf(f, "stamina: %f\n", l->stamina); fprintf(f, "alive: %d\n",l->alive); fprintf(f, "lastdamtype: %d\n",l->lastdamtype); fprintf(f, "lastdam: %s\n",l->lastdam); fprintf(f, "material: %d\n",l->material->id); fprintf(f, "timespent: %d\n",l->timespent); fprintf(f, "sorted: %d\n",l->sorted); fprintf(f, "polyrevert: %d\n",l->polyrevert); fprintf(f, "forgettimer: %f\n",l->forgettimer); //fprintf(f, "eyeadj: %d\n",l->eyeadjustment); fprintf(f, "facing: %d\n",l->facing); fprintf(f, "turncounter: %d\n",l->turncounter); fprintf(f, "rotated: %d\n",l->rotated); // lf flags saveflagpile(f, l->flags); // lifeform objects obcount = 0; for (o = l->pack->first ; o ; o = o->next) { fprintf(f, "ob:%ld\n",o->id); obcount++; } fprintf(f, "ob:-1\n"); fprintf(f, "obdefs\n"); // now save our object definitions for (o = l->pack->first ; o ; o = o->next) { saveob(f, o); } // lifeform polypack objects obcount = 0; for (o = l->polypack->first ; o ; o = o->next) { fprintf(f, "polyob:%ld\n",o->id); obcount++; } fprintf(f, "polyob:-1\n"); fprintf(f, "polyobdefs\n"); // now save our polypack object definitions for (o = l->polypack->first ; o ; o = o->next) { saveob(f, o); } return B_FALSE; } int savegame(void) { map_t *m; FILE *f; char buf[BUFLEN]; int rv; int mapcount = 0; snprintf(buf, BUFLEN, "%s/game.sav",SAVEDIR); f = fopen(buf, "wt"); if (!f) { msg("Could not open save file!"); return B_TRUE; } rv = saveregions(f); if (rv) { msg("Could not save region data."); return B_TRUE; } for (m = firstmap; m ; m = m->next) { mapcount++; } fprintf(f, "start_maps:%d\n",mapcount); for (m = firstmap; m ; m = m->next) { // save world rv = savemap(f, m); if (rv) { msg("Could not save map '%s'",m->name); return B_TRUE; } } fprintf(f, "end_maps\n"); // load world data saveworlddata(f); // save player + their objects savelf(f, player); saveknowledge(f); savevars(f); fclose(f); return B_FALSE; } int savemap(FILE *f, map_t *m) { int i; object_t *o; lifeform_t *l; int x,y; int obcount = 0; // save map info fprintf(f, "id:%d\n",m->id); // map id fprintf(f, "region:%d\n",m->region->id); // map region id fprintf(f, "depth:%d\n",m->depth); // map depth fprintf(f, "name:%s\n",m->name); // map name fprintf(f, "habitat:%d\n",m->habitat->id); // habitat fprintf(f, "seed:%u\n",m->seed); // seed fprintf(f, "lastplayervisit:%ld\n",m->lastplayervisit); fprintf(f, "dims:%d,%d\n",m->w, m->h); // map dimensons fprintf(f, "illumination:%d\n",m->illumination); // seed fprintf(f, "nextmaps:\n"); for (i = 0; i < MAXDIR_ORTH; i++) { fprintf(f, "%d\n",m->nextmap[i] ); // map dimensons } fprintf(f, "beingcreated:%d\n",m->beingcreated); // save all non-player lifeforms (includes their objects) fprintf(f, "lifeforms:\n"); for (l = m->lf ; l ; l = l->next) { if (l->controller != C_PLAYER) { // don't save the player! savelf(f, l); } } fprintf(f, "endlifeforms\n"); // save room defs fprintf(f, "nrooms:%d\n",m->nrooms); for (i = 0; i < m->nrooms; i++) { fprintf(f, "%d,%d,%d,%d,%d,%s\n",m->room[i].id, m->room[i].x1, m->room[i].y1, m->room[i].x2, m->room[i].y2, m->room[i].vault ? m->room[i].vault->id : "^^^"); } // cells fprintf(f, "cells:\n"); for (y = 0; y < m->h; y++) { for (x = 0; x < m->w; x++) { cell_t *c; c = getcellat(m, x, y); // cell info fprintf(f, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", c->room ? c->room->id : -1, c->type->id, c->known, c->knowntime, c->knownglyph.ch, c->knownglyph.colour, c->visited,c->locked, c->habitat->id, c->isroomwall, c->temperature ); // cell objects for (o = c->obpile->first ; o ; o = o->next) { fprintf(f, "ob:%ld\n",o->id); obcount++; } fprintf(f, "ob:-1\n"); } } // save object definitions from map cells fprintf(f, "MAPOBS:%d\n",obcount); for (y = 0; y < m->h; y++) { for (x = 0; x < m->w; x++) { cell_t *c; c = getcellat(m, x, y); // cell objects for (o = c->obpile->first ; o ; o = o->next) { saveob(f, o); } } } saveflagpile(f, m->flags); return B_FALSE; } int saveob(FILE *f, object_t *o) { object_t *oo; int ncontents; fprintf(f, "id:%ld\n",o->id); fprintf(f, "type:%d\n",o->type->id); fprintf(f, "material:%d\n",o->material->id); fprintf(f, "weight:%f\n",o->mass); fprintf(f, "inscr:%s\n",o->inscription ? o->inscription : "^^^"); fprintf(f, "letter:%c\n",o->letter); fprintf(f, "bless:%d\n",o->blessed); fprintf(f, "blessknown:%d\n",o->blessknown); fprintf(f, "amt:%d\n",o->amt); fprintf(f, "birthtime:%ld\n",o->birthtime); saveflagpile(f, o->flags); // object contents... ncontents = countobs(o->contents, B_FALSE); if (ncontents) { fprintf(f, "obcontents:%d\n",ncontents); for (oo = o->contents->first ; oo ; oo = oo->next) { saveob(f, oo); } fprintf(f, "endobcontents\n"); } fprintf(f, "endob\n"); return B_FALSE; } int saveobtobones(object_t *o, FILE *f, int x, int y) { char obname[BUFLEN]; if (!obgoesinbones(o)) return B_TRUE; // chance that someone picked up the object if (onein(4)) return B_TRUE; // modify the object? if (hasflag(o->flags, F_DECAY)) { // food will decay by the time someone else finds it. return B_TRUE; } if (isweapon(o) || isarmour(o)) { // weapons/armour might degrade in quality if (hasflag(o->flags, F_MASTERWORK)) { // masterwork -> normal killflagsofid(o->flags, F_MASTERWORK); } else { if (onein(3)) { applyobmod(o, findobmod(OM_SHODDY)); } if (onein(3) && ismetal(o->material->id)) { addflag(o->flags, F_RUSTED, R_RUSTY, NA, NA, NULL); } } } if (o->material->id == MT_BLOOD) { sprintf(obname, "a blood stain"); } else if (o->type->id == OT_GRIMOIRE) { sprintf(obname, "grimoire"); } else { getobnametrue(o, obname, o->amt); } fprintf(f, "at(%d,%d) ob:%s\n", x,y, obname); return B_FALSE; } int saveregions(FILE *f) { int i; regionoutline_t *ro; region_t *r; int numoutlines = 0,numregions = 0; fprintf(f, "start_regions\n"); for (ro = firstregionoutline ; ro ; ro = ro->next) { numoutlines++; } fprintf(f, "numoutlines:%d\n",numoutlines); for (ro = firstregionoutline ; ro ; ro = ro->next) { // save this outline fprintf(f, "startro\n"); fprintf(f, "rtypeid:%d\n",ro->rtype->id); // region type id fprintf(f, "nthings:%d\n",ro->nthings); for (i = 0; i < ro->nthings; i++) { fprintf(f, "startthing\n"); fprintf(f, " thingid:%d\n",(int)ro->thing[i].id); fprintf(f, " thingdepth:%d,%d,%d\n",ro->thing[i].depth, ro->thing[i].x, ro->thing[i].y); fprintf(f, " thingkind:%d\n",(int)ro->thing[i].whatkind); fprintf(f, " thingval:%d\n",(int)ro->thing[i].value); if (strlen(ro->thing[i].what)) { char localwhat[BUFLEN]; strcpy(localwhat,ro->thing[i].what); /* for (p = localwhat ; *p; p++) { if (*p == ' ') *p = '^'; } */ fprintf(f, " thingwhat:%s\n",localwhat); } else { fprintf(f, " thingwhat:NULL\n"); } fprintf(f, "endthing\n"); } fprintf(f, "endro\n"); } // now save out the actual region->outline mappings numregions = 0; for (r = firstregion ; r; r = r->next) { numregions++; } fprintf(f, "numregions:%d\n",numregions); for (r = firstregion ; r; r = r->next) { fprintf(f, "startregion\n"); fprintf(f, " rid:%d\n",r->id); fprintf(f, " rtypeid:%d\n",r->rtype->id); fprintf(f, " outline:%d\n",r->outline ? r->outline->id : -1); fprintf(f, " parentregion:%d\n",r->parentregion ? r->parentregion->id : -1); fprintf(f, " nthings:%d\n",r->nthings); fprintf(f, " depthmod:%d\n",r->depthmod); fprintf(f, " createdby:%d\n",r->createdbymapid); fprintf(f, "endregion\n"); } fprintf(f, "end_regions\n"); return B_FALSE; } int saveworlddata(FILE *f) { fprintf(f, "timedata:%ld,%ld,%ld\n",curtime,gamedays,gamesecs); return B_FALSE; } int showhiscores(lifeform_t *lf, int min, int max) { sqlite3 *db; int rc; char filename[BUFLEN],*cmd; char *errmsg = NULL; char hilitescoretext[BUFLEN]; long hilitescore = -1; if (lf && !lfhasflag(lf, F_NOSCORE)) { hilitescore = calcscore(lf); if (hilitescore == 0) hilitescore = -1; } else { hilitescore = -1; } // open database snprintf(filename, BUFLEN, "%s/hiscores.db", DATADIR); rc = sqlite3_open(filename, &db); if (rc) { msg("error opening hiscore file '%s'.\n",filename); dblog("error opening hiscore file '%s'.\n",filename); return B_TRUE; } // show top ten //snprintf(cmd, BUFLEN, "select * from hiscores order by score desc limit 10;"); asprintf(&cmd, "select (select count(*) from hiscores b where b.score > a.score) + 1 as rank, score,name,job,killedby from hiscores a where (rank >= %d) and (rank <= %d) order by score desc limit 100;", min, max); snprintf(hilitescoretext, BUFLEN, "%ld",hilitescore); rc = sqlite3_exec(db, cmd, showhiscoreline, hilitescoretext, &errmsg); if (rc != SQLITE_OK) { msg("error %d reading hiscores: '%s'", rc, errmsg); dblog("query was: '%s'", cmd); dblog("error %d reading hiscores: '%s'\n sql command: [%s]", rc, errmsg, cmd); sqlite3_free(errmsg); } free(cmd); sqlite3_close(db); return B_FALSE; } // returns player's rank in 'rank' int writehiscore(lifeform_t *lf, int *rank) { sqlite3 *db; int rc; char filename[BUFLEN],*cmd; char pname[BUFLEN]; char racename[BUFLEN]; char jobname[BUFLEN]; char killedby[BUFLEN]; char *escaped; char *errmsg = NULL; sqlite3_stmt *smt; job_t *j; long minscore = 0; long score; score = calcscore(lf); // open database snprintf(filename, BUFLEN, "%s/hiscores.db", DATADIR); rc = sqlite3_open(filename, &db); if (rc) { msg("error %d opening hiscore file '%s'.\n",rc, filename); dblog("error %d opening hiscore file '%s'.\n",rc, filename); return B_TRUE; } getplayername(pname); j = getjob(player); strcpy(racename, player->race->name); capitalise(racename); snprintf(jobname, BUFLEN, "Lv%d %s %s", player->level, racename, getjobname(player)); makekillertext(killedby, lf->killverb, lf->lastdam, lf->cell->map, B_FALSE, B_TRUE); // add escapes escaped = strdup(killedby); strrep(&escaped, "'", "''", NULL); if (!lfhasflag(lf, F_NOSCORE) && (score > 0)) { asprintf(&cmd, "insert into 'hiscores' (score,name,job,killedby) VALUES (%ld, '%s', '%s', '%s')", score, pname, jobname, escaped); rc = sqlite3_exec(db, cmd, NULL, NULL, &errmsg); free(cmd); if (rc != SQLITE_OK) { msg("error writing hiscores: '%s'", errmsg); dblog("error writing hiscores: '%s'", errmsg); dblog("query was: '%s'", cmd); sqlite3_free(errmsg); } } free(escaped); if (rank) { if (lfhasflag(lf, F_NOSCORE)) { *rank = -1; } else if (score == 0) { *rank = -2; } else { // find out the player's rank asprintf(&cmd, "select (select count(*) from hiscores b where b.score > a.score) + 1 as rank from hiscores a where score = %ld;",score); rc = sqlite3_prepare_v2(db, cmd, -1, &smt, 0); free(cmd); rc = sqlite3_step(smt); while (rc == SQLITE_ROW) { const char *p; p = (const char *)sqlite3_column_text(smt, 0); *rank = atoi(p); rc = sqlite3_step(smt); } } } // now delete all hiscore entries after 100 // find score number 100... asprintf(&cmd, "select score from hiscores order by score desc limit 100;"); rc = sqlite3_prepare_v2(db, cmd, -1, &smt, 0); free(cmd); rc = sqlite3_step(smt); while (rc == SQLITE_ROW) { const char *p; p = (const char *)sqlite3_column_text(smt, 0); minscore = atol(p); rc = sqlite3_step(smt); } if (minscore > 0) { // we now have a minimum score - delete everything lower than it. asprintf(&cmd, "delete from hiscores where score < %ld;", minscore); rc = sqlite3_exec(db, cmd, NULL, NULL, &errmsg); free(cmd); } sqlite3_close(db); return 0; }