#include <platform.h>
#include <bios.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <malloc.h>
#include <mem.h>
#include <pcx.h>
#include <types.h>
#include <bgraph.h>
#include <event.h>
#include <strlite.h>
#include <devices.h>
#include <bmouse.h>
#include <memman.h>
#include <fcntl.h>
#include <zvuk.h>
#include <stdarg.h>
#include "globals.h"
#include "temp_storage.h"

#include <assert.h>
#include <sys/stat.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 34
#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;
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[12];
  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;
  char *c;

	c=find_map_path(filename);
	f=fopen_icase(c,"rb");free(c);
  if (f==NULL) return -1;
  do
     {
     r=load_section(f,&temp,&sect,&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;

  for(i=0;i<mapsize*4;i++) if (map_items[i]!=NULL) free(map_items[i]);
  memset(map_items,0,mapsize*16);
  while(temp_storage_read(&i,sizeof(i),f) && i!=-1)
     {
     temp_storage_read(&j,sizeof(j),f);
     map_items[i]=(short *)getmem(j*2);
     temp_storage_read(map_items[i],2*j,f);
     }
  }

extern TSTR_LIST texty_v_mape;

void save_map_description(TMPFILE_WR *f)
  {
  int count,max;
  int 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)
     {
     int 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)
  {
  int count;
  int 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);
     }
  return 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(&macro_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=get_snd_effect(SND_GFX);
  s.music_vol=get_snd_effect(SND_MUSIC);
  s.xbass=get_snd_effect(SND_XBASS);
  s.bass=get_snd_effect(SND_BASS);
  s.treble=get_snd_effect(SND_TREBL);
  s.stereing=get_snd_effect(SND_LSWAP);
  s.swapchans=get_snd_effect(SND_SWAP);
  s.out_filter=get_snd_effect(SND_OUTFILTER);
  s.autosave=autosave_enabled;
	s.game_flags=(enable_glmap!=0);
  strncpy(s.level_name,level_fname,12);
  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 || strncmp(s.level_name,level_fname,12))
     {
     strncpy(loadlevel.name,s.level_name,12);
     loadlevel.start_pos=viewsector;
     loadlevel.dir=viewdir;
     send_message(E_CLOSE_MAP);
     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 void MakeSaveGameDir(const char *name)
{
  char *p=(char *)alloca(strlen(name)+1);
  strcpy(p,name);
  p[strlen(p)-1]=0;
  mkdir(p,0666);
}

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 slotnum,char *gamename)
  {
  char *sn,*ssn,*gn;
  FILE *svf;
  int r;

  SEND_LOG("(SAVELOAD) Saving game slot %d",slotnum);
  save_map_state();
  concat(sn,pathtable[SR_SAVES],_SLOT_SAV);
  MakeSaveGameDir(pathtable[SR_SAVES]);
  ssn=alloca(strlen(sn)+3);
  sprintf(ssn,sn,slotnum);
  gn=alloca(SAVE_NAME_SIZE);
  strncpy(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(ssn,"wb");
  if (svf==NULL)
  {
	char buff[256];
	sprintf(buff,"Nelze ulozit pozici na cestu: %s", ssn);
    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(int slotnum)
  {
  char *sn,*ssn;
  FILE *svf;
  int r,t;

  SEND_LOG("(SAVELOAD) Loading game slot %d",slotnum);
  if (battle) konec_kola();
  battle=0;
  close_story_file();
  purge_temps(0);
  concat(sn,pathtable[SR_SAVES],_SLOT_SAV);
  ssn=alloca(strlen(sn)+3);
  sprintf(ssn,sn,slotnum);
  svf=fopen_icase(ssn,"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 (stricmp(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;
    }

}

static void load_specific_file(int slot_num,char *filename,void **out,int32_t *size) //call it in task!
  {
  FILE *slot;
  char *c,*d;

  concat(c,pathtable[SR_SAVES],_SLOT_SAV);
  d=alloca(strlen(c)+2);
  sprintf(d,c,slot_num);
  slot=fopen_icase(d,"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);
  }

//------------------------ SAVE LOAD DIALOG ----------------------------
static char force_save;
static TSTR_LIST slot_list=NULL;
static int last_select=-1;
static char used_pos[SLOTS_MAX];
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 SELECT_COLOR RGB555(31,31,31)
#define NORMAL_COLOR RGB555(10,31,10)
#define STORY_X 57
#define STORY_Y 50
#define STORY_XS (298-57)
#define STORY_YS (302-50)

void read_slot_list()
  {
  int i;
  char *mask,*name;
  char slotname[SAVE_NAME_SIZE];
  if (slot_list==NULL) slot_list=create_list(SLOTS_MAX);
  concat(mask,pathtable[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);
     }
  }

static void place_name(int c,int i,char show)
  {
  int z,x;
  if (c) x=SAVE_SLOT_S;else x=LOAD_SLOT_S;
  if (show) schovej_mysku();
  position(x,z=i*SLOT_SPACE+21+SCREEN_OFFLINE);outtext(slot_list[i]);
  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));
  set_font(H_FBOLD,NORMAL_COLOR);
  for(i=0;i<SLOTS_MAX;i++) place_name(1,i,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));
  set_font(H_FBOLD,NORMAL_COLOR);
  for(i=0;i<SLOTS_MAX;i++) place_name(0,i,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 && *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 (*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 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 int bright_slot(int yr)
  {
  int id;

  id=yr/SLOT_SPACE;
  if ((yr % SLOT_SPACE)<18 && yr>0)
     {
     if (id!=last_select)
     {
     set_font(H_FBOLD,NORMAL_COLOR);
     if (last_select!=-1) place_name(force_save,last_select,1);
     set_font(H_FBOLD,SELECT_COLOR);
     place_name(force_save,id,1);
     last_select=id;
     read_story(id);
     }
     }
  else
     id=-1;
  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,-1);
  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 && used_pos[id])
     send_message(E_CLOSE_MAP,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 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 && used_pos[id])
     {
     if (load_game(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;
        }
     }
  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);
  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 saveload_keyboard(EVENT_MSG *msg,void **_)
  {
  if (msg->msg == E_KEYBOARD)
     {
      int v = va_arg(msg->data, int);
     switch (v>>8)
        {
        case 1:unwire_proc();wire_proc();break;
        case 'H':if (last_select>0) bright_slot((last_select-1)*SLOT_SPACE+1);break;
        case 'P':if (last_select<SLOTS_MAX-1) bright_slot((last_select+1)*SLOT_SPACE+1);break;
        case 28:ms_last_event.event_type|=0x2;
                if (force_save) clk_save_proc(0,0,0,0,last_select*SLOT_SPACE+1+18);
                else if (load_mode==4)
                  clk_load_proc_menu(0,0,0,0,last_select*SLOT_SPACE+1+18);
                else
                  clk_load_proc(0,0,0,0,last_select*SLOT_SPACE+1+18);
                break;
        }
     }
  }

void unwire_save_load()
  {
  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);
  }

void wire_save_load(char save)
  {
  schovej_mysku();
  mute_all_tracks(0);
  force_save=save & 1;
  load_mode=save;
  if (slot_list==NULL) read_slot_list();
  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;
  send_message(E_ADD,E_KEYBOARD,saveload_keyboard);
  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);
  else 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
  }
//po teto akci se nesmi spustit TM_SCENE!!!! pokud mapfile!=level_fname
