Index: bindings.doc ================================================================== --- bindings.doc +++ bindings.doc @@ -107,10 +107,13 @@ and the title is set to "New Level". '^S' Save level. +'^T' + Edit the level title. + '^a' Add an object with the current MRU values to that location, if there is not already another object of the same class there. '^c' Index: default.heromeshrc ================================================================== --- default.heromeshrc +++ default.heromeshrc @@ -143,10 +143,11 @@ ?.editKey.R: select 're',substr(:resize,1,instr(:resize,'x')-1),substr(:resize,instr(:resize,'x')+1) where length(:resize); ?.editKey.ctrl.N: ^N ?.editKey.ctrl.P: ^P ?.editKey.ctrl.Q: ^Q ?.editKey.ctrl.S: ^S +?.editKey.ctrl.T: ^T ?.editKey.ctrl.X: select 're',pfwidth(),pfheight(); ?.editKey.space: ^c ?.editKey.return: ^e ?.editKey.f1: select 'im',:Import_Level; ?.editKey.f2: select 'ex',:Export_Level; Index: edit.c ================================================================== --- edit.c +++ edit.c @@ -971,11 +971,11 @@ break; case '%': if(nlevelstrings>0x2000) { screen_message("Too many level strings"); } else { - levelstrings=realloc(levelstrings,(nlevelstrings+1)*sizeof(char*)); + levelstrings=realloc(levelstrings,(nlevelstrings+1)*sizeof(unsigned char*)); if(!levelstrings) fatal("Allocation failed\n"); levelstrings[nlevelstrings++]=import_string(p+1); } break; default: @@ -1015,10 +1015,256 @@ level_title=strdup("New Level"); if(!level_title) fatal("Allocation failed\n"); level_changed=level_version=level_code=0; level_ord=level_nindex+1; } + +static int cursor_end(const Uint8*s) { + int i=0; + for(;;) { + if(*s==10 || !*s) return i; + if(*s==31 && s[1]) s++; + i++; + s++; + } +} + +static inline Uint8 pick_character(void) { + SDL_Rect r; + SDL_Event ev; + Uint8 buf[17]; + int i,j; + Uint8 p=0; + redraw: + r.x=r.y=4; + r.w=r.h=0x9C; + SDL_FillRect(screen,&r,0xF8); + SDL_LockSurface(screen); + draw_text(24,8,"0123456789ABCDEF",0xF8,0xF3); + buf[16]=0; + for(i=0;i<16;i++) { + snprintf(buf,2,"%X",i); + draw_text(8,(i+3)<<3,buf,0xF8,0xF3); + for(j=0;j<16;j++) buf[j]=(i<<4)|j?:255; + draw_text(24,(i+3)<<3,buf,0xF8,0xFF); + } + buf[0]=p?:255; + buf[1]=0; + i=p>>4; + j=p&15; + draw_text((j+3)<<3,(i+3)<<3,buf,0xF2,0xFE); + SDL_UnlockSurface(screen); + SDL_Flip(screen); + while(SDL_WaitEvent(&ev)) { + switch(ev.type) { + case SDL_QUIT: + SDL_PushEvent(&ev); + return; + case SDL_KEYDOWN: + switch(ev.key.keysym.sym) { + case SDLK_RETURN: case SDLK_SPACE: case SDLK_KP_ENTER: return p?:255; + case SDLK_KP2: if(ev.key.keysym.mod&KMOD_NUM) goto norm; //fallthrough + case SDLK_DOWN: p+=16; break; + case SDLK_KP4: if(ev.key.keysym.mod&KMOD_NUM) goto norm; //fallthrough + case SDLK_LEFT: p--; break; + case SDLK_KP6: if(ev.key.keysym.mod&KMOD_NUM) goto norm; //fallthrough + case SDLK_RIGHT: p++; break; + case SDLK_KP8: if(ev.key.keysym.mod&KMOD_NUM) goto norm; //fallthrough + case SDLK_UP: p-=16; break; + default: norm: + i=ev.key.keysym.unicode; + if(i>='0' && i<='9') p=(p<<4)|(i-'0'); + if(i>='A' && i<='F') p=(p<<4)|(i+10-'A'); + if(i>='a' && i<='f') p=(p<<4)|(i+10-'a'); + if(i==13 || i==10) return p?:255; + } + goto redraw; + case SDL_VIDEOEXPOSE: + goto redraw; + } + } +} + +static void edit_string(unsigned char**ps) { + SDL_Rect rect; + SDL_Event ev; + char buf[19]; + Uint8*s=malloc(0x3000); + Uint8*cp; + Uint16 li[64]; + int c,e,i,j,n,r,sz; + char o=0; + char d=0; + if(!s) fatal("Allocation failed\n"); + if(*ps) strncpy(s,*ps,0x2FFD); else *s=0; + s[0x2FFD]=0; + *li=0; + c=r=0; + redraw: + e=0; + redraw2: + set_cursor(XC_xterm); + rect.x=rect.y=0; + rect.w=screen->w; + rect.h=screen->h; + SDL_FillRect(screen,&rect,0xF0); + rect.h=24; + SDL_FillRect(screen,&rect,0xF1); + SDL_LockSurface(screen); + if(ps==&level_title) { + draw_text(0,16," Title: ",0xF9,0xFF); + } else { + snprintf(buf,19," String %d: ",(int)(ps-levelstrings)); + draw_text(0,16,buf,0xF9,0xFF); + } + draw_text(160,16,o?"OVR":"INS",0xF1,0xFE); + draw_text(0,0," Cancel Preview Save <\x18\x19\x1A\x1B> MoveCursor <^P> InsertChar <^Y> DelLine",0xF1,0xFB); + draw_text(0,8,"ALT+ <0-7> Color Bar Center Image Left Quiz",0xF1,0xFB); + draw_text(0,24,"\x10",0xF0,0xF1); + cp=0; + for(i=j=n=0;s[i] && n<63;) { + draw_text(0,(n+3)<<3,"\x10",0xF0,0xF1); + i+=draw_text_line(8,(n+3)<<3,s+i,r==n?c:-1,&cp); + if(j=(s[i]==10)) i++; + sz=li[++n]=i; + } + if(!i) { + sz=li[n=1]=r=c=0; + cp=s; + draw_text(8,24,"\xFE",0xFF,0xFE); + } else if(j && n<63) { + draw_text(0,(n+3)<<3,"\x10",0xF0,0xF1); + draw_text(8,(n+3)<<3,"\xFE",r==n?0xFF:0xF0,r==n?0xFE:0xF1); + if(r==n) cp=s+i,c=0; + li[++n]=i; + } + if(r && r>=n) r--,e=0; + if(n<63) li[n+1]=0xFFFF; + SDL_UnlockSurface(screen); + if(!cp) { + if(e) fatal("Confusion in edit_string\n"); + c=cursor_end(s+li[r]); + e=1; + goto redraw2; + } + if(d) { + d=0; + goto del; + } + snprintf(buf,19,"%d,%d / %d [%d]",r+1,c,n,sz); + draw_text(200,16,buf,0xF1,0xFA); + SDL_Flip(screen); + while(SDL_WaitEvent(&ev)) { + switch(ev.type) { + case SDL_QUIT: + SDL_PushEvent(&ev); + return; + case SDL_KEYDOWN: + switch(ev.key.keysym.sym) { + case SDLK_ESCAPE: return; + case SDLK_F1: modal_draw_popup(s); break; + case SDLK_F2: + free(*ps); + *ps=s; + return; + case SDLK_KP0: if(ev.key.keysym.mod&KMOD_NUM) goto norm; //fallthrough + case SDLK_INSERT: ins: o^=1; break; + case SDLK_KP1: if(ev.key.keysym.mod&KMOD_NUM) goto norm; //fallthrough + case SDLK_END: end: c=cursor_end(s+li[r]); break; + case SDLK_KP2: if(ev.key.keysym.mod&KMOD_NUM) goto norm; //fallthrough + case SDLK_DOWN: down: if(r<63 && li[r+1]!=0xFFFF) ++r; break; + case SDLK_KP4: if(ev.key.keysym.mod&KMOD_NUM) goto norm; //fallthrough + case SDLK_LEFT: left: if(c) --c; break; + case SDLK_KP6: if(ev.key.keysym.mod&KMOD_NUM) goto norm; //fallthrough + case SDLK_RIGHT: right: ++c; break; + case SDLK_KP7: if(ev.key.keysym.mod&KMOD_NUM) goto norm; //fallthrough + case SDLK_HOME: home: c=0; break; + case SDLK_KP8: if(ev.key.keysym.mod&KMOD_NUM) goto norm; //fallthrough + case SDLK_UP: up: if(r) --r; break; + case SDLK_KP_PERIOD: if(ev.key.keysym.mod&KMOD_NUM) goto norm; //fallthrough + case SDLK_DELETE: del: + if(!*cp) break; + i=(*cp==31?2:1); + memmove(cp,cp+i,(s+sz)-(cp+i-1)); + break; + case SDLK_BACKSPACE: back: + if(cp==s || !c) break; + c--; + d=1; + break; + default: norm: + i=ev.key.keysym.unicode; + if(ev.key.keysym.mod&(KMOD_ALT|KMOD_META)) { + switch(ev.key.keysym.sym) { + case SDLK_0: i=1; goto addch; + case SDLK_1: i=2; goto addch; + case SDLK_2: i=3; goto addch; + case SDLK_3: i=4; goto addch; + case SDLK_4: i=5; goto addch; + case SDLK_5: i=6; goto addch; + case SDLK_6: i=7; goto addch; + case SDLK_7: i=8; goto addch; + case SDLK_b: i=15; goto addch; + case SDLK_c: i=12; goto addch; + case SDLK_i: i=14; goto addch; + case SDLK_l: i=11; goto addch; + case SDLK_n: i=10; goto addch; + case SDLK_q: i=16; goto addch; + } + } + if(i<32) { + switch(i+64) { + case 'A': goto home; + case 'D': goto right; + case 'E': goto up; + case 'F': goto end; + case 'G': goto del; + case 'H': goto back; + case 'M': i=10; goto addch; + case 'P': goto specialchar; + case 'S': goto left; + case 'W': r=c=0; break; + case 'X': goto down; + case 'V': goto ins; + case 'Y': goto erase; + case 'Z': r=n?n-1:0; c=0; break; + } + } else if(i<127) { + addch: + if(i==10 && n>62) break; + if(sz>=0x2FFC) break; + if(o && *cp==31) memmove(cp,cp+1,(s+sz)-cp); + if(!*cp) cp[1]=0; + if(!o) memmove(cp+1,cp,(s+sz+1)-cp); + *cp=i; + if(i==10) r++,c=0; else c++; + } + break; + } + goto redraw; + case SDL_VIDEOEXPOSE: + goto redraw; + } + } + erase: + c=0; + if(li[r+1]==0xFFFF) s[li[r]]=0; else memmove(s+li[r],s+li[r+1],sz+1-li[r+1]); + if(r && r==n-1) --r; + goto redraw; + specialchar: + if(sz>=0x2FFA) goto redraw; + i=pick_character(); + if(i>=32) goto addch; + if(o && *cp==31) memmove(cp,cp+1,(s+sz)-cp); + if(!*cp) cp[1]=0; + memmove(cp+1,cp,(s+sz+1)-cp); + if(!o) memmove(cp+1,cp,(s+sz+1)-cp); + *cp=31; + cp[1]=i; + c++; + goto redraw; +} static int editor_command(int prev,int cmd,int number,int argc,sqlite3_stmt*args,void*aux) { int x,y; switch(cmd) { case '^a': // Add object (no duplicates) @@ -1044,10 +1290,13 @@ case '^Q': // Quit return -1; case '^S': // Save level save_level(); return 1; + case '^T': // Level title + edit_string(&level_title); + return 0; case 'ex': // Export level if(argc<2) return prev; export_level(sqlite3_column_text(args,1)); return prev; case 'go': // Select level Index: exec.c ================================================================== --- exec.c +++ exec.c @@ -32,11 +32,11 @@ Uint8 generation_number_inc; Uint32 move_number; unsigned char*quiz_text; Inventory*inventory; Uint32 ninventory; -char**levelstrings; +unsigned char**levelstrings; Uint16 nlevelstrings; Value*array_data; Uint16 ndeadanim; DeadAnimation*deadanim; Uint8 no_dead_anim; @@ -72,14 +72,14 @@ static Value destroy(Uint32 from,Uint32 to,Uint32 why); static const Sint8 x_delta[8]={1,1,0,-1,-1,-1,0,1}; static const Sint8 y_delta[8]={0,-1,-1,-1,0,1,1,1}; -const char*value_string_ptr(Value v) { +const unsigned char*value_string_ptr(Value v) { switch(v.t) { case TY_STRING: return stringpool[v.u]; - case TY_LEVELSTRING: return v.u"; + case TY_LEVELSTRING: return v.u"; default: fatal("Internal confusion: Trying to get string pointer for a non-string\n"); } } void pfunlink(Uint32 n) { Index: heromesh.h ================================================================== --- heromesh.h +++ heromesh.h @@ -102,10 +102,11 @@ void draw_picture(int x,int y,Uint16 img); void draw_cell(int x,int y); // Use only when screen is locked void draw_text(int x,int y,const unsigned char*t,int bg,int fg); +int draw_text_line(int x,int y,unsigned char*t,int cur,Uint8**cp); void draw_key(int x,int y,int k,int bg,int fg); const char*screen_prompt(const char*txt); int screen_message(const char*txt); @@ -255,18 +256,18 @@ extern Uint8 generation_number_inc; extern Uint32 move_number; extern unsigned char*quiz_text; extern Inventory*inventory; extern Uint32 ninventory; -extern char**levelstrings; +extern unsigned char**levelstrings; extern Uint16 nlevelstrings; extern Value*array_data; extern Uint16 ndeadanim; extern DeadAnimation*deadanim; extern Uint8 no_dead_anim; -const char*value_string_ptr(Value v); +const unsigned char*value_string_ptr(Value v); void pfunlink(Uint32 n); void pflink(Uint32 n); Uint32 objalloc(Uint16 c); void objtrash(Uint32 n); void annihilate(void); Index: main.c ================================================================== --- main.c +++ main.c @@ -337,11 +337,11 @@ i=0; while(p=max_objects) goto bad3; q=memchr(p,0,end-p); if(!q) goto bad1; - levelstrings=realloc(levelstrings,(i+1)*sizeof(char*)); + levelstrings=realloc(levelstrings,(i+1)*sizeof(unsigned char*)); if(!levelstrings) fatal("Allocation failed\n"); levelstrings[i]=strdup(p); if(!levelstrings[i]) fatal("Allocation failed\n"); p=q+1; i++; Index: picture.c ================================================================== --- picture.c +++ picture.c @@ -133,10 +133,58 @@ t++; if(!--len) return; pix+=8; } } + +int draw_text_line(int x,int y,unsigned char*t,int cur,Uint8**cp) { + // To be called only when screen is locked! + int len=strlen(t); + const unsigned char*s=t; + Uint8*pix=screen->pixels; + Uint8*p; + Uint16 pitch=screen->pitch; + int bg,fg,xx,yy; + char isimg=0; + char e=0; + const unsigned char*f; + if(!*t) return 0; + len=(screen->w-x)>>3; + if(len<=0 || y+8>screen->h) return len<1?1:len; + pix+=y*pitch+x; + for(;;) { + if(!cur) *cp=t; + if(*t==10) { + f=fontdata+(17<<3); + bg=0xF0,fg=0xF1; + e=1; + } else if(!*t) { + f=fontdata+(254<<3); + bg=0xF0,fg=0xF1; + e=1; + } else if(*t<31) { + f=fontdata+(" 01234567?NLC#IBQ???????????????"[*t]<<3); + if(*t==14) isimg=1; + bg=0xF3,fg=0xF0; + } else { + if(*t==31 && t[1]) t++; + f=fontdata+(*t<<3); + bg=0xF0,fg=isimg?0xF2:0xF7; + } + if(!cur--) bg^=15,fg^=15; + p=pix; + for(yy=0;yy<8;yy++) { + for(xx=0;xx<8;xx++) p[xx]=(*f<pixels; Uint16 pitch=screen->pitch;