Index: class.c ================================================================== --- class.c +++ class.c @@ -645,10 +645,11 @@ if(!inpstack) fatal("Allocation failed\n"); inpstack->classfp=classfp; inpstack->linenum=linenum; inpstack->next=nxt; linenum=1; + if(main_options['S']) fatal("Cannot use {include} with level hash calculation mode\n"); if(*name=='.' || *name=='_' || *name=='-' || !*name || name[strspn(name,"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_-abcdefghijklmnopqrstuvwxyz.")]) ParseError("Improper name of include file \"%s\"\n",name); if(main_options['z']) { if(strlen(name)<9 || memcmp(name-strlen(name),".include",8)) ParseError("Include file name doesn't end with .include\n"); classfp=composite_slice(name,0)?:fopen(name,"r"); Index: commandline.doc ================================================================== --- commandline.doc +++ commandline.doc @@ -22,10 +22,15 @@ Write details of macro expansion to stdout. -O Write a solution Hamster archive with private solutions to stdout. +-S + Compute level hashes. The level hashes depend on the class definitions + and on the level itself, except for the title. It does not depend on any + other files, including other levels, nor the level number. + -T Mode for testing some internal functions of Free Hero Mesh and SDL. You probably do not need to use this mode yourself. -U Index: config.doc ================================================================== --- config.doc +++ config.doc @@ -76,10 +76,15 @@ .gamma Gamma setting. If this is set, colours are gamma corrected by the number specified here. The default setting is 1.0. +.hash + Hash algorithm to use for some features; this must be one of the numbers + for hash algorithms listed in the hash.h source file. Can be decimal, or + hexadecimal if it starts with "0x". + .imageSize The picture size to use, up to 255. If the puzzle set contains pictures of the requested size, it will use those, otherwise it will try to make the pictures it does have larger by integer scaling; if that also does not work, then it is an error. Index: edit.c ================================================================== --- edit.c +++ edit.c @@ -14,10 +14,11 @@ #include "sqlite3.h" #include "smallxrm.h" #include "heromesh.h" #include "quarks.h" #include "cursorshapes.h" +#include "hash.h" EditorRect editrect; typedef struct { Uint16 class; @@ -850,24 +851,16 @@ case TY_LEVELSTRING: fprintf(fp," %%%u",(int)v.u); break; default: fprintf(fp," ???"); break; } } -static void export_level(const char*cmd) { +static void export_level_stream(FILE*fp) { Uint32*p=playfield; int i; Uint32 n; Object*o; - FILE*fp; - if(!cmd || !*cmd) return; - fp=popen(cmd,"w"); - if(!fp) { - screen_message("Cannot open pipe"); - return; - } - fprintf(fp,"; Free Hero Mesh exported level ID=%d ORD=%d\n",level_id,level_ord); - fprint_esc(fp,'@',level_title); + if(!main_options['S']) fprint_esc(fp,'@',level_title); fprintf(fp,"C %d\nD %d %d\n",level_code,pfwidth,pfheight); again: for(i=0;i<64*64;i++) { n=p[i]; while(n!=VOIDLINK) { @@ -888,10 +881,22 @@ } } else { fprintf(fp,"W\n"); } for(i=0;i128) fatal("Hash algorithm not valid or too long: %llu (length %d)\n",alg,hn); + // Class hash + if(main_options['z']) { + in=composite_slice(".class",1); + } else { + v=sqlite3_mprintf("%s.class",basefilename); + if(!v) fatal("Allocation failed\n"); + in=fopen(v,"r"); + sqlite3_free(v); + } + if(!in) fatal("Cannot open class file\n"); + out=hash_stream(alg,0,h1); + if(!out) fatal("Allocation failed\n"); + while((c=fgetc(in))!=EOF) { + if(c=='\t') c=' '; + if(c!='\r') fputc(c,out); + } + fclose(in); + fclose(out); + printf("-1 0 %llx ",alg); + hexout(h1,hn); + putchar('\n'); + for(n=0;n