Index: TODO ================================================================== --- TODO +++ TODO @@ -63,5 +63,6 @@ * Chroma * Xsok * PuzzleScript (limited; not everything is or will be capable) * Sokoban * Puzzle Boy + * Pitman/Catrap Index: edit.c ================================================================== --- edit.c +++ edit.c @@ -26,10 +26,20 @@ } MRU; #define MRUCOUNT 32 static MRU mru[MRUCOUNT]; static int curmru; +static char*solution_data; +static int solution_length; + +static inline void discard_solution(void) { + if(solution_data) { + sqlite3_free(solution_data); + solution_data=0; + solution_length=0; + } +} static void rewrite_class_def(void) { Uint32 i,n; Uint8 cu[0x4000/8]; Uint8 mu[0x4000/8]; @@ -264,10 +274,16 @@ sqlite3_exec(userdb,"BEGIN;",0,0,0); write_lump(FIL_LEVEL,level_id,sz,data); sqlite3_free(data); if(level_ord==level_nindex+1) update_level_index(); rewrite_class_def(); + if(solution_data) { + solution_data[0]=level_version&255; + solution_data[1]=level_version>>8; + write_lump(FIL_SOLUTION,level_id,solution_length,solution_data); + discard_solution(); + } sqlite3_exec(userdb,"COMMIT;",0,0,0); } static void redraw_editor(void) { char buf[32]; @@ -973,17 +989,19 @@ Object*o; FILE*fp; size_t size=0; char*buf=0; char*p; + sqlite3_str*sol=0; Value v; if(!cmd || !*cmd) return; fp=popen(cmd,"r"); if(!fp) { screen_message("Cannot open pipe"); return; } + discard_solution(); level_changed=1; while(getline(&buf,&size,fp)>0) { p=buf; p[strcspn(p,"\r\n\f")]=0; p+=strspn(p,"\t "); @@ -1061,10 +1079,31 @@ levelstrings=realloc(levelstrings,(nlevelstrings+1)*sizeof(unsigned char*)); if(!levelstrings) fatal("Allocation failed\n"); levelstrings[nlevelstrings++]=import_string(p+1); } break; + case '\'': + if(!sol) { + sol=sqlite3_str_new(userdb); + sqlite3_str_appendchar(sol,3,0); // append level version (will be overwritten later) and flags + } + p=strchr(buf,' '); + if(p) { + *p=0; + p=import_numbers(p+1,&y,0); + if(!p || *p) goto bad; + } else { + y=1; + } + for(x=8;x<256;x++) { + if(heromesh_key_names[x] && !strcmp(buf+1,heromesh_key_names[x])) { + sqlite3_str_appendchar(sol,y,x); + break; + } + } + if(x==256) goto bad; + break; default: if(*p && *p!=';') { bad: fprintf(stderr,"Invalid record in imported data: %s\n",buf); screen_message("Invalid record"); @@ -1074,10 +1113,15 @@ } done: free(buf); pclose(fp); generation_number_inc=0; + if(sol) { + solution_length=sqlite3_str_length(sol); + solution_data=sqlite3_str_finish(sol); + if(!solution_data) fatal("Allocation failed"); + } } static void new_level(void) { sqlite3_stmt*st; int i; @@ -1092,10 +1136,11 @@ return; } i=sqlite3_column_int(st,0); sqlite3_finalize(st); if(i>0xFFFE) return; + discard_solution(); annihilate(); level_id=i; free(level_title); level_title=strdup("New Level"); if(!level_title) fatal("Allocation failed\n"); @@ -1505,10 +1550,11 @@ case '^N': // New level if(level_nindex>0xFFFE) return 0; new_level(); return 1; case '^P': // Play + discard_solution(); return -2; case '^Q': // Quit return -1; case '^S': // Save level save_level(); @@ -1552,10 +1598,11 @@ case 'ex': // Export level if(argc<2) return prev; export_level(sqlite3_column_text(args,1)); return prev; case 'go': // Select level + discard_solution(); load_level(number); return 1; case 'im': // Import level if(argc<2) return prev; import_level(sqlite3_column_text(args,1)); @@ -1569,10 +1616,11 @@ free(level_title); level_title=strdup(sqlite3_column_text(args,1)); if(!level_title) fatal("Allocation failed\n"); return 0; case 'lv': // Set level version + discard_solution(); level_version=number; level_changed=0; return 0; case 'mR': // Select MRU relative number+=curmru; @@ -1585,10 +1633,11 @@ editrect.x0=editrect.y0=editrect.x1=editrect.y1=0; x=sqlite3_column_int(args,1); y=sqlite3_column_int(args,2); if(x<1 || y<1 || x>64 || y>64) return 0; level_changed=1; + discard_solution(); annihilate(); pfwidth=x; pfheight=y; return 0; default: @@ -1599,10 +1648,11 @@ void run_editor(void) { SDL_Event ev; int i; curmru=0; set_caption(); + discard_solution(); load_level(level_id); redraw_editor(); while(SDL_WaitEvent(&ev)) { switch(ev.type) { case SDL_VIDEOEXPOSE: Index: export.doc ================================================================== --- export.doc +++ export.doc @@ -56,10 +56,19 @@ %string A level string. The level strings are numbered in order, starting from string 0. The format is like that of the title. +'key number + Specify the key name (same as the "input constants" described in + class.doc), and optionally the repeat count. This enters it into the + solution; if at least one command like this is present then it will + overwrite the existing solution when this level is saved. (Note: This + does not automatically verify the solution; it only records it.) + (Currently, this line is implemented only for import, and not for + export. Later an option might be added to do this on export, too.) + === Misc values === A number is written in decimal, and must be 0 to 65535. Index: picture.c ================================================================== --- picture.c +++ picture.c @@ -312,12 +312,17 @@ return 0; } int screen_message(const char*txt) { int n=0; - SDL_Rect r={0,0,screen->w,16}; + SDL_Rect r={0,0,0,16}; SDL_Event ev; + if(!screen) { + fprintf(stderr," * %s\n",txt); + return 0; + } + r.w=screen->w; SDL_FillRect(screen,&r,0xF4); r.y=16; r.h=1; SDL_FillRect(screen,&r,0xF8); SDL_LockSurface(screen);