mirror of
https://github.com/ondra-novak/gates_of_skeldal.git
synced 2025-07-04 21:50:38 -04:00
1815 lines
47 KiB
C
1815 lines
47 KiB
C
#include <platform/platform.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <malloc.h>
|
|
|
|
#include <libs/pcx.h>
|
|
#include <libs/types.h>
|
|
#include <libs/bgraph.h>
|
|
#include <libs/event.h>
|
|
#include <libs/strlite.h>
|
|
#include <libs/devices.h>
|
|
#include <libs/bmouse.h>
|
|
#include <libs/memman.h>
|
|
#include <fcntl.h>
|
|
#include <platform/sound.h>
|
|
#include <stdarg.h>
|
|
#include "globals.h"
|
|
#include "temp_storage.h"
|
|
|
|
#include <assert.h>
|
|
#include <sys/stat.h>
|
|
#include <time.h>
|
|
#define STATE_CUR_VER 2
|
|
|
|
#define _GAME_ST "_GAME.TMP"
|
|
#define _GLOBAL_ST "_GLOBEV.TMP"
|
|
#define _SLOT_SAV "slot%02d.SAV"
|
|
#define SLOTS_MAX 10
|
|
|
|
#define GM_MAPENABLE 0x1
|
|
|
|
#define SAVE_SLOT_S 32
|
|
#define LOAD_SLOT_S (372+34)
|
|
#define SAVE_SLOT_E (34+203)
|
|
#define LOAD_SLOT_E (372+34+203)
|
|
|
|
#define SSAVE_VERSION 0
|
|
|
|
static TMPFILE_WR *story=NULL;
|
|
static char load_another;
|
|
static unsigned long current_campaign = 0;
|
|
static long prev_game_time_save = -999;
|
|
|
|
char reset_mobiles=0;
|
|
|
|
typedef struct s_save
|
|
{
|
|
int viewsector;
|
|
char viewdir;
|
|
short version;
|
|
char not_used;
|
|
int gold;
|
|
short cur_group;
|
|
char autosave;
|
|
char enable_sort;
|
|
char shownames;
|
|
char showlives;
|
|
char zoom_speed;
|
|
char turn_speed;
|
|
char autoattack;
|
|
char music_vol;
|
|
char sample_vol;
|
|
char xbass;
|
|
char bass;
|
|
char treble;
|
|
char stereing;
|
|
char swapchans;
|
|
char out_filter;
|
|
int32_t glob_flags;
|
|
int32_t game_time;
|
|
char runes[5];
|
|
char level_name[13];
|
|
short picks; //pocet_sebranych predmetu v mysi
|
|
short items_added; //pocet_pridanych predmetu
|
|
int sleep_long;
|
|
int game_flags;
|
|
}S_SAVE;
|
|
|
|
|
|
static int get_list_count();
|
|
|
|
static int unable_open_temp(char *c)
|
|
{
|
|
char d[]="Unable to open the file : ",*e;
|
|
|
|
concat(e,d,c);
|
|
closemode();
|
|
display_error(e);
|
|
SEND_LOG("(SAVELOAD) Open temp error detected (%s)",c);
|
|
exit(1);
|
|
}
|
|
|
|
static void unable_write_temp(char *c)
|
|
{
|
|
char d[]="Unable to write to the temp file : ",*e;
|
|
|
|
concat(e,d,c);
|
|
closemode();
|
|
display_error(e);
|
|
SEND_LOG("(SAVELOAD) Open temp error detected (%s)",c);
|
|
exit(1);
|
|
}
|
|
|
|
|
|
int load_org_map(char *filename,TSTENA **sides,TSECTOR **sectors,TMAP_EDIT_INFO **coords,int *mapsize)
|
|
{
|
|
FILE *f;
|
|
void *temp;
|
|
int sect;
|
|
int32_t size,r;
|
|
char nmapend=1;
|
|
|
|
|
|
const char *c=build_pathname(2, gpathtable[SR_MAP],filename);
|
|
f=fopen_icase(c,"rb");
|
|
if (f==NULL) return -1;
|
|
do
|
|
{
|
|
r=load_section(f,&temp,§,&size);
|
|
if (r==size)
|
|
switch (sect)
|
|
{
|
|
case A_SIDEMAP:
|
|
*sides=temp;
|
|
break;
|
|
case A_SECTMAP:
|
|
*sectors=temp;
|
|
if (mapsize!=NULL) *mapsize=size/sizeof(TSECTOR);
|
|
break;
|
|
case A_MAPINFO:
|
|
if (coords!=NULL) *coords=temp;else free(temp);
|
|
break;
|
|
case A_MAPGLOB:
|
|
//memcpy(&mglob,temp,min(sizeof(mglob),size));
|
|
free(temp);
|
|
break;
|
|
case A_MAPEND :
|
|
nmapend=0;
|
|
free(temp);
|
|
break;
|
|
default: free(temp);
|
|
}
|
|
else
|
|
{
|
|
if (temp!=NULL)free(temp);
|
|
fclose(f);
|
|
return -1;
|
|
}
|
|
}
|
|
while (nmapend);
|
|
fclose(f);
|
|
return 0;
|
|
}
|
|
|
|
void save_daction(TMPFILE_WR *f,int count,D_ACTION *ptr)
|
|
{
|
|
if (ptr!=NULL)
|
|
{
|
|
save_daction(f,count+1,ptr->next);
|
|
temp_storage_write(ptr,sizeof(D_ACTION),f);
|
|
}
|
|
else
|
|
temp_storage_write(&count,2,f);
|
|
}
|
|
|
|
void load_daction(TMPFILE_RD *fsta)
|
|
{
|
|
uint16_t i,j;
|
|
i=0;
|
|
while (d_action!=NULL) //vymaz pripadne delaited actions
|
|
{
|
|
D_ACTION *p;
|
|
p=d_action; d_action=p->next;free(p);
|
|
}
|
|
temp_storage_read(&i,2,fsta);d_action=NULL;
|
|
for(j=0;j<i;j++)
|
|
{
|
|
D_ACTION *p;
|
|
|
|
p=(D_ACTION *)getmem(sizeof(D_ACTION));
|
|
temp_storage_read(p,sizeof(D_ACTION),fsta);
|
|
p->next=d_action;
|
|
d_action=p;
|
|
}
|
|
}
|
|
|
|
void save_items(TMPFILE_WR *f)
|
|
{
|
|
int32_t i,j;
|
|
short *c;
|
|
|
|
for(i=0;i<mapsize*4;i++)
|
|
if (map_items[i]!=NULL)
|
|
{
|
|
for(j=1,c=map_items[i];*c;c++,j++);
|
|
temp_storage_write(&i,sizeof(i),f);
|
|
temp_storage_write(&j,sizeof(j),f);
|
|
temp_storage_write(map_items[i],2*j,f);
|
|
}
|
|
i=-1;
|
|
temp_storage_write(&i,sizeof(i),f);
|
|
}
|
|
|
|
void restore_items(TMPFILE_RD *f)
|
|
{
|
|
int32_t i,j;
|
|
|
|
short **new_item_map = getmem(mapsize*4*sizeof(*map_items));
|
|
memset(new_item_map,0,mapsize*4*sizeof(*map_items));
|
|
while(temp_storage_read(&i,sizeof(i),f) && i!=-1) {
|
|
temp_storage_read(&j,sizeof(j),f);
|
|
new_item_map[i]=(short *)getmem(j*2);
|
|
temp_storage_read(new_item_map[i],2*j,f);
|
|
short *v = new_item_map[i];
|
|
while (*v) { //sanitize map items
|
|
if (*v < 1 || *v >= item_count) {
|
|
free(new_item_map[i]);
|
|
new_item_map[i] = map_items[i];
|
|
map_items[i] = NULL;
|
|
break;
|
|
}
|
|
++v;
|
|
}
|
|
}
|
|
|
|
for(i=0;i<mapsize*4;i++) if (map_items[i]!=NULL) free(map_items[i]);
|
|
memset(map_items,0,mapsize*4*sizeof(*map_items));
|
|
map_items = new_item_map;
|
|
|
|
}
|
|
|
|
extern TSTR_LIST texty_v_mape;
|
|
|
|
void save_map_description(TMPFILE_WR *f)
|
|
{
|
|
int count,max;
|
|
int32_t i;
|
|
|
|
if (texty_v_mape==NULL) max=0;else max=str_count(texty_v_mape);
|
|
for(i=0,count=0;i<max;i++) if (texty_v_mape[i]!=NULL) count++;
|
|
temp_storage_write(&count,1*sizeof(count),f);
|
|
for(i=0;i<max;i++) if (texty_v_mape[i]!=NULL)
|
|
{
|
|
word len;
|
|
len=strlen(texty_v_mape[i]+12)+12+1;
|
|
temp_storage_write(&len,1*2,f);
|
|
temp_storage_write(texty_v_mape[i],1*len,f);
|
|
}
|
|
}
|
|
|
|
void load_map_description(TMPFILE_RD *f)
|
|
{
|
|
int32_t count;
|
|
int32_t i;
|
|
word len;
|
|
|
|
if (texty_v_mape!=NULL)release_list(texty_v_mape);
|
|
temp_storage_read(&count,1*sizeof(count),f);
|
|
if (!count)
|
|
{
|
|
texty_v_mape=NULL;
|
|
return;
|
|
}
|
|
texty_v_mape=create_list(count);
|
|
for(i=0;i<count;i++)
|
|
{
|
|
temp_storage_read(&len,1*2,f);
|
|
{
|
|
char *s;
|
|
s=(char *)alloca(len);
|
|
memset(s,1,len-1);
|
|
s[len-1]=0;
|
|
str_replace(&texty_v_mape,i,s);
|
|
}
|
|
temp_storage_read(texty_v_mape[i],1*len,f);
|
|
}
|
|
}
|
|
|
|
void save_vyklenky(TMPFILE_WR *fsta)
|
|
{
|
|
temp_storage_write(&vyk_max,1*sizeof(vyk_max),fsta);
|
|
if (vyk_max)
|
|
temp_storage_write(map_vyk,vyk_max*sizeof(TVYKLENEK),fsta);
|
|
}
|
|
|
|
int load_vyklenky(TMPFILE_RD *fsta)
|
|
{
|
|
int i=0;
|
|
temp_storage_read(&i,1*sizeof(vyk_max),fsta);
|
|
if (vyk_max)
|
|
{
|
|
if (i>vyk_max) return -2;
|
|
temp_storage_read(map_vyk,vyk_max*sizeof(TVYKLENEK),fsta);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
void save_all_fly(TMPFILE_WR *fsta)
|
|
{
|
|
LETICI_VEC *f;
|
|
int32_t sz = 1;
|
|
|
|
f=letici_veci;
|
|
while (f!=NULL)
|
|
{
|
|
short *c;
|
|
|
|
sz = sizeof(*f);
|
|
temp_storage_write(&sz,sizeof(sz),fsta);
|
|
temp_storage_write(f,sz,fsta);
|
|
c=f->items;
|
|
if (c!=NULL) do temp_storage_write(c,1*2,fsta); while (*c++);
|
|
f=f->next;
|
|
}
|
|
sz = 0;
|
|
temp_storage_write(&sz,sizeof(sz),fsta);
|
|
}
|
|
|
|
int load_all_fly(TMPFILE_RD *fsta)
|
|
{
|
|
LETICI_VEC *n;
|
|
int32_t sz;
|
|
|
|
destroy_all_fly();
|
|
|
|
temp_storage_read(&sz,sizeof(sz),fsta);
|
|
while (sz == sizeof(LETICI_VEC))
|
|
{
|
|
short items[100],*c;
|
|
n=New(LETICI_VEC);
|
|
c=items;memset(items,0,sizeof(items));
|
|
if (temp_storage_read(n,1*sizeof(*n),fsta)!=sizeof(*n))
|
|
{
|
|
free(n);
|
|
return -2;
|
|
}
|
|
if (n->items!=NULL)
|
|
{
|
|
do
|
|
temp_storage_read(c,2,fsta);
|
|
while (*c++);
|
|
n->items=NewArr(short,c-items);
|
|
memcpy(n->items,items,(c-items)*sizeof(short));
|
|
}
|
|
add_fly(n);
|
|
temp_storage_read(&sz,sizeof(sz),fsta);
|
|
}
|
|
return sz != 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
int save_map_state() //uklada stav mapy pro savegame (neuklada aktualni pozici);
|
|
{
|
|
char sta[200];
|
|
char *bf = NULL;
|
|
TMPFILE_WR *fsta;
|
|
int32_t i;
|
|
int32_t siz;
|
|
TSTENA *org_sides;
|
|
TSECTOR *org_sectors;
|
|
short res=-1;
|
|
unsigned char ver=0;
|
|
|
|
strcpy(sta,level_fname);
|
|
fsta=temp_storage_create(sta);if (fsta==NULL) unable_open_temp(sta);
|
|
SEND_LOG("(SAVELOAD) Saving map state for current map");
|
|
if (load_org_map(level_fname,&org_sides,&org_sectors,NULL,NULL)) goto err;
|
|
siz=(mapsize+7)/8;
|
|
bf=(char *)getmem(siz);
|
|
ver=STATE_CUR_VER;
|
|
temp_storage_write(&ver,sizeof(ver)*1,fsta); //<-------------------------
|
|
temp_storage_write(&mapsize,sizeof(mapsize)*1,fsta); //<-------------------------
|
|
memset(bf,0,siz);
|
|
temp_storage_write(&siz,1*sizeof(siz),fsta); //<-------------------------
|
|
for(i=0;i<mapsize;i++) //save automap
|
|
if (map_coord[i].flags & MC_AUTOMAP) bf[i>>3]|=1<<(i & 7);
|
|
temp_storage_write(bf,siz*1,fsta);
|
|
for(i=0;i<mapsize;i++) //save disclosed
|
|
if (map_coord[i].flags & MC_DISCLOSED) bf[i>>3]|=1<<(i & 7);
|
|
temp_storage_write(bf,siz*1,fsta);
|
|
save_map_description(fsta);
|
|
for(i=0;i<mapsize*4;i++) //save changed sides
|
|
if (memcmp(map_sides+i,org_sides+i,sizeof(TSTENA)))
|
|
{
|
|
temp_storage_write(&i,sizeof(i),fsta);
|
|
temp_storage_write(map_sides+i,1*sizeof(TSTENA),fsta);
|
|
}
|
|
i=-1;
|
|
temp_storage_write(&i,sizeof(i),fsta);
|
|
for(i=0;i<mapsize;i++) //save changed sectors
|
|
if (memcmp(map_sectors+i,org_sectors+i,sizeof(TSECTOR)))
|
|
{
|
|
temp_storage_write(&i,sizeof(i),fsta);
|
|
temp_storage_write(map_sectors+i,1*sizeof(TSECTOR),fsta);
|
|
}
|
|
i=-1;
|
|
temp_storage_write(&i,sizeof(i),fsta);
|
|
for(i=0;i<MAX_MOBS;i++) if (mobs[i].vlajky & MOB_LIVE)
|
|
{
|
|
temp_storage_write(&i,sizeof(i),fsta);
|
|
temp_storage_write(mobs+i,sizeof(TMOB),fsta); //save_mobmap
|
|
}
|
|
i=-1;
|
|
temp_storage_write(&i,sizeof(i),fsta);
|
|
i=mapsize*4;
|
|
temp_storage_write(&i,sizeof(i),fsta); //save flag maps //<-------------------------
|
|
temp_storage_write(flag_map,i,fsta);
|
|
save_daction(fsta,0,d_action); //save dactions//<-------------------------
|
|
temp_storage_write(¯o_state_block.count,1*sizeof(macro_state_block.count),fsta);
|
|
if (macro_state_block.count)temp_storage_write(macro_state_block.states,1*macro_state_block.count,fsta);//save_macros
|
|
if (save_codelocks(fsta)) goto err;
|
|
save_items(fsta);
|
|
save_vyklenky(fsta);
|
|
save_all_fly(fsta);
|
|
save_enemy_paths(fsta);
|
|
res=0;
|
|
err:
|
|
SEND_LOG("(SAVELOAD) State of current map saved (err:%d)",res);
|
|
temp_storage_close_wr(fsta);
|
|
free(org_sectors);
|
|
free(org_sides);
|
|
free(bf);
|
|
if (res)
|
|
{
|
|
remove(sta);
|
|
unable_write_temp(sta);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
int load_map_state() //obnovuje stav mapy; nutno volat po zavolani load_map;
|
|
{
|
|
char sta[200];
|
|
char *bf = NULL;
|
|
TMPFILE_RD *fsta;
|
|
int32_t i;
|
|
int32_t siz;
|
|
short res=-2;
|
|
unsigned char ver=0;
|
|
|
|
strcpy(sta,level_fname);
|
|
fsta=temp_storage_open(sta);if (fsta==NULL) return -1;
|
|
i=0;
|
|
if (!temp_storage_read(&ver,sizeof(ver)*1,fsta)) goto err;
|
|
if (ver>STATE_CUR_VER) goto err;
|
|
if (!temp_storage_read(&i,sizeof(mapsize)*1,fsta)) goto err;
|
|
if (mapsize!=i) goto err;
|
|
SEND_LOG("(SAVELOAD) Loading map state for current map");
|
|
temp_storage_read(&siz,1*sizeof(siz),fsta);
|
|
bf=(char *)getmem(siz);
|
|
if (!temp_storage_read(bf,siz*1,fsta)) goto err;
|
|
for (i=0;i<mapsize;i++)
|
|
if ((bf[i>>3]>>(i & 7)) & 1) map_coord[i].flags|=MC_AUTOMAP;
|
|
if (!temp_storage_read(bf,siz*1,fsta)) goto err;
|
|
for (i=0;i<mapsize;i++)
|
|
if ((bf[i>>3]>>(i & 7)) & 1) map_coord[i].flags|=MC_DISCLOSED;
|
|
load_map_description(fsta);
|
|
while (temp_storage_read(&i,sizeof(i),fsta) && i >= 0 && i<=mapsize*4)
|
|
if (temp_storage_read(map_sides+i,1*sizeof(TSTENA),fsta)!=sizeof(TSTENA)) goto err;
|
|
while (temp_storage_read(&i,sizeof(i),fsta) && i >= 0 && i<=mapsize)
|
|
if (temp_storage_read(map_sectors+i,1*sizeof(TSECTOR),fsta)!=sizeof(TSECTOR)) goto err;
|
|
if (reset_mobiles) //reloads mobiles if flag present
|
|
{
|
|
char mm[MAX_MOBS];
|
|
for(i=0;i<MAX_MOBS;mobs[i].vlajky &=~MOB_LIVE,i++)
|
|
if (mobs[i].vlajky & MOB_LIVE) mm[i]=1;else mm[i]=0;
|
|
while (temp_storage_read(&i,1*2,fsta) && i<=MAX_MOBS)
|
|
{
|
|
if (mm[i]) mobs[i].vlajky |=MOB_LIVE;
|
|
temp_storage_skip(fsta,sizeof(TMOB));
|
|
}
|
|
reset_mobiles=0;
|
|
}
|
|
else
|
|
{
|
|
for(i=0;i<MAX_MOBS;(mobs[i].vlajky &=~MOB_LIVE),i++);
|
|
while (temp_storage_read(&i,sizeof(i),fsta) && i>=0 && i<=MAX_MOBS)
|
|
if (temp_storage_read(mobs+i,1*sizeof(TMOB),fsta)!=sizeof(TMOB)) goto err;
|
|
}
|
|
for(i=0;i<MAX_MOBS;i++) mobs[i].vlajky &=~MOB_IN_BATTLE;
|
|
refresh_mob_map();
|
|
temp_storage_read(&i,sizeof(i),fsta);
|
|
temp_storage_read(flag_map,i,fsta);
|
|
load_daction(fsta);
|
|
size_t stsz;
|
|
temp_storage_read(&stsz,sizeof(macro_state_block.count),fsta);
|
|
if (macro_state_block.count == stsz) {
|
|
temp_storage_read(macro_state_block.states,macro_state_block.count,fsta);
|
|
}
|
|
else
|
|
{
|
|
temp_storage_skip(fsta,stsz);
|
|
SEND_LOG("(ERROR) Multiaction: Sizes mismatch %lu != %lu",stsz,macro_state_block.count);
|
|
}
|
|
if (load_codelocks(fsta)) goto err;
|
|
restore_items(fsta);
|
|
res=0;
|
|
res|=load_vyklenky(fsta);
|
|
res|=load_all_fly(fsta);
|
|
res|=load_enemy_paths(fsta);
|
|
|
|
err:
|
|
SEND_LOG("(SAVELOAD) State of current map loaded (err:%d)",res);
|
|
temp_storage_close_rd(fsta);
|
|
free(bf);
|
|
return res;
|
|
}
|
|
|
|
void restore_current_map() //pouze obnovuje ulozeny stav aktualni mapy
|
|
{
|
|
int i;
|
|
|
|
SEND_LOG("(SAVELOAD) Restore map...");
|
|
kill_all_sounds();
|
|
for(i=0;i<mapsize;i++) map_coord[i].flags&=~0x7f; //vynuluj flags_info
|
|
free(map_sides); //uvolni informace o stenach
|
|
free(map_sectors); //uvolni informace o sektorech
|
|
free(map_coord); //uvolni minfo informace
|
|
load_org_map(level_fname,&map_sides,&map_sectors,&map_coord,NULL); //nahrej originalni mapu
|
|
load_map_state(); //nahrej ulozenou mapu
|
|
for(i=1;i<mapsize*4;i++) call_macro(i,MC_STARTLEV);
|
|
}
|
|
|
|
static void add_status_file(FILE *f, const char *name, size_t sz, void *data) {
|
|
size_t name_size = strlen(name);
|
|
uint8_t name_size_b;
|
|
if (name_size > 255) name_size_b = 255; else name_size_b = (uint8_t)name_size;
|
|
fwrite(&name_size_b,1,1,f);
|
|
fwrite(name, 1, name_size_b, f);
|
|
uint32_t data_size = sz;
|
|
fwrite(&data_size,1,sizeof(data_size),f);
|
|
fwrite(data, 1,data_size, f);
|
|
}
|
|
|
|
static void pack_status_file_cb(const char *name, void *ctx) {
|
|
FILE *f = ctx;
|
|
int32_t sz = temp_storage_find(name);
|
|
assert(sz > 0);
|
|
void *data = getmem(sz);
|
|
temp_storage_retrieve(name, data, sz);
|
|
add_status_file(f, name, sz, data);
|
|
free(data);
|
|
}
|
|
|
|
int pack_all_status(FILE *f)
|
|
{
|
|
char c = 0;
|
|
temp_storage_list(pack_status_file_cb, f);
|
|
fwrite(&c,1,1,f);
|
|
return 0;
|
|
}
|
|
|
|
|
|
typedef enum enum_all_status_callback_result_t {
|
|
|
|
enum_status_cont_skip, //continue, skip this block
|
|
enum_status_cont_read, //continue, i read this block
|
|
enum_status_skip_stop, //stop, skip this block
|
|
enum_status_read_stop, //stop, don't skip i read this block
|
|
enum_status_error //error
|
|
|
|
} ENUM_ALL_STATUS_CALLBACK_RESULT;
|
|
|
|
//return 1 success, 0 stopped, -1 error
|
|
static int enum_all_status(FILE *f, ENUM_ALL_STATUS_CALLBACK_RESULT (*cb)(FILE *, const char *, size_t , void *), void *ctx) {
|
|
while(1) {
|
|
uint8_t name_size_b;
|
|
if (fread(&name_size_b, 1,1,f)==0) return 1;
|
|
char *name = (char *)alloca(name_size_b+1);
|
|
if (fread(name, 1, name_size_b, f) != name_size_b) return -1;
|
|
name[name_size_b] = 0;
|
|
uint32_t data_size;
|
|
if (fread(&data_size,1,sizeof(uint32_t),f) != sizeof(uint32_t)) return -1;
|
|
ENUM_ALL_STATUS_CALLBACK_RESULT st = cb(f, name, data_size, ctx);
|
|
switch (st) {
|
|
case enum_status_error: return 0;
|
|
case enum_status_cont_skip: fseek(f, data_size, SEEK_CUR);break;
|
|
case enum_status_cont_read: break;
|
|
case enum_status_skip_stop: fseek(f, data_size, SEEK_CUR);return 0;
|
|
case enum_status_read_stop: return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
static ENUM_ALL_STATUS_CALLBACK_RESULT unpack_status_callback(FILE *f, const char *name, size_t datasize, void *_) {
|
|
void *buff = getmem(datasize);
|
|
if (fread(buff, 1, datasize, f) != datasize) {
|
|
free(buff);
|
|
return enum_status_error;;
|
|
}
|
|
temp_storage_store(name, buff, datasize);
|
|
free(buff);
|
|
return enum_status_cont_read;
|
|
}
|
|
|
|
int unpack_all_status(FILE *f)
|
|
{
|
|
int r = enum_all_status(f, &unpack_status_callback, NULL);
|
|
if (r) return 0;
|
|
return -1;
|
|
}
|
|
|
|
int save_basic_info()
|
|
{
|
|
TMPFILE_WR *f;
|
|
S_SAVE s;
|
|
short *p;
|
|
int i;
|
|
char res=0;
|
|
THUMAN *h;
|
|
|
|
SEND_LOG("(SAVELOAD) Saving basic info for game (file:%s)",_GAME_ST );
|
|
f=temp_storage_create(_GAME_ST);
|
|
if (f==NULL) return 1;
|
|
s.viewsector=viewsector;
|
|
s.viewdir=viewdir;
|
|
s.version=SSAVE_VERSION;
|
|
s.not_used=0;
|
|
s.gold=money;
|
|
s.cur_group=cur_group;
|
|
s.shownames=show_names;
|
|
s.showlives=show_lives;
|
|
s.autoattack=autoattack;
|
|
s.turn_speed=turn_speed(-1);
|
|
s.zoom_speed=zoom_speed(-1);
|
|
s.game_time=game_time;
|
|
s.enable_sort=enable_sort;
|
|
s.sleep_long=sleep_ticks;
|
|
s.sample_vol=MIN(get_snd_effect(SND_GFX),255);
|
|
s.music_vol=MIN(get_snd_effect(SND_MUSIC),255);
|
|
s.xbass=MIN(get_snd_effect(SND_XBASS),255);
|
|
s.bass=MIN(get_snd_effect(SND_BASS),255);
|
|
s.treble=MIN(get_snd_effect(SND_TREBL),255);
|
|
s.stereing=MIN(get_snd_effect(SND_LSWAP),255);
|
|
s.swapchans=MIN(get_snd_effect(SND_SWAP),255);
|
|
s.out_filter=MIN(get_snd_effect(SND_OUTFILTER),255);
|
|
s.autosave=autosave_enabled;
|
|
s.game_flags=(enable_glmap!=0);
|
|
strcopy_n(s.level_name,level_fname,sizeof(s.level_name));
|
|
for(i=0;i<5;i++) s.runes[i]=runes[i];
|
|
if (picked_item!=NULL)
|
|
for(i=1,p=picked_item;*p;i++,p++);else i=0;
|
|
s.picks=i;
|
|
s.items_added=item_count-it_count_orgn;
|
|
temp_storage_write(&s,1*sizeof(s),f);
|
|
if (i)
|
|
temp_storage_write(picked_item,2*i,f);
|
|
if (s.items_added)
|
|
temp_storage_write(glob_items+it_count_orgn,sizeof(TITEM)*s.items_added,f);
|
|
save_spells(f);
|
|
temp_storage_write(postavy,1*sizeof(postavy),f);
|
|
for(i=0,h=postavy;i<POCET_POSTAV;h++,i++) if (h->demon_save!=NULL)
|
|
temp_storage_write(h->demon_save,sizeof(THUMAN)*1,f); //ulozeni polozek s demony
|
|
res|=save_dialog_info(f);
|
|
temp_storage_close_wr(f);
|
|
SEND_LOG("(SAVELOAD) Done... Result: %d",res);
|
|
return res;
|
|
}
|
|
|
|
int load_basic_info()
|
|
{
|
|
TMPFILE_RD *f;
|
|
S_SAVE s;
|
|
int i;
|
|
char res=0;
|
|
TITEM *itg;
|
|
THUMAN *h;
|
|
|
|
SEND_LOG("(SAVELOAD) Loading basic info for game (file:%s)",_GAME_ST);
|
|
f=temp_storage_open(_GAME_ST);
|
|
if (f==NULL) return 1;
|
|
res|=(temp_storage_read(&s,1*sizeof(s),f)!=sizeof(s));
|
|
if (s.game_flags & GM_MAPENABLE) enable_glmap=1;else enable_glmap=0;
|
|
i=s.picks;
|
|
if (picked_item!=NULL) free(picked_item);
|
|
if (i)
|
|
{
|
|
picked_item=NewArr(short,i);
|
|
res|=(temp_storage_read(picked_item,2*i,f)!=(unsigned)i);
|
|
}
|
|
else picked_item=NULL;
|
|
itg=NewArr(TITEM,it_count_orgn+s.items_added);
|
|
memcpy(itg,glob_items,it_count_orgn*sizeof(TITEM));
|
|
free(glob_items);glob_items=itg;
|
|
if (s.items_added)
|
|
res|=(temp_storage_read(glob_items+it_count_orgn,sizeof(TITEM)*s.items_added,f)!=(unsigned)s.items_added);
|
|
item_count=it_count_orgn+s.items_added;
|
|
res|=load_spells(f);
|
|
for(i=0,h=postavy;i<POCET_POSTAV;h++,i++) if (h->demon_save!=NULL) free(h->demon_save);
|
|
if (!res) res|=(temp_storage_read(postavy,1*sizeof(postavy),f)!=sizeof(postavy));
|
|
for(i=0,h=postavy;i<POCET_POSTAV;h++,i++)
|
|
{
|
|
h->programovano=0;
|
|
h->provadena_akce=h->zvolene_akce=NULL;
|
|
h->dostal=0;
|
|
if (h->demon_save!=NULL)
|
|
{
|
|
h->demon_save=New(THUMAN);
|
|
temp_storage_read(h->demon_save,sizeof(THUMAN)*1,f);//obnova polozek s demony
|
|
}
|
|
}
|
|
res|=load_dialog_info(f);
|
|
temp_storage_close_rd(f);
|
|
viewsector=s.viewsector;
|
|
viewdir=s.viewdir;
|
|
cur_group=s.cur_group;
|
|
show_names=s.shownames;
|
|
show_lives=s.showlives;
|
|
autoattack=s.autoattack;
|
|
turn_speed(s.turn_speed);
|
|
zoom_speed(s.zoom_speed);
|
|
game_time=s.game_time;
|
|
sleep_ticks=s.sleep_long;
|
|
enable_sort=s.enable_sort;
|
|
autosave_enabled=s.autosave;
|
|
money=s.gold;
|
|
for(i=0;i<5;i++) runes[i]=s.runes[i];
|
|
set_snd_effect(SND_GFX,s.sample_vol);
|
|
set_snd_effect(SND_MUSIC,s.music_vol);
|
|
set_snd_effect(SND_XBASS,s.xbass);
|
|
set_snd_effect(SND_BASS,s.bass);
|
|
set_snd_effect(SND_TREBL,s.treble);
|
|
set_snd_effect(SND_LSWAP,s.stereing);
|
|
set_snd_effect(SND_SWAP,s.swapchans);
|
|
set_snd_effect(SND_OUTFILTER,s.out_filter);
|
|
if (level_fname==NULL || strcmp(s.level_name,level_fname))
|
|
{
|
|
strcopy_n(loadlevel.name,s.level_name,sizeof(loadlevel.name));
|
|
loadlevel.start_pos=viewsector;
|
|
loadlevel.dir=viewdir;
|
|
send_message(E_CLOSE_MAP,NULL);
|
|
load_another=1;
|
|
}
|
|
else load_another=0;
|
|
for(i=0;i<POCET_POSTAV;i++) postavy[i].dostal=0;
|
|
SEND_LOG("(SAVELOAD) Done... Result: %d",res);
|
|
return res;
|
|
}
|
|
|
|
|
|
static int save_global_events()
|
|
{
|
|
TMPFILE_WR *f;
|
|
f=temp_storage_create(_GLOBAL_ST);
|
|
if (f==NULL) return 1;
|
|
temp_storage_write(GlobEventList,1*sizeof(GlobEventList),f);
|
|
temp_storage_close_wr(f);
|
|
return 0;
|
|
}
|
|
|
|
static int load_global_events()
|
|
{
|
|
TMPFILE_RD *f;
|
|
memset(GlobEventList,0,sizeof(GlobEventList));
|
|
|
|
f=temp_storage_open(_GLOBAL_ST);
|
|
if (f==NULL) return 1;
|
|
temp_storage_read(GlobEventList,1*sizeof(GlobEventList),f);
|
|
temp_storage_close_rd(f);
|
|
return 0;
|
|
}
|
|
|
|
int save_game(int game_time,char *gamename)
|
|
{
|
|
char *gn;
|
|
FILE *svf;
|
|
int r;
|
|
|
|
if (current_campaign == 0) {
|
|
time_t t;
|
|
time(&t);
|
|
current_campaign = (unsigned long) t;
|
|
}
|
|
|
|
char str_buff[50];
|
|
snprintf(str_buff,sizeof(str_buff),"sav.%08lx.%08X", current_campaign, game_time);
|
|
|
|
|
|
SEND_LOG("(SAVELOAD) Saving game slot %d",game_time);
|
|
save_map_state();
|
|
const char *sn = build_pathname(2,gpathtable[SR_SAVES],str_buff);
|
|
sn = local_strdup(sn);
|
|
create_directories(gpathtable[SR_SAVES]);
|
|
gn=alloca(SAVE_NAME_SIZE);
|
|
strcopy_n(gn,gamename,SAVE_NAME_SIZE);
|
|
if ((r=save_shops())!=0) return r;
|
|
if ((r=save_basic_info())!=0) return r;
|
|
save_book();
|
|
save_global_events();
|
|
svf=fopen_icase(sn,"wb");
|
|
if (svf==NULL)
|
|
{
|
|
char buff[256];
|
|
sprintf(buff,"Nelze ulozit pozici na cestu: %s", sn);
|
|
display_error(buff);
|
|
}
|
|
else
|
|
{
|
|
fwrite(gn,1,SAVE_NAME_SIZE,svf);
|
|
close_story_file();
|
|
r=pack_all_status(svf);
|
|
open_story_file();
|
|
fclose(svf);
|
|
}
|
|
SEND_LOG("(SAVELOAD) Game saved.... Result %d",r);
|
|
disable_intro();
|
|
return r;
|
|
}
|
|
|
|
extern char running_battle;
|
|
|
|
int load_game(const char *fname)
|
|
{
|
|
FILE *svf;
|
|
int r,t;
|
|
|
|
sscanf(fname,"sav.%lx.%lx", ¤t_campaign, &prev_game_time_save);
|
|
|
|
SEND_LOG("(SAVELOAD) Loading file: %s",fname);
|
|
if (battle) konec_kola();
|
|
battle=0;
|
|
close_story_file();
|
|
purge_temps(0);
|
|
const char *sn = build_pathname(2, gpathtable[SR_SAVES], fname);
|
|
svf=fopen_icase(sn,"rb");
|
|
if (svf==NULL) return 1;
|
|
fseek(svf,SAVE_NAME_SIZE,SEEK_CUR);
|
|
r=unpack_all_status(svf);
|
|
fclose(svf);
|
|
open_story_file();
|
|
if (r>0)
|
|
{
|
|
SEND_LOG("(ERROR) Error detected during unpacking game... Loading stopped (result:%d)",r);
|
|
return r;
|
|
}
|
|
load_book();
|
|
load_global_events();
|
|
if ((t=load_saved_shops())!=0) return t;
|
|
if ((t=load_basic_info())!=0) return t;
|
|
running_battle=0;
|
|
norefresh=0;
|
|
if (!load_another) restore_current_map();
|
|
else
|
|
{
|
|
save_map=0;
|
|
norefresh=1;
|
|
}
|
|
for(t=0;t<POCET_POSTAV;t++) postavy[t].zvolene_akce=NULL;
|
|
SEND_LOG("(SAVELOAD) Game loaded.... Result %d",r);
|
|
// if (GetKeyState(VK_CONTROL) & 0x80) correct_level();
|
|
return r;
|
|
}
|
|
|
|
typedef struct load_specific_file_callback_data_t {
|
|
const char *name;
|
|
size_t size;
|
|
void *data;
|
|
|
|
} LOAD_SPECIFIC_FILE_CALLBACK_DATA;
|
|
|
|
static ENUM_ALL_STATUS_CALLBACK_RESULT load_specific_file_callback(FILE *f, const char *name, size_t datasize, void *ctx) {
|
|
LOAD_SPECIFIC_FILE_CALLBACK_DATA *me = ctx;
|
|
if (istrcmp(name, me->name) == 0) {
|
|
void *d = getmem(datasize);
|
|
if (fread(d, 1, datasize, f) != datasize) {
|
|
free(d);
|
|
return enum_status_error;
|
|
}
|
|
me->size = datasize;
|
|
me->data = d;
|
|
return enum_status_read_stop;
|
|
} else {
|
|
return enum_status_cont_skip;
|
|
}
|
|
|
|
}
|
|
|
|
//------------------------ SAVE LOAD DIALOG ----------------------------
|
|
static char force_save;
|
|
//static TSTR_LIST slot_list=NULL;
|
|
static int last_select=-1;
|
|
|
|
static TSTR_LIST story_text=NULL;
|
|
static void *back_texture=NULL;
|
|
static int cur_story_pos=0;
|
|
//static char load_mode;
|
|
|
|
#define SLOT_SPACE 33
|
|
#define SLOT_FONT H_FBOLD
|
|
#define SELECT_COLOR RGB555(31,31,31)
|
|
#define NORMAL_COLOR RGB555(12,31,12)
|
|
#define STORY_X 57
|
|
#define STORY_Y 50
|
|
#define STORY_XS (298-57)
|
|
#define STORY_YS (302-50)
|
|
|
|
#if 0
|
|
void read_slot_list()
|
|
{
|
|
int i;
|
|
char *name;
|
|
char slotname[SAVE_NAME_SIZE];
|
|
if (slot_list==NULL) slot_list=create_list(SLOTS_MAX);
|
|
const char *mask = build_pathname(2, gpathtable[SR_SAVES],_SLOT_SAV);
|
|
name=alloca(strlen(mask)+1);
|
|
for(i=0;i<SLOTS_MAX;i++)
|
|
{
|
|
FILE *f;
|
|
sprintf(name,mask,i);
|
|
f=fopen_icase(name,"rb");
|
|
if (f!=NULL)
|
|
{
|
|
fread(slotname,1,SAVE_NAME_SIZE,f);
|
|
fclose(f);
|
|
used_pos[i]=1;
|
|
}
|
|
else
|
|
{
|
|
strcpy(slotname,texty[75]);
|
|
used_pos[i]=0;
|
|
}
|
|
str_replace(&slot_list,i,slotname);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
typedef struct {
|
|
TSTR_LIST files;
|
|
TSTR_LIST names;
|
|
size_t count;
|
|
} TSAVEGAME_LIST;
|
|
|
|
static TSAVEGAME_LIST current_game_slot_list = {};
|
|
static int current_slot_list_top_line = 0;
|
|
|
|
typedef struct {
|
|
TSTR_LIST files;
|
|
const char *prefix;
|
|
size_t prefix_len;
|
|
size_t count;
|
|
} TSAVEGAME_CB_STATE;
|
|
|
|
static char is_same_prefix(const char *name, const char *prev_name) {
|
|
const char *sep1 = strrchr(name, '.');
|
|
const char *sep2 = strrchr(prev_name, '.');
|
|
if (!sep1 || !sep2) return 0;
|
|
if ((sep1 - name) != (sep2 - prev_name)) return 0;
|
|
if (strncmp(name, prev_name,sep1-name) == 0) return 1;
|
|
return 0;
|
|
}
|
|
|
|
static int get_all_savegames_callback(const char *name, LIST_FILE_TYPE type , size_t tm, void *ctx) {
|
|
if (istrncmp(name, "sav.", 4) != 0
|
|
&& istrcmp(name+strlen(name)-4,".sav") != 0)
|
|
return 0;
|
|
TSAVEGAME_CB_STATE *st = (TSAVEGAME_CB_STATE *)ctx;
|
|
if (st->prefix_len == 0 || strncmp(name, st->prefix, st->prefix_len) == 0) {
|
|
size_t nlen = strlen(name);
|
|
if (st->count == (size_t)str_count(st->files)) {
|
|
TSTR_LIST nw = create_list(st->count * 3/2);
|
|
str_move_list(nw, st->files);;
|
|
release_list(st->files);
|
|
st->files = nw;
|
|
}
|
|
char *buff = NewArr(char, nlen + 1 + sizeof(tm));
|
|
strncpy(buff, name, nlen+1);
|
|
memcpy(buff+nlen+1, &tm, sizeof(tm));
|
|
st->files[st->count] = buff;
|
|
++st->count;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int compare_strings (const void *a, const void *b) {
|
|
return strcmp(*(const char **)a, *(const char **)b);
|
|
}
|
|
|
|
static int compare_by_time (const void *a, const void *b) {
|
|
const char *s1 = *(const char **)a;
|
|
const char *s2 = *(const char **)b;
|
|
size_t tm1;
|
|
size_t tm2;
|
|
memcpy(&tm1, s1 + strlen(s1)+1, sizeof(tm1));
|
|
memcpy(&tm2, s2 + strlen(s2)+1, sizeof(tm2));
|
|
return tm1<tm2?1:tm1>tm2?-1:0;
|
|
}
|
|
|
|
static int dedup_strings_prefix(TSTR_LIST lst, int count) {
|
|
int j = -1;
|
|
for (int i = 0; i < count; ++i) {
|
|
if (j < 0 || !is_same_prefix(lst[j], lst[i])) {
|
|
++j;
|
|
}
|
|
if (j != i) lst[j] = lst[i];
|
|
}
|
|
++j;
|
|
int r = j;
|
|
while (j != count) {
|
|
lst[j] = NULL;
|
|
++j;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
|
|
/*
|
|
static void load_specific_file(int slot_num,char *filename,void **out,int32_t *size) //call it in task!
|
|
{
|
|
FILE *slot;
|
|
|
|
if (current_game_slot_list.count <= (size_t)slot_num) {
|
|
*out = NULL;
|
|
return;
|
|
}
|
|
|
|
slot=fopen_icase(build_pathname(2, gpathtable[SR_SAVES], current_game_slot_list.files[slot_num]),"rb");
|
|
if (slot==NULL)
|
|
{
|
|
*out=NULL;
|
|
return;
|
|
}
|
|
fseek(slot,SAVE_NAME_SIZE,SEEK_CUR);
|
|
|
|
LOAD_SPECIFIC_FILE_CALLBACK_DATA ctx;
|
|
ctx.name = filename;
|
|
|
|
*out = NULL;
|
|
*size = 0;
|
|
if (enum_all_status(slot, &load_specific_file_callback, &ctx) == 0){
|
|
*out = ctx.data;
|
|
*size = ctx.size;
|
|
}
|
|
fclose(slot);
|
|
}
|
|
*/
|
|
static void load_specific_file(const char *filename,const char *name, void **out,int32_t *size) //call it in task!
|
|
{
|
|
FILE *slot;
|
|
|
|
|
|
slot=fopen_icase(build_pathname(2, gpathtable[SR_SAVES], filename),"rb");
|
|
if (slot==NULL)
|
|
{
|
|
*out=NULL;
|
|
return;
|
|
}
|
|
fseek(slot,SAVE_NAME_SIZE,SEEK_CUR);
|
|
|
|
LOAD_SPECIFIC_FILE_CALLBACK_DATA ctx;
|
|
ctx.name = name;
|
|
|
|
*out = NULL;
|
|
*size = 0;
|
|
if (enum_all_status(slot, &load_specific_file_callback, &ctx) == 0){
|
|
*out = ctx.data;
|
|
*size = ctx.size;
|
|
}
|
|
fclose(slot);
|
|
}
|
|
|
|
|
|
static TSAVEGAME_LIST get_all_savegames(unsigned long kampan) {
|
|
//sav.creation_time.game_save_time
|
|
char prefix[50];
|
|
snprintf(prefix,50,"sav.%08lx.",kampan);
|
|
TSAVEGAME_CB_STATE st;
|
|
st.files = create_list(32);
|
|
st.prefix = kampan?prefix:NULL;
|
|
st.prefix_len = kampan?strlen(prefix):0;
|
|
st.count = 0;
|
|
list_files(gpathtable[SR_SAVES], file_type_just_name|file_type_need_timestamp|file_type_normal, get_all_savegames_callback, &st);
|
|
qsort(st.files, st.count, sizeof(char *), compare_strings);
|
|
if (kampan == 0) {
|
|
st.count =dedup_strings_prefix(st.files, (int)st.count);
|
|
}
|
|
qsort(st.files, st.count, sizeof(char *), compare_by_time);
|
|
|
|
TSTR_LIST names = create_list(st.count);
|
|
for (size_t i = 0; i < st.count; ++i) {
|
|
FILE *f=fopen_icase(build_pathname(2, gpathtable[SR_SAVES], st.files[i]), "rb");
|
|
if (f!=NULL) {
|
|
char slotname[SAVE_NAME_SIZE+1];
|
|
fread(slotname,1,SAVE_NAME_SIZE,f);
|
|
slotname[SAVE_NAME_SIZE] = 0;
|
|
fclose(f);
|
|
str_replace(&names, i, slotname);
|
|
} else {
|
|
str_replace(&names, i, texty[75]);
|
|
}
|
|
}
|
|
|
|
TSAVEGAME_LIST out;
|
|
out.files = st.files;
|
|
out.names = names;
|
|
out.count = st.count;
|
|
return out;
|
|
}
|
|
|
|
static void free_savegame_list(TSAVEGAME_LIST *lst) {
|
|
release_list(lst->files);
|
|
release_list(lst->names);
|
|
lst->files = 0;
|
|
lst->names = 0;
|
|
}
|
|
|
|
static void place_name(int c,int i,char show, char sel)
|
|
{
|
|
int z,x;
|
|
int p = i + current_slot_list_top_line;
|
|
if ((size_t)p >= current_game_slot_list.count) return;
|
|
if (c) x=SAVE_SLOT_S;else x=LOAD_SLOT_S;
|
|
if (show) schovej_mysku();
|
|
const char *name = current_game_slot_list.names[p];
|
|
set_font(SLOT_FONT,sel?SELECT_COLOR:NORMAL_COLOR);
|
|
int w = text_width(name);
|
|
int spc = 0;
|
|
if (w > 210) {
|
|
int len = strlen(name);
|
|
int extra = (w-210)/len;
|
|
spc = -extra-1;
|
|
}
|
|
position(x,z=i*SLOT_SPACE+21+SCREEN_OFFLINE);
|
|
outtext_ex(name,spc);
|
|
if (show)
|
|
{
|
|
ukaz_mysku();
|
|
showview(x,z,204,18);
|
|
}
|
|
}
|
|
|
|
static void redraw_save()
|
|
{
|
|
int i;
|
|
schovej_mysku();
|
|
put_picture(0,SCREEN_OFFLINE,ablock(H_SAVELOAD));
|
|
put_picture(274,SCREEN_OFFLINE,ablock(H_SVITEK));
|
|
for(i=0;i<SLOTS_MAX;i++) {
|
|
place_name(1,i,0,0);
|
|
}
|
|
ukaz_mysku();
|
|
}
|
|
|
|
static void redraw_load()
|
|
{
|
|
int i;
|
|
schovej_mysku();
|
|
put_picture(0,SCREEN_OFFLINE,ablock(H_SVITEK));
|
|
put_picture(372,SCREEN_OFFLINE,ablock(H_SAVELOAD));
|
|
for(i=0;i<SLOTS_MAX;i++) place_name(0,i,0,0);
|
|
ukaz_mysku();
|
|
}
|
|
|
|
static void redraw_story_bar(int pos)
|
|
{
|
|
int i,y,ys,x,count;
|
|
schovej_mysku();
|
|
if (force_save) x=STORY_X+274;else x=STORY_X;
|
|
if (back_texture==NULL)
|
|
{
|
|
back_texture=getmem(STORY_XS*STORY_YS*2+6);
|
|
get_picture(x,STORY_Y+SCREEN_OFFLINE,STORY_XS,STORY_YS,back_texture);
|
|
}
|
|
else
|
|
put_picture(x,STORY_Y+SCREEN_OFFLINE,back_texture);
|
|
if (story_text!=NULL)
|
|
{
|
|
y=SCREEN_OFFLINE+STORY_Y;
|
|
ys=STORY_YS;
|
|
count=str_count(story_text);
|
|
set_font(H_FONT6,NOSHADOW(0));
|
|
for(i=pos;i<count;i++) if (story_text[i]!=NULL)
|
|
{
|
|
int h;
|
|
|
|
h=text_height(story_text[i]);
|
|
if (ys<2*h) break;
|
|
position(x,y);outtext(story_text[i]);
|
|
ys-=h;
|
|
y+=h;
|
|
}
|
|
}
|
|
ukaz_mysku();
|
|
showview(x,STORY_Y+SCREEN_OFFLINE,STORY_XS,STORY_YS);
|
|
}
|
|
/*
|
|
static void read_story_task(va_list args)
|
|
{
|
|
int slot=va_arg(args,int);
|
|
|
|
TSTR_LIST ls;
|
|
void *text_data;
|
|
char *c,*d;
|
|
int32_t size;
|
|
|
|
load_specific_file(slot,STORY_BOOK,&text_data,&size);
|
|
if (text_data!=NULL)
|
|
{
|
|
ls=create_list(2);
|
|
c=text_data;
|
|
set_font(H_FONT6,0);
|
|
while (size>0)
|
|
{
|
|
int xs,ys;
|
|
d=c;
|
|
while (size>0 && *d!='\r' && *d!='\n') {d++;size--;};
|
|
if (!size) break;
|
|
*d=0;
|
|
{
|
|
char *e,*or;
|
|
or=e=getmem(strlen(c)+2);
|
|
zalamovani(c,e,STORY_XS,&xs,&ys);
|
|
while (*e)
|
|
{
|
|
str_add(&ls,e);
|
|
if (text_width(e)>STORY_XS) abort();
|
|
e=strchr(e,0)+1;
|
|
}
|
|
c=d+1;size--;
|
|
if (size > 0 &&(*c=='\n' || *c=='\r')) {c++;size--;};
|
|
free(or);
|
|
}
|
|
}
|
|
free(text_data);
|
|
}
|
|
else ls=NULL;
|
|
if (story_text!=NULL) release_list(story_text);
|
|
story_text=ls;
|
|
cur_story_pos=get_list_count();if (cur_story_pos<0) cur_story_pos=0;
|
|
redraw_story_bar(cur_story_pos);
|
|
}
|
|
|
|
static void read_story(int slot)
|
|
{
|
|
static int task_num=-1;
|
|
|
|
if (task_num!=-1) term_task(task_num);
|
|
if (slot!=-1)
|
|
task_num=add_task(8196,read_story_task,slot);
|
|
}
|
|
*/
|
|
|
|
static void read_story(const char *filename) {
|
|
void *text_data;
|
|
int32_t size;
|
|
TSTR_LIST ls;
|
|
char *c,*d;
|
|
|
|
load_specific_file(filename,STORY_BOOK,&text_data,&size);
|
|
if (text_data!=NULL)
|
|
{
|
|
ls=create_list(2);
|
|
c=text_data;
|
|
set_font(H_FONT6,0);
|
|
while (size>0)
|
|
{
|
|
int xs,ys;
|
|
d=c;
|
|
while (size>0 && *d!='\r' && *d!='\n') {d++;size--;};
|
|
if (!size) break;
|
|
*d=0;
|
|
{
|
|
char *e,*or;
|
|
or=e=getmem(strlen(c)+2);
|
|
zalamovani(c,e,STORY_XS,&xs,&ys);
|
|
while (*e)
|
|
{
|
|
str_add(&ls,e);
|
|
if (text_width(e)>STORY_XS) abort();
|
|
e=strchr(e,0)+1;
|
|
}
|
|
c=d+1;size--;
|
|
if (size > 0 &&(*c=='\n' || *c=='\r')) {c++;size--;};
|
|
free(or);
|
|
}
|
|
}
|
|
free(text_data);
|
|
}
|
|
else ls=NULL;
|
|
if (story_text!=NULL) release_list(story_text);
|
|
story_text=ls;
|
|
cur_story_pos=get_list_count();if (cur_story_pos<0) cur_story_pos=0;
|
|
redraw_story_bar(cur_story_pos);
|
|
|
|
}
|
|
|
|
static int get_list_count()
|
|
{
|
|
int count,i,max=0;
|
|
|
|
if (story_text==NULL) return 0;
|
|
count=str_count(story_text);
|
|
for(i=0;i<count;i++) if (story_text[i]!=NULL) max=i;
|
|
return max-20;
|
|
}
|
|
|
|
static void select_slot(int i);
|
|
|
|
static int bright_slot(int yr)
|
|
{
|
|
int id;
|
|
|
|
id=yr/SLOT_SPACE+current_slot_list_top_line;
|
|
select_slot(id);
|
|
return id;
|
|
}
|
|
|
|
char updown_scroll(int id,int xa,int ya,int xr,int yr);
|
|
|
|
static char updown_noinst=0;
|
|
|
|
static void updown_scroll_hold(EVENT_MSG *msg,void **_)
|
|
{
|
|
if (msg->msg == E_MOUSE)
|
|
{
|
|
MS_EVENT *ms;
|
|
|
|
ms=get_mouse(msg);
|
|
if (ms->event_type==0x4 || !ms->tl1 || ms->tl2 || ms->tl3)
|
|
{
|
|
send_message(E_DONE,E_MOUSE,updown_scroll_hold);
|
|
send_message(E_DONE,E_TIMER,updown_scroll_hold);
|
|
updown_noinst=0;
|
|
}
|
|
}
|
|
if (msg->msg == E_TIMER)
|
|
{
|
|
MS_EVENT *ms;
|
|
|
|
updown_noinst=1;
|
|
ms=&ms_last_event;
|
|
ms->event_type=0x2;
|
|
send_message(E_MOUSE,ms);
|
|
if (updown_noinst)
|
|
{
|
|
send_message(E_DONE,E_MOUSE,updown_scroll_hold);
|
|
send_message(E_DONE,E_TIMER,updown_scroll_hold);
|
|
updown_noinst=0;
|
|
}
|
|
else
|
|
updown_noinst=1;
|
|
}
|
|
}
|
|
|
|
char updown_scroll(int id,int xa,int ya,int xr,int yr)
|
|
{
|
|
int count;
|
|
xr,yr,xa,ya;
|
|
if (story_text==NULL) return 0;
|
|
cur_story_pos+=id;
|
|
count=get_list_count();
|
|
if (cur_story_pos>count) cur_story_pos=count;
|
|
if (cur_story_pos<0) cur_story_pos=0;
|
|
redraw_story_bar(cur_story_pos);
|
|
if (updown_noinst)
|
|
{
|
|
updown_noinst=0;
|
|
return 1;
|
|
}
|
|
send_message(E_ADD,E_MOUSE,updown_scroll_hold);
|
|
send_message(E_ADD,E_TIMER,updown_scroll_hold);
|
|
return 1;
|
|
}
|
|
|
|
static char close_saveload(int id,int xa,int ya,int xr,int yr)
|
|
{
|
|
xa;ya;xr;yr;id;
|
|
if (ms_last_event.event_type & 0x8)
|
|
{
|
|
unwire_proc();
|
|
wire_proc();
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
char clk_load_konec(int id,int xa,int ya,int xr,int yr)
|
|
{
|
|
id;xa;ya;xr;yr;
|
|
send_message(E_CLOSE_MAP,NULL);
|
|
return 1;
|
|
}
|
|
|
|
static char clk_load_proc(int id,int xa,int ya,int xr,int yr);
|
|
|
|
#define CLK_LOAD_ERROR 5
|
|
T_CLK_MAP clk_load_error[]=
|
|
{
|
|
{-1,59,14+SCREEN_OFFLINE,306,46+SCREEN_OFFLINE,updown_scroll,2,H_MS_ZARE},
|
|
{1,59,310+SCREEN_OFFLINE,306,332+SCREEN_OFFLINE,updown_scroll,2,H_MS_ZARE},
|
|
{-1,LOAD_SLOT_S,SCREEN_OFFLINE,LOAD_SLOT_E,350,clk_load_proc,3,H_MS_DEFAULT},
|
|
{-1,30,0,85,14,clk_load_konec,2,H_MS_DEFAULT},
|
|
{-1,0,0,639,479,empty_clk,0xff,H_MS_DEFAULT},
|
|
};
|
|
|
|
|
|
|
|
static char clk_load_proc_menu(int id,int xa,int ya,int xr,int yr)
|
|
{
|
|
id=bright_slot(yr-18);
|
|
xa;ya;xr;yr;
|
|
if (ms_last_event.event_type & 0x2 && id>=0 && (size_t)id < current_game_slot_list.count) {
|
|
send_message(E_CLOSE_MAP,current_game_slot_list.files[id]);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
#define CLK_LOAD_MENU 5
|
|
T_CLK_MAP clk_load_menu[]=
|
|
{
|
|
{-1,59,14+SCREEN_OFFLINE,306,46+SCREEN_OFFLINE,updown_scroll,2,H_MS_ZARE},
|
|
{1,59,310+SCREEN_OFFLINE,306,332+SCREEN_OFFLINE,updown_scroll,2,H_MS_ZARE},
|
|
{-1,LOAD_SLOT_S,SCREEN_OFFLINE,LOAD_SLOT_E,350,clk_load_proc_menu,3,H_MS_DEFAULT},
|
|
{-1,0,0,639,479,clk_load_konec,8,H_MS_DEFAULT},
|
|
{-1,0,0,639,479,empty_clk,0xff,H_MS_DEFAULT},
|
|
};
|
|
|
|
static void load_save_pos_ingame(int id) {
|
|
if (load_game(current_game_slot_list.files[id]))
|
|
{
|
|
message(1,0,0,"",texty[79],texty[80]);
|
|
redraw_load();
|
|
showview(0,0,0,0);
|
|
change_click_map(clk_load_error,CLK_LOAD_ERROR);
|
|
}
|
|
else
|
|
{
|
|
unwire_proc();
|
|
wire_proc();
|
|
if (battle) konec_kola();
|
|
unwire_proc();
|
|
if (!load_another)
|
|
{
|
|
wire_main_functs();
|
|
cur_mode=MD_GAME;
|
|
bott_draw(1);
|
|
pick_set_cursor();
|
|
for(id=0;id<mapsize;id++) map_coord[id].flags&=~MC_DPLAYER;
|
|
build_player_map();
|
|
}
|
|
reg_grafiku_postav();
|
|
build_all_players();
|
|
cancel_render=1;
|
|
}
|
|
|
|
}
|
|
|
|
static char clk_load_proc(int id,int xa,int ya,int xr,int yr)
|
|
{
|
|
id=bright_slot(yr-18);
|
|
xa;ya;xr;yr;
|
|
if (ms_last_event.event_type & 0x2 && id>=0 && (size_t)id < current_game_slot_list.count)
|
|
{
|
|
load_save_pos_ingame(id);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static char global_gamename[SAVE_NAME_SIZE];
|
|
static int slot_pos;
|
|
|
|
void save_step_next(EVENT_MSG *msg,void **unused)
|
|
{
|
|
int c;
|
|
|
|
unused;
|
|
if (msg->msg==E_KEYBOARD)
|
|
{
|
|
c=va_arg(msg->data, int);
|
|
if (c==13)
|
|
{
|
|
send_message(E_KEYBOARD,c);
|
|
save_game(slot_pos,global_gamename);
|
|
wire_proc();
|
|
// read_slot_list();
|
|
msg->msg=-2;
|
|
}
|
|
else if(c==27)
|
|
{
|
|
send_message(E_KEYBOARD,c);
|
|
msg->msg=-2;
|
|
wire_save_load(1);
|
|
}
|
|
}
|
|
}
|
|
static char clk_askname_stop(int id,int xa,int ya,int xr,int yr)
|
|
{
|
|
id,xa,ya,xr,yr;
|
|
if (ms_last_event.event_type & 0x2)
|
|
{
|
|
send_message(E_KEYBOARD,13);
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
send_message(E_KEYBOARD,27);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
static void save_it(char ok)
|
|
{
|
|
if (ok)
|
|
{
|
|
save_game(slot_pos,global_gamename);
|
|
// read_slot_list();
|
|
wire_proc();
|
|
GlobEvent(MAGLOB_AFTERSAVE,viewsector,viewdir);
|
|
}
|
|
else
|
|
{
|
|
wire_save_load(force_save);
|
|
}
|
|
}
|
|
|
|
#define CLK_ASK_NAME 2
|
|
T_CLK_MAP clk_ask_name[]=
|
|
{
|
|
{-1,0,0,639,479,clk_askname_stop,8+2,H_MS_DEFAULT},
|
|
{-1,0,0,639,479,empty_clk,0xff,H_MS_DEFAULT},
|
|
};
|
|
|
|
|
|
|
|
void wire_ask_gamename(int id)
|
|
{
|
|
int x,y;
|
|
|
|
x=SAVE_SLOT_S;
|
|
y=id*SLOT_SPACE+21+SCREEN_OFFLINE;
|
|
slot_pos=id;
|
|
schovej_mysku();
|
|
put_picture(x,y,ablock(H_LOADTXTR));
|
|
//strcpy(global_gamename,slot_list[id]);
|
|
clk_ask_name[0].id=add_task(16384,type_text_v2,global_gamename,x,y,SAVE_SLOT_E-SAVE_SLOT_S,SAVE_NAME_SIZE,H_FBOLD,RGB555(31,31,0),save_it);
|
|
change_click_map(clk_ask_name,CLK_ASK_NAME);
|
|
ukaz_mysku();
|
|
}
|
|
|
|
|
|
#define CLK_SAVELOAD 11
|
|
T_CLK_MAP clk_load[]=
|
|
{
|
|
{-1,LOAD_SLOT_S,SCREEN_OFFLINE,LOAD_SLOT_E,350,clk_load_proc,3,H_MS_DEFAULT},
|
|
{-1,59,14+SCREEN_OFFLINE,306,46+SCREEN_OFFLINE,updown_scroll,2,H_MS_ZARE},
|
|
{1,59,310+SCREEN_OFFLINE,306,332+SCREEN_OFFLINE,updown_scroll,2,H_MS_ZARE},
|
|
{-1,54,378,497,479,start_invetory,2+8,-1},
|
|
{-1,337,0,357,14,go_map,2,H_MS_DEFAULT},
|
|
|
|
{-1,291,0,313,14,go_book,2,H_MS_DEFAULT},
|
|
{-1,87,0,142,14,game_setup,2,H_MS_DEFAULT},
|
|
{-1,30,0,85,14,konec,2,H_MS_DEFAULT},
|
|
{1,147,0,205,14,clk_saveload,2,H_MS_DEFAULT},
|
|
{-1,267,0,289,15,clk_sleep,2,H_MS_DEFAULT},
|
|
{-1,0,0,639,479,close_saveload,9,H_MS_DEFAULT},
|
|
};
|
|
|
|
|
|
static char clk_save_proc(int id,int xa,int ya,int xr,int yr)
|
|
{
|
|
id=bright_slot(yr-18)+current_slot_list_top_line;
|
|
xa;ya;xr;yr;
|
|
if (ms_last_event.event_type & 0x2 && id>=0)
|
|
{
|
|
unwire_proc();
|
|
wire_ask_gamename(id);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
T_CLK_MAP clk_save[]=
|
|
{
|
|
{-1,SAVE_SLOT_S,SCREEN_OFFLINE,SAVE_SLOT_E,350,clk_save_proc,3,H_MS_DEFAULT},
|
|
{-1,59+274,14+SCREEN_OFFLINE,306+274,46+SCREEN_OFFLINE,updown_scroll,2,H_MS_ZARE},
|
|
{1,59+274,310+SCREEN_OFFLINE,306+274,332+SCREEN_OFFLINE,updown_scroll,2,H_MS_ZARE},
|
|
{-1,54,378,497,479,start_invetory,2+8,-1},
|
|
{-1,337,0,357,14,go_map,2,H_MS_DEFAULT},
|
|
{-1,291,0,313,14,go_book,2,H_MS_DEFAULT},
|
|
{-1,87,0,142,14,game_setup,2,H_MS_DEFAULT},
|
|
{-1,30,0,85,14,konec,2,H_MS_DEFAULT},
|
|
{0,207,0,265,14,clk_saveload,2,H_MS_DEFAULT},
|
|
{-1,267,0,289,15,clk_sleep,2,H_MS_DEFAULT},
|
|
{-1,0,0,639,479,close_saveload,9,H_MS_DEFAULT},
|
|
};
|
|
|
|
static void select_slot(int i) {
|
|
int rel = i-current_slot_list_top_line;
|
|
while (rel < 0) {
|
|
--current_slot_list_top_line;
|
|
schovej_mysku();
|
|
redraw_load();
|
|
showview(0,0,0,0);
|
|
ukaz_mysku();
|
|
rel++;
|
|
}
|
|
while (rel > SLOTS_MAX-1) {
|
|
++current_slot_list_top_line;
|
|
schovej_mysku();
|
|
redraw_load();
|
|
showview(0,0,0,0);
|
|
ukaz_mysku();
|
|
rel--;
|
|
}
|
|
if (last_select != i) {
|
|
if (last_select != -1) place_name(0,last_select-current_slot_list_top_line,1,0);
|
|
place_name(0,i-current_slot_list_top_line,1,1);
|
|
last_select = i;
|
|
if (last_select != -1 && last_select < (int)current_game_slot_list.count) {
|
|
read_story(current_game_slot_list.files[last_select]);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void saveload_keyboard(EVENT_MSG *msg,void **_)
|
|
{
|
|
if (msg->msg == E_KEYBOARD)
|
|
{
|
|
int v = quit_request_as_escape(va_arg(msg->data, int));
|
|
switch (v>>8)
|
|
{
|
|
case 1:unwire_proc();wire_proc();break;
|
|
case 'H':if (last_select>0) select_slot(last_select-1);break;
|
|
case 'P':if (last_select<(int)current_game_slot_list.count-1) select_slot(last_select+1);break;
|
|
case 28:if (last_select>=0) load_save_pos_ingame(last_select);break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void saveload_keyboard_menu(EVENT_MSG *msg,void **_)
|
|
{
|
|
if (msg->msg == E_KEYBOARD)
|
|
{
|
|
int v = quit_request_as_escape(va_arg(msg->data, int));
|
|
switch (v>>8)
|
|
{
|
|
case 1:send_message(E_CLOSE_MAP,NULL);break;
|
|
case 'H':if (last_select>0) select_slot(last_select-1);break;
|
|
case 'P':if (last_select<(int)current_game_slot_list.count-1) select_slot(last_select+1);break;
|
|
case 28:if (last_select>= 0 && last_select < (int)current_game_slot_list.count) {
|
|
send_message(E_CLOSE_MAP, current_game_slot_list.files[last_select]);
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
void unwire_save_load(void)
|
|
{
|
|
term_task_wait(clk_ask_name[0].id);
|
|
if (back_texture!=NULL) free(back_texture);
|
|
back_texture=NULL;
|
|
if (story_text!=NULL)release_list(story_text);
|
|
story_text=NULL;
|
|
cancel_pass=0;
|
|
send_message(E_DONE,E_KEYBOARD,saveload_keyboard);
|
|
send_message(E_DONE,E_KEYBOARD,saveload_keyboard_menu);
|
|
free_savegame_list(¤t_game_slot_list);
|
|
}
|
|
|
|
void wire_save_load(char save) {
|
|
if (save == 1) {
|
|
//TODO save
|
|
} else {
|
|
schovej_mysku();
|
|
mute_all_tracks(0);
|
|
current_game_slot_list = get_all_savegames(current_campaign);
|
|
|
|
curcolor = 0;
|
|
bar32(0, 17, 639, 17 + 360);
|
|
if (force_save)
|
|
redraw_save();
|
|
else
|
|
redraw_load();
|
|
if (save == 4)
|
|
effect_show(NULL);
|
|
else
|
|
showview(0, 0, 0, 0);
|
|
redraw_story_bar(cur_story_pos);
|
|
unwire_proc = unwire_save_load;
|
|
if (save == 1)
|
|
change_click_map(clk_save, CLK_SAVELOAD);
|
|
else if (save == 2)
|
|
change_click_map(clk_load_error, CLK_LOAD_ERROR);
|
|
else if (save == 4) {
|
|
change_click_map(clk_load_menu, CLK_LOAD_MENU);
|
|
send_message(E_ADD, E_KEYBOARD, saveload_keyboard_menu);
|
|
}
|
|
else {
|
|
send_message(E_ADD, E_KEYBOARD, saveload_keyboard);
|
|
change_click_map(clk_load, CLK_SAVELOAD);
|
|
}
|
|
cancel_pass = 1;
|
|
if (last_select != -1) {
|
|
int x = last_select * SLOT_SPACE + 1;
|
|
last_select = -1;
|
|
bright_slot(x);
|
|
}
|
|
ukaz_mysku();
|
|
update_mysky();
|
|
}
|
|
}
|
|
|
|
|
|
void open_story_file()
|
|
{
|
|
|
|
story=temp_storage_append(STORY_BOOK);
|
|
SEND_LOG("(STORY) Story temp file is opened....");
|
|
}
|
|
|
|
|
|
void write_story_text(char *text)
|
|
{
|
|
int l = strlen(text);
|
|
temp_storage_write( text, l, story);
|
|
temp_storage_write("\n", 1, story);
|
|
}
|
|
|
|
void close_story_file()
|
|
{
|
|
if (story!=NULL) temp_storage_close_wr(story);
|
|
story=NULL;
|
|
SEND_LOG("(STORY) Story temp file is closed...");
|
|
}
|
|
|
|
static int load_map_state_partial(char *level_fname,int mapsize) //obnovuje stav mapy; castecne
|
|
{
|
|
char *bf = NULL;
|
|
TMPFILE_RD *fsta;
|
|
int i;
|
|
int32_t siz;
|
|
short res=-2;
|
|
unsigned char ver;
|
|
|
|
|
|
fsta=temp_storage_open(level_fname);
|
|
if (fsta==NULL) return -1;
|
|
if (!temp_storage_read(&ver,sizeof(ver)*1,fsta)) goto err;
|
|
if (ver>STATE_CUR_VER) goto err;
|
|
if (!temp_storage_read(&i,sizeof(mapsize)*1,fsta)) goto err;
|
|
if (mapsize!=i) goto err;
|
|
SEND_LOG("(SAVELOAD) Partial restore for map: %s (%s)",level_fname,"START");
|
|
temp_storage_read(&siz,1*sizeof(siz),fsta);
|
|
bf=(char *)getmem(siz);
|
|
if (!temp_storage_read(bf,siz*1,fsta)) goto err;
|
|
for (i=0;i<mapsize;i++)
|
|
map_coord[i].flags|=(bf[i>>3]>>(i & 7)) & 1;
|
|
load_map_description(fsta);
|
|
while (temp_storage_read(&i,1*2,fsta) && i<=mapsize*4)
|
|
if (temp_storage_read(map_sides+i,1*sizeof(TSTENA),fsta)!=sizeof(TSTENA)) goto err;
|
|
while (temp_storage_read(&i,1*2,fsta) && i<=mapsize)
|
|
if (temp_storage_read(map_sectors+i,1*sizeof(TSECTOR),fsta)!=sizeof(TSECTOR)) goto err;
|
|
res=0;
|
|
err:
|
|
free(bf);
|
|
temp_storage_close_rd(fsta);
|
|
SEND_LOG("(SAVELOAD) Partial restore for map: %s (%s)",level_fname,"DONE");
|
|
return res;
|
|
}
|
|
|
|
|
|
int load_map_automap(char *mapfile)
|
|
{
|
|
int i;
|
|
|
|
SEND_LOG("(SAVEGAME) CRITICAL SECTION - Swapping maps: %s <-> %s",level_fname,mapfile);
|
|
kill_all_sounds();
|
|
for(i=0;i<mapsize;i++) map_coord[i].flags&=~0x7f; //vynuluj flags_info
|
|
free(map_sides); //uvolni informace o stenach
|
|
free(map_sectors); //uvolni informace o sektorech
|
|
free(map_coord); //uvolni minfo informace
|
|
load_org_map(mapfile,&map_sides,&map_sectors,&map_coord,&mapsize); //nahrej originalni mapu
|
|
return load_map_state_partial(mapfile,mapsize); //nahrej ulozenou mapu
|
|
}
|
|
|
|
static void herni_cas_for_savegame(char *c) {
|
|
int32_t inmin = game_time/6;
|
|
if (inmin >= 96*60) {
|
|
int32_t inhours = inmin/60;
|
|
sprintf(c,"%dd %dh", inhours/24, inhours%24);
|
|
} else {
|
|
sprintf(c,"%02d:%02d", inmin/60, inmin%60);
|
|
}
|
|
}
|
|
|
|
|
|
#define DEFAULT_GAME_NAME(extra) \
|
|
char game_name[100];\
|
|
char hernicas[50];\
|
|
herni_cas_for_savegame(hernicas);\
|
|
snprintf(game_name, sizeof(game_name), "%s %s" extra, mglob.mapname, hernicas);
|
|
|
|
void do_autosave() {
|
|
DEFAULT_GAME_NAME(" (A)");
|
|
if (game_time - prev_game_time_save<360) return;
|
|
prev_game_time_save = game_time;
|
|
save_game(game_time, game_name);
|
|
|
|
}
|
|
|
|
void do_save_dialog() {
|
|
DEFAULT_GAME_NAME("");
|
|
if (ask_save_dialog(game_name, sizeof(game_name))) {
|
|
prev_game_time_save = game_time;
|
|
save_game(game_time, game_name);
|
|
}
|
|
|
|
|
|
}
|