Free Hero Mesh

Check-in [07dd5d8d17]
Login
This is a mirror of the main repository for Free Hero Mesh. New tickets and changes will not be accepted at this mirror.
Overview
Comment:Implement saving solutions.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 07dd5d8d176f3cc86e4dd274c75fa02f312a9e8c
User & Date: user on 2021-03-29 23:48:21
Other Links: manifest | tags
Context
2021-03-30
06:32
Add the maxTrigger resource, to try to prevent some kinds of infinite loops check-in: 655771dcba user: user tags: trunk
2021-03-29
23:48
Implement saving solutions. check-in: 07dd5d8d17 user: user tags: trunk
2021-03-28
20:45
Improve the README file check-in: bbc05f163c user: user tags: trunk
Changes

Modified config.doc from [ae08bc54e2] to [51ec860823].

63
64
65
66
67
68
69





70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88







89
90
91
92
93
94
95
  separated by any kind of whitespaces.

.progress
  If positive, how many steps between dots in the progress report for the
  auto testing most. If negative, number of milliseconds to sleep before
  each level is executed.






.screenFlags
  SDL flags: d = double buffer, f = full screen, h = use hardware surface,
  n = no window frame, p = hardware palette, r = allow the window to be
  resized, y = asynchronous blit, z = no parachute. Some flags might not
  work if the window manager does not support them.

.screenHeight
  Height of the window (not counting the border), in pixels. This should
  be at least 480; the default is 600.

.screenWidth
  Width of the window (not counting the border), in pixels. This should
  be at least 640; the default is 800.

.showInventory
  True means to show the inventory in the margin by default; false means
  to show the move list in the margin by default. Either way, it is
  possible to change the display at run time.








.sqlCoveringIndexScan
  Boolean controlling if SQLite will use covering index scans.

.sqlExtensions
  Names of SQLite extensions with spaces in between.

.sqlFile







>
>
>
>
>



















>
>
>
>
>
>
>







63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
  separated by any kind of whitespaces.

.progress
  If positive, how many steps between dots in the progress report for the
  auto testing most. If negative, number of milliseconds to sleep before
  each level is executed.

.saveSolutions
  If true, then solutions are saved if you solve a level in less moves
  than the currently recorded solution (or if no solution is already
  recorded). This has no effect in read-only mode.

.screenFlags
  SDL flags: d = double buffer, f = full screen, h = use hardware surface,
  n = no window frame, p = hardware palette, r = allow the window to be
  resized, y = asynchronous blit, z = no parachute. Some flags might not
  work if the window manager does not support them.

.screenHeight
  Height of the window (not counting the border), in pixels. This should
  be at least 480; the default is 600.

.screenWidth
  Width of the window (not counting the border), in pixels. This should
  be at least 640; the default is 800.

.showInventory
  True means to show the inventory in the margin by default; false means
  to show the move list in the margin by default. Either way, it is
  possible to change the display at run time.

.solutionComment
  If defined, record the specified text as the solution comment, whenever
  a solution is recorded.

.solutionTimestamp
  If true, record a timestamp with the solution.

.sqlCoveringIndexScan
  Boolean controlling if SQLite will use covering index scans.

.sqlExtensions
  Names of SQLite extensions with spaces in between.

.sqlFile

Modified game.c from [be2f426be6] to [f4202f9aed].

1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

30
31
32
33
34
35







36
37
38
39
40
41
42
#if 0
gcc ${CFLAGS:--s -O2} -c -Wno-multichar game.c `sdl-config --cflags`
exit
#endif

/*
  This program is part of Free Hero Mesh and is public domain.
*/

#include "SDL.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "sqlite3.h"
#include "smallxrm.h"
#include "heromesh.h"
#include "quarks.h"
#include "cursorshapes.h"
#include "names.h"

Uint8*replay_list;
Uint16 replay_size,replay_count,replay_pos,replay_mark;
Uint8 solution_replay=255;

static volatile Uint8 timerflag;
static int exam_scroll;
static Uint8*inputs;
static int inputs_size,inputs_count;
static Uint8 side_mode=255;


static void setup_game(void) {
  const char*v;
  optionquery[1]=Q_showInventory;
  v=xrm_get_resource(resourcedb,optionquery,optionquery,2)?:"";
  side_mode=boolxrm(v,1);







  solution_replay=0;
}

static void redraw_game(void) {
  char buf[32];
  SDL_Rect r;
  int x,y;













>
















>






>
>
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#if 0
gcc ${CFLAGS:--s -O2} -c -Wno-multichar game.c `sdl-config --cflags`
exit
#endif

/*
  This program is part of Free Hero Mesh and is public domain.
*/

#include "SDL.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "sqlite3.h"
#include "smallxrm.h"
#include "heromesh.h"
#include "quarks.h"
#include "cursorshapes.h"
#include "names.h"

Uint8*replay_list;
Uint16 replay_size,replay_count,replay_pos,replay_mark;
Uint8 solution_replay=255;

static volatile Uint8 timerflag;
static int exam_scroll;
static Uint8*inputs;
static int inputs_size,inputs_count;
static Uint8 side_mode=255;
static Uint8 should_record_solution;

static void setup_game(void) {
  const char*v;
  optionquery[1]=Q_showInventory;
  v=xrm_get_resource(resourcedb,optionquery,optionquery,2)?:"";
  side_mode=boolxrm(v,1);
  if(main_options['r']) {
    should_record_solution=0;
  } else {
    optionquery[1]=Q_saveSolutions;
    v=xrm_get_resource(resourcedb,optionquery,optionquery,2)?:"";
    should_record_solution=boolxrm(v,0);
  }
  solution_replay=0;
}

static void redraw_game(void) {
  char buf[32];
  SDL_Rect r;
  int x,y;
785
786
787
788
789
790
791












































792
793
794
795
796
797
798
      replay_list=realloc(replay_list,replay_size+=0x200);
      if(!replay_list) fatal("Allocation failed\n");
    }
    replay_list[replay_pos++]=k;
    if(replay_pos>replay_count) replay_count=replay_pos;
  }
}













































void run_game(void) {
  int i;
  SDL_Event ev;
  set_caption();
  replay_count=0;
  if(side_mode==255) setup_game();







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
      replay_list=realloc(replay_list,replay_size+=0x200);
      if(!replay_list) fatal("Allocation failed\n");
    }
    replay_list[replay_pos++]=k;
    if(replay_pos>replay_count) replay_count=replay_pos;
  }
}

static void record_solution(void) {
  const char*v;
  const char*com;
  Uint8*data;
  Uint8*p;
  long sz;
  if(solution_replay) return;
  if(data=read_lump(FIL_SOLUTION,level_id,&sz)) {
    if(sz<3 || (data[0]|(data[1]<<8))!=level_version || (data[2]&~3)) goto dontkeep;
    sz-=3;
    if(data[2]&1) sz-=strnlen(data+3,sz);
    if(data[2]&2) sz-=8;
    if(sz<=0 || sz>replay_pos) goto dontkeep;
    free(data);
    return;
    dontkeep:
    free(data);
  }
  optionquery[1]=Q_solutionComment;
  com=xrm_get_resource(resourcedb,optionquery,optionquery,2);
  if(com && !*com) com=0;
  optionquery[1]=Q_solutionTimestamp;
  v=xrm_get_resource(resourcedb,optionquery,optionquery,2)?:"";
  data=malloc(sz=replay_pos+(boolxrm(v,0)?8:0)+(com?strlen(com)+1:0)+3);
  if(!data) fatal("Allocation failed\n");
  data[0]=level_version&255;
  data[1]=level_version>>8;
  data[2]=(boolxrm(v,0)?2:0)|(com?1:0);
  p=data+3;
  if(com) {
    strcpy(p,com);
    p+=strlen(com)+1;
  }
  if(data[2]&2) {
    time_t t=time(0);
    p[0]=t>>000; p[1]=t>>010; p[2]=t>>020; p[3]=t>>030;
    p[4]=t>>040; p[5]=t>>050; p[6]=t>>060; p[7]=t>>070;
    p+=8;
  }
  memcpy(p,replay_list,replay_pos);
  write_lump(FIL_SOLUTION,level_id,sz,data);
  free(data);
}

void run_game(void) {
  int i;
  SDL_Event ev;
  set_caption();
  replay_count=0;
  if(side_mode==255) setup_game();
843
844
845
846
847
848
849

850
851
852
853
854
855
856
          return;
        }
      replay:
        if(inputs_count) {
          for(i=0;i<inputs_count && !gameover;i++) if(inputs[i]) input_move(inputs[i]);
          inputs_count=0;
          no_dead_anim=0;

        }
        redraw_game();
        timerflag=0; // ensure we have not missed a timer event
        break;
    }
  }
  quit:







>







896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
          return;
        }
      replay:
        if(inputs_count) {
          for(i=0;i<inputs_count && !gameover;i++) if(inputs[i]) input_move(inputs[i]);
          inputs_count=0;
          no_dead_anim=0;
          if(gameover==1 && should_record_solution) record_solution();
        }
        redraw_game();
        timerflag=0; // ensure we have not missed a timer event
        break;
    }
  }
  quit: