diff --git a/game/CMakeLists.txt b/game/CMakeLists.txt index 8283f0b..ec4e460 100644 --- a/game/CMakeLists.txt +++ b/game/CMakeLists.txt @@ -32,6 +32,7 @@ setup.c chargen.c sndandmus.c specproc.c +console.c advconfig.c temp_storage.cpp ${CMAKE_BINARY_DIR}/default_font.cpp diff --git a/game/automap.c b/game/automap.c index d14a325..a399ec7 100644 --- a/game/automap.c +++ b/game/automap.c @@ -859,10 +859,23 @@ T_CLK_MAP clk_kniha[]= }; +static void kniha_keyboard_proc(EVENT_MSG *msg, void **) { + if (msg->msg == E_KEYBOARD) { + int c = quit_request_as_escape(va_arg(msg->data,int)); + switch(c>>8) { + case 1: exit_kniha(1, 0, 0, 0, 0);break; + case 0x4d: page_change(2, 0, 0, 0, 0);break; + case 0x4b: page_change(-2, 0, 0, 0, 0);break; + default:break; + } + } +} + void unwire_kniha(void) { hold_timer(TM_FAST_TIMER,0); GlobEvent(MAGLOB_AFTERBOOK,viewsector,viewdir); + send_message(E_DONE,E_KEYBOARD, kniha_keyboard_proc); } @@ -882,6 +895,7 @@ void wire_kniha(void) schovej_mysku(); put_picture(0,0,ablock(H_KNIHA)); change_click_map(clk_kniha,CLK_KNIHA); + send_message(E_ADD,E_KEYBOARD, kniha_keyboard_proc); unwire_proc=unwire_kniha; set_font(H_FONT6,AUTOMAP_FONT_COLOR); write_book(cur_page); diff --git a/game/builder.c b/game/builder.c index 07576ed..72d5136 100644 --- a/game/builder.c +++ b/game/builder.c @@ -603,6 +603,7 @@ void other_draw() show_money(); anim_sipky(0,-1); draw_fx(); + draw_console_window(); int32_t scr_linelen2 = GetScreenPitch(); memset(GetScreenAdr()+(SCREEN_OFFLINE-1)*scr_linelen2,0,1280); diff --git a/game/clk_map.c b/game/clk_map.c index 5671000..165fb21 100644 --- a/game/clk_map.c +++ b/game/clk_map.c @@ -456,6 +456,7 @@ T_CLK_MAP clk_main_view[]= {H_SIPKY_J,560,446,598,474,clk_step,2,H_MS_DEFAULT}, {H_SIPKY_SV,599,387,628,418,clk_step,2,H_MS_DEFAULT}, {H_SIPKY_V,605,420,632,454,clk_step,2,H_MS_DEFAULT}, + {-1,565,408,593,447,clk_enter,2,H_MS_DEFAULT}, {MS_GAME_WIN,0,17,639,377,clk_fly_cursor,8,-1}, {1,320,303,639,376,pick_item_,2,-1},//344 {0,0,303,320,376,pick_item_,2,-1},//344 diff --git a/game/console.c b/game/console.c new file mode 100644 index 0000000..c6cf5f4 --- /dev/null +++ b/game/console.c @@ -0,0 +1,593 @@ +#include +#include +#include "globals.h" + +#include +#define console_max_characters 120 +#define console_max_lines 16 + + +/****/ + + +static void wzprintf(const char *text,...); +static void wzputs(const char *text); + +char *side_flags[]= + { + "AUTOMAP", + "!PLR", + "!MONST", + "!THING", + "!SOUND", + "ALARM", + "PASS", + "TRANSPARENT", + "P_ANIM", + "P_VIS", + "P_PING", + "P_FORW", + "S_ANIM", + "S_VIS", + "S_PING", + "S_FORW", + "LEFT_A", + "RIGHT_A", + "ALT_SIDES", + "SPEC", + "COPY", + "SEND", + "APLY2ND", + "AUTOANIM", + "", + "", + "", + "", + "", + "SECRET", + "TRUESEE", + "INVIS" + }; + +char *obl_flags[]= + { + "RECESS", + "UP_SIDE", + "DOWN_SIDE", + "ITPUSH" + }; + +char *mc_flags[]= + { + "MAPPED", + "FLY_OBJECT", + "PLAYER", + "DEAD_PLAYER", + "SPECTXTR", + "SAFEPLACE", + "UNUSED", + "MARKED!", + "SHADED", + "STAIRS", + "DOWN", + "!AUTOMAP", + "!SUMMON" + }; + +void mman_scan(int ) + { + } + +void show_flags(int number,char **flags,char nums) + { + int i=0; + while (nums--) + { + if (number & 1) wzprintf("%s ",flags[i]); + i++; + number>>=1; + } + } + +void spell_group_invis() + { + int i; + char ok=1; + + for(i=0;ijidlo/MAX_HLAD(human_selected); + mv=(float)human_selected->voda/MAX_ZIZEN(human_selected); + human_selected=h; + h->exp=level_map[level-2]; + check_player_new_level(h); + if (auto_advance) + { + int vlssuma=h->vlastnosti[VLS_SILA]+ + h->vlastnosti[VLS_OBRAT]+ + h->vlastnosti[VLS_POHYB]+ + h->vlastnosti[VLS_SMAGIE]; + int b,i; + + for(i=0;i<4;i++) + { + b=h->vlastnosti[i]*h->bonus/vlssuma; + h->bonus-=b;vlssuma-=h->vlastnosti[i]; + while (b--) advance_vls(i); + } + prepocitat_postavu(human_selected); + } + human_selected->jidlo=(int)(mh*MAX_HLAD(human_selected)); + human_selected->voda=(int)(mv*MAX_ZIZEN(human_selected)); + wzprintf("%s ziskal%s uroven cislo %d\r\n",h->jmeno,h->female?"a":"",level); + } + + +extern char folow_mode; +extern char folow_mob; +void macro_drop_item(); + +static char take_money() + { + int i; + if (!wzscanf("Kolik: (0 - zrusit):","%d",&i)) return 0; + money+=i; + if (i) + { + SEND_LOG("(WIZARD) Take Money %d, total %d",i,money); + } + return (i!=0); + } + +#define ALL "ALL" +static char purge_map() + { + char buffer[200]; + char *c; + + STOP(); +/* struct find_t rc; + int rs; + + concat(c,pathtable[SR_TEMP],"*.TMP"); + rs=_dos_findfirst(c,_A_NORMAL,&rc); + while (rs==0) + { + if (rc.name[0]!='~') wzputs(rc.name); + rs=_dos_findnext(&rc); + } + _dos_findclose(&rc);*/ + wzprintf("\r\n Zadej jmeno tempu (all - vse):");gets(buffer); + if (buffer[0]==0) return 0; + strupr(buffer); + concat(c,pathtable[SR_TEMP],buffer); + if (strcmp(buffer,ALL) && check_file_exists_ex(c)) + { + wzputs("Soubor nenalezen!"); + return 0; + } + SEND_LOG("(WIZARD) Purge Map: '%s'",buffer,0); + if (!strcmp(buffer,ALL)) purge_temps(0); + else remove(c); + return 1; + } + +static char heal_meditate(void) + { + int a,b,i; + THUMAN *p; + + if (!wzscanf("Obnovit postavu c: (0 - vsechny, -1 - zrusit):","%d",&b)) return 0; + if (b==-1) return 0; + if (b) a=b-1;else a=0,b=POCET_POSTAV; + p=postavy+a; + for(i=a;iused && p->lives) + { + p->lives=p->vlastnosti[VLS_MAXHIT]; + p->mana=p->vlastnosti[VLS_MAXMANA]; + p->kondice=p->vlastnosti[VLS_KONDIC]; + p->jidlo=MAX_HLAD(p); + p->voda=MAX_ZIZEN(p); + SEND_LOG("(WIZARD) Restoring character '%s'",p->jmeno,0); + bott_draw(1); + } + return 1; + } + +static char raise_death(void) + { + int b; + THUMAN *p; + char *c,*d; + + if (!wzscanf("Obzivit postavu c: (0 a -1 - zrusit):","%d",&b)) return 0; + b--; + if (b<0) return 0; + p=postavy+b; + p->lives=p->vlastnosti[VLS_MAXHIT]; + p->mana=p->vlastnosti[VLS_MAXMANA]; + p->kondice=p->vlastnosti[VLS_KONDIC]; + c="(WIZARD) '%s' has been returned to game by gods power!";d=strchr(c,'\''); + wzprintf(d,p->jmeno);putchar('\r\n'); + bott_draw(1); + return 0; + } + +/* + static char raise_killed_monster(HWND hDlg) + { + HWND listdlg=PrepareListWindow(hDlg); + HWND list=GetDlgItem(listdlg,IDC_LIST); + char buff[256]; + int i; + int res; + + for (i=0;ibonus_zbrani[i],h->weapon_expy[i]); + if (!wzscanf(" ","%[^\n]",buff)) return 0; + if (buff[0]==0) return 0; + if (sscanf(buff,"%d %d",&bonus,&value)!=2) wzputs("Huh?!"); + else + { + bonus--; + if (bonus<0 || bonus>=TPW_MAX) wzputs("Spatna zbran"); + else + if (value<0 || value>=10) wzputs("Spatna hodnota"); + else + h->bonus_zbrani[bonus]=value; + } + } + while(1); + } + +static reload_mobs() + { + extern char reset_mobiles; + reset_mobiles=1; + strncpy(loadlevel.name,level_fname,12); + loadlevel.start_pos=viewsector; + loadlevel.name[12]=0; + loadlevel.dir=viewdir; + send_message(E_CLOSE_MAP); + } + +#endif + + +static char display_game_status(void) + { + short *v; + THUMAN *p; + TSTENA *s; + TSECTOR *ss; + int i,cn,astr; + + SEND_LOG("(WIZARD) Starting wizard window at Sect %d Side %d",viewsector,viewdir); + wzprintf("Sektor: %5d Smer: %d Skupina %d \r\n",viewsector,viewdir,cur_group); + for(i=0,p=postavy;iused) + wzprintf("%d.%-14s (%d) Sek:%5d Smr:%d HPReg:%d MPReg:%d VPReg:%d %04X%s\r\n",i+1,p->jmeno,p->groupnum,p->sektor,p->direction,p->vlastnosti[VLS_HPREG], + p->vlastnosti[VLS_MPREG], p->vlastnosti[VLS_VPREG], p->vlastnosti[VLS_KOUZLA], p->lives?"":"(smrt)"); + else + wzprintf("%d. (nepouzito)\r\n",i); + wzputs(""); + wzprintf("Predmet(y) v mysi: "); + v=picked_item; + if (v==NULL) wzprintf("");else while(*v) wzprintf("%d ",abs(*v++)-1); + wzputs("\r\n"); + for(i=0,cn=0,astr=0;isector_type, ss->floor,ss->ceil,ss->sector_tag,ss->side_tag,ss->action); + wzprintf(" Vychody: Sev %d Vych %d Jih %d Z�p %d\r\n",ss->step_next[0],ss->step_next[1],ss->step_next[2],ss->step_next[3]); + wzprintf(" Vlajky: %02X %02X ",ss->flags,map_coord[viewsector].flags);show_flags(map_coord[viewsector].flags,mc_flags,12); + wzputs("\r\n"); + wzprintf("Stena: Prim %d Sec %d Obl %d Anim_prim %d/%d Anim_sec %d/%d\r\n", + s->prim,s->sec,s->oblouk & 0xf,s->prim_anim>>4,s->prim_anim & 0xf,s->sec_anim>>4,s->sec_anim & 0xf); + wzprintf(" Cil akce %d Smer akce %d Akce %d\r\n",s->action,s->sector_tag,s->side_tag & 0x3); + wzprintf(" Multiakce: %s\r\n",macros[viewsector*4+viewdir].action_list==NULL?"":"Existuje"); + wzprintf(" Vlajky: %04X %02X %02X ",s->flags,s->oblouk>>4,s->side_tag>>2); + wzputs(""); + show_flags(s->flags,side_flags,32); + show_flags(s->oblouk>>4,obl_flags,4); + return 0; + } + +/*****/ + +void unaffect(); +extern char immortality; +extern char nohassle; + + +static char console_input_line[console_max_characters+1] = ""; +static char *console_output_lines[console_max_lines] = {}; + +static const int console_x = 0; +static const int console_y = 20; +static const int console_width = 640; +static const int console_height = 160; +static const int console_padding = 3; +static int console_blink = 0; +static char console_visible = 0; + + +void draw_console_window() { + if (!console_visible) return; + trans_bar(console_x, console_y, console_width, console_height, 0); + + set_font(H_FLITT5, RGB888(255,255,128)); + int y = console_y+console_height-text_height("X")-console_padding; + position(console_x+console_padding, y); + outtext("$ "); + outtext(console_input_line); + if ((console_blink>>1) & 1) { + outtext("_"); + } + ++console_blink; + + set_font(H_FLITT5, RGB888(255,255,255)); + + + y-=3*text_height("X")/2; + + for (int i = 0; i < console_max_lines;++i) { + position(console_x+console_padding,y); + if (console_output_lines[i]) outtext(console_output_lines[i]); + y-=text_height("X"); + if (y < console_y+console_padding) break; + } +} + +char console_is_visible() { + return console_visible; +} + +static void console_add_line(const char *line) { + free(console_output_lines[console_max_lines-1]); + memmove(console_output_lines+1,console_output_lines, (console_max_lines-1)*sizeof(char *)); + console_output_lines[0] = strdup(line); +} + +typedef struct { + char *cmd_buffer; + const char *command; + const char *args; +} PARSED_COMMAND; + +static PARSED_COMMAND parse_command(const char *cmd) { + PARSED_COMMAND ret; + ret.command = 0; + ret.args = 0; + ret.cmd_buffer = strdup(cmd); + char *c =ret.cmd_buffer; + while (*c && isspace(*c)) ++c; + if (!*c) return ret; + ret.command = c; + ret.args = NULL; + char *sep = strrchr(c, ' '); + if (sep!= NULL) { + *sep = 0; + ++sep; + while (*sep && isspace(*sep)) ++sep; + if (*sep) { + ret.args = sep; + char *end = strrchr(sep,0); + end--; + while (end > sep && isspace(*end)) end--; + end++; + *end = 0; + } + + } + return ret; +} + +static int process_on_off_command(const char *cmd, char on) { + if (stricmp(cmd, "inner-eye") == 0) { + show_debug = on; + return 1; + } + if (stricmp(cmd, "hunter-instinct") == 0) { + show_lives = on; + return 1; + } + if (stricmp(cmd, "no-hassle") == 0) { + nohassle=on; + return 1; + } + if (stricmp(cmd, "iron-skin") == 0) { + immortality=on; + return 1; + } + if (stricmp(cmd, "spirit-wander") == 0) { + cur_group=on?10:postavy[0].groupnum; + return 1; + } + return 0; +} + +static int process_actions(const char *command) { + if (stricmp(command, "flute") == 0) { + bott_draw_fletna(); + return 1; + } + if (stricmp(command, "global-map") == 0) { + wire_global_map(); + return 1; + } + if (stricmp(command, "status") == 0) { + display_game_status(); + return 1; + } + return 0; +} + +static int process_command(PARSED_COMMAND cmd) { + int onoff = -1; + if (cmd.args) { + if (stricmp(cmd.args, "on") == 0) onoff = 1; + else if (stricmp(cmd.args, "off") == 0) onoff = 0; + } else { + return process_actions(cmd.command); + } + if (onoff != -1) { + return process_on_off_command(cmd.command, onoff); + } + return 0; +} + +static void console_keyboard(EVENT_MSG *msg, void **) { + if (msg->msg == E_KEYBOARD) { + int c = va_arg(msg->data, int) & 0xFF; + if (c == E_QUIT_GAME_KEY) return; + if (c) { + int len = strlen(console_input_line); + if (c == 0x1B) { + console_show(0); + msg->msg = -1; + return; + } + if (c == '\b') { + if (len) { + console_input_line[len-1] = 0; + } + msg->msg = -1; + } else if (c == '\r') { + PARSED_COMMAND cmd = parse_command(console_input_line); + char ok = process_command(cmd); + if (ok) { + console_add_line(console_input_line); + console_input_line[0] = 0; + } + free(cmd.cmd_buffer); + msg->msg = -1; + } else if (c >=32 && len < console_max_characters) { + console_input_line[len] = c; + console_input_line[len+1] = 0; + msg->msg = -1; + } + } + } +} + + +static void wire_console(void) { + send_message(E_ADD,E_KEYBOARD, console_keyboard); +} + + +static void unwire_console(void) { + send_message(E_DONE,E_KEYBOARD, console_keyboard); +} + +void console_show(char show) { + if (console_visible != show) { + console_visible = show; + if (show) wire_console(); + else unwire_console(); + } + +} + +static void wzprintf(const char *text,...) + { + char buff[console_max_characters+1]; + static char wzprint_line[console_max_characters+1]; + va_list lst; + va_start(lst, text); + vsnprintf(buff,console_max_characters, text, lst); + char *c = buff; + char *d = strchr(c, '\n'); + while (d != NULL) { + *d = 0; + strncat(wzprint_line,c, console_max_characters); + console_add_line(wzprint_line); + c = d+1; + d = strchr(c, '\n'); + wzprint_line[0] = 0; + } + strncat(wzprint_line, c, console_max_characters); + + } + + +static void wzputs(const char *text) + { + console_add_line(text); + } + + + + + diff --git a/game/dialogy.c b/game/dialogy.c index 6a698eb..04a0140 100644 --- a/game/dialogy.c +++ b/game/dialogy.c @@ -134,7 +134,7 @@ void small_anm_buff(void *target,const void *buff,const void *paleta); void small_anm_delta(void *target,const void *buff,const void *paleta); //#pragma aux small_anm_delta parm[edi][esi][ebx] modify [eax ecx] -static void animace_kouzla(int act,const void *data,int csize) +static void animace_kouzla(MGIF_HEADER_T *_,int act,const void *data,int csize) { word *p=GetScreenAdr()+loc_anim_render_buffer; switch (act) @@ -169,7 +169,8 @@ static void dialog_anim(va_list args) do { anm=open_mgif(aptr); - while (anm!=NULL && task_quitmsg()) + char f = anm != NULL; + while (f && task_quitmsg()) { task_sleep(); if (!spdc) @@ -179,7 +180,7 @@ static void dialog_anim(va_list args) hid=1;schovej_mysku(); } else hid=0; - anm=mgif_play(anm); + f=mgif_play(anm); spdc=speed; if (hid) ukaz_mysku(); showview(PIC_X,PIC_Y,320,180); @@ -191,7 +192,7 @@ static void dialog_anim(va_list args) } } rep--; - close_mgif(); + close_mgif(anm); } while (!cntr && rep && !task_quitmsg()); free(aptr); diff --git a/game/gamesave.c b/game/gamesave.c index fb28d59..5cdd72e 100644 --- a/game/gamesave.c +++ b/game/gamesave.c @@ -1013,7 +1013,7 @@ static void read_story_task(va_list args) { int xs,ys; d=c; - while (size && *d!='\r' && *d!='\n') {d++;size--;}; + while (size>0 && *d!='\r' && *d!='\n') {d++;size--;}; if (!size) break; *d=0; { @@ -1027,7 +1027,7 @@ static void read_story_task(va_list args) e=strchr(e,0)+1; } c=d+1;size--; - if (*c=='\n' || *c=='\r') {c++;size--;}; + if (size > 0 &&(*c=='\n' || *c=='\r')) {c++;size--;}; free(or); } } diff --git a/game/globals.h b/game/globals.h index 43489ea..ee48bea 100644 --- a/game/globals.h +++ b/game/globals.h @@ -1724,7 +1724,7 @@ int count_pages(void); void save_book(void); void load_book(void); void prekodovat(char *c); - +char clk_enter(int id,int xa,int ya,int xr,int yr); //menu int enter_menu(char open); //task! @@ -1787,5 +1787,9 @@ static __inline int quit_request_as_escape(int c) { if (c == E_QUIT_GAME_KEY) return 0x011B;else return c; } +void draw_console_window(void); +void console_show(char show); +char console_is_visible(void); + //extras #include "extras.h" diff --git a/game/globmap.c b/game/globmap.c index 67d79e5..417ae0a 100644 --- a/game/globmap.c +++ b/game/globmap.c @@ -22,14 +22,15 @@ #include #define GLOBMAP "GLOBMAP.DAT" -#define ODDELOVACE ";:=,\n{}" +#define ODDELOVACE ";:=,\n\r{}" #define OD_COMMAND oddelovace[0] #define OD_CRIT oddelovace[1] #define OD_SET oddelovace[2] #define OD_COMMA oddelovace[3] #define OD_NEWLINE oddelovace[4] -#define OD_IN oddelovace[5] -#define OD_OUT oddelovace[6] +#define OD_CR oddelovace[5] +#define OD_IN oddelovace[6] +#define OD_OUT oddelovace[7] #define OD_COMMENT '`' #define INDEXU 256 @@ -247,7 +248,7 @@ static char test_kriterii(void) break; default: { - hodn=temp_storage_find(text); + hodn=temp_storage_find(text)>=0; /* char c[200]; sprintf(c,"%s.TMP",text); hodn=!check_file_exists(c);*/ @@ -269,11 +270,11 @@ static char proved_prikaz() char op; ODD=cti_oddelovac(); - while (ODD==OD_NEWLINE) ODD=cti_oddelovac(); //preskoc prazdne radky + while (ODD==OD_NEWLINE || ODD==OD_CR) ODD=cti_oddelovac(); //preskoc prazdne radky if (ODD==OD_IN) return 0; //cti znak { do { - while (ODD==OD_NEWLINE || ODD==OD_COMMAND) ODD=cti_oddelovac(); + while (ODD==OD_NEWLINE || ODD==OD_CR || ODD==OD_COMMAND) ODD=cti_oddelovac(); if (ODD!=0) error("O�ek�v� se jm�no definice (p��klad: INDX=)"); cti_retezec(20,prikaz,1,1); op=get_symbol(prikaz); @@ -335,9 +336,9 @@ static char proved_prikaz() default:error(prikaz); } ODD=cti_oddelovac(); - if (ODD!=OD_COMMAND && ODD!=OD_NEWLINE && ODD!=EOF) ex_error(OD_COMMAND); + if (ODD!=OD_COMMAND && ODD!=OD_NEWLINE && ODD!=OD_CR && ODD!=EOF) ex_error(OD_COMMAND); } - while (ODD!=OD_NEWLINE && ODD!=EOF); + while (ODD!=OD_NEWLINE && ODD !=OD_CR && ODD!=EOF); return 0; } diff --git a/game/interfac.c b/game/interfac.c index 75370e4..6e517f1 100644 --- a/game/interfac.c +++ b/game/interfac.c @@ -1360,6 +1360,7 @@ TMPFILE_RD *enc_open(const char *filename) encdata[i] = last; } temp_storage_store("__enc_temp", encdata, size); + free(encdata); return temp_storage_open("__enc_temp"); } diff --git a/game/inv.c b/game/inv.c index ba29949..c10c488 100644 --- a/game/inv.c +++ b/game/inv.c @@ -65,7 +65,6 @@ TSHOP **shop_list=NULL; int max_shops=0; //shop_list=prima spojeni s obchody void *shop_hacek=NULL; //hacek za ktery visi cely shop strom (free(shop_hacek) - odalokuje shopy) //hacek lze ulozit do savegame -> ulozi se cely stav obchodu -int32_t shop_hacek_size=0; //toto je jeho delka static TSHOP_ALL_STATE shop_all_state; #define ico_extract(icnnum) (((char*)ablock(ikon_libs+(icnnum)/IT_LIB_SIZE))+IT_ICONE_SIZE*((icnnum)%IT_LIB_SIZE)) @@ -207,6 +206,7 @@ void load_items() hs=hl_ptr; prepare_graphics(&hl_ptr,(char *)p,size,wav_load,SR_ZVUKY); sound_handle=hs-1; + free(p); break; default: free(p); @@ -853,12 +853,17 @@ char exit_inv(int id,int xa,int ya,int xr,int yr) void definuj_postavy() { int i,num1,r,inv=0,z; - const char *c,*end; + char *c,*end; + const char *tmpptr; char cc; int tmp; - c=ablock(H_POSTAVY_DAT); - end=c+get_handle(H_POSTAVY_DAT)->size; + tmpptr=ablock(H_POSTAVY_DAT); + size_t sz = get_handle(H_POSTAVY_DAT)->size; + c = alloca(sz+1); + memcpy(c, tmpptr, sz); + c[sz] = 0; + end=c + sz; for(i=0;citems==NULL) it=glob_items+p->item-1;else it=&glob_items[*(p->items)-1]; - if (p->flags & FLY_DESTROY_SEQ) smr=3; + if (p->flags & FLY_DESTROY_SEQ) { + smr=3; + } else if (smr==3) smr=1; picnum=it->v_letu[(smr<<2)+p->anim_pos]; if (!picnum) @@ -2445,9 +2452,7 @@ static void rebuild_shops(const void *shop_ptr) int i; SEND_LOG("(SHOP) Rebuilding shops...."); - if (shop_list!=NULL) free(shop_list); max_shops = *(const int32_t *)c; - shop_list=NewArr(TSHOP *,max_shops); c+=4; const char *d = c; size_t reqsize = 0; @@ -2499,8 +2504,10 @@ void load_shops(void) shop_list=NULL; return; } + int32_t shop_hacek_size=0; //toto je jeho delka const void *sh=afile(SHOP_NAME,SR_MAP,&shop_hacek_size); rebuild_shops(sh); + ablock_free(sh); } static int32_t *get_product_count(const TPRODUCT *p) { diff --git a/game/kouzla.c b/game/kouzla.c index de1491a..f59ce6d 100644 --- a/game/kouzla.c +++ b/game/kouzla.c @@ -173,7 +173,7 @@ void call_spell(int i); int calculatePhaseDoor(int sector, int dir, int um); -static void animace_kouzla(int act,const void *data, int ssize) +static void animace_kouzla(MGIF_HEADER_T *_,int act,const void *data, int ssize) { switch (act) { @@ -236,16 +236,17 @@ static void play_anim(va_list args) //tasked animation anm=open_mgif(ablock(block)); c=0; SEND_LOG("(ANIM) Buffer is now ready..."); - while (anm!=NULL) + char f = 1; + while (f) { task_wait_event(E_KOUZLO_ANM); c++; SEND_LOG("(ANIM) Rendering frame %d in animation %xh",c,block); - anm=mgif_play(anm); + f=mgif_play(anm); neco_v_pohybu=1; } task_wait_event(E_KOUZLO_ANM); - close_mgif(); + close_mgif(anm); running_anm=0; free(anim_render_buffer); diff --git a/game/realgame.c b/game/realgame.c index e38d11c..f1a0d9e 100644 --- a/game/realgame.c +++ b/game/realgame.c @@ -1575,8 +1575,7 @@ void step_zoom(char smer) sort_groups(); bott_draw(0); other_draw(); - shift_zoom(smer); - if (smer==0 && nopass) shift_zoom(smer+2); + if (!nopass) shift_zoom(smer); if (battle || (game_extras & EX_ALWAYS_MINIMAP)) draw_medium_map(); sort_groups(); bott_draw(0); @@ -1858,6 +1857,10 @@ void *game_keyboard(EVENT_MSG *msg,void **usr) {unwire_proc();cancel_render=1;wire_save_load(1);}break; case '=':unwire_proc();cancel_render=1;wire_save_load(0);break; case '>':game_setup(0,0,0,0,0);break; + case 0x2E: if (get_control_key_state() && get_shift_key_state()) { + console_show(!console_is_visible()); + } + break; CASE_KEY_1_6:c=group_sort[c-2]; if (postavy[c].sektor==viewsector && postavy[c].used) add_to_group(c); diff --git a/game/skeldal.c b/game/skeldal.c index 967b70b..960bda5 100644 --- a/game/skeldal.c +++ b/game/skeldal.c @@ -474,7 +474,7 @@ void set_font(int font,int c1,...) if (c1 & BGSWITCHBIT) { charcolors[0]=0xFFFF; - for (i=1;i<5;i++) charcolors[i]=c1 & ~0x20; + for (i=1;i<5;i++) charcolors[i]=c1 & ~BGSWITCHBIT; } else if (c1 & FONT_TSHADOW) { if ((c1 & FONT_TSHADOW_GRAY) == FONT_TSHADOW_GRAY) @@ -998,6 +998,7 @@ void unwire_main_functs(void) delete_from_timer(TM_REGEN); send_message(E_DONE,E_KEYBOARD,game_keyboard); send_message(E_DONE,E_KROK,real_krok); + console_show(0); disable_click_map(); cancel_render=1; wire_proc=wire_main_functs; @@ -1439,6 +1440,16 @@ static void load_saved_game(void) } } +static int any_save_callback(const char *c, LIST_FILE_TYPE _, size_t __, void *___) { + return 1; +} + +static char any_save() { + int c = list_files(gpathtable[SR_SAVES],file_type_normal,any_save_callback,0); + return c; +} + + static void start(va_list args) { int volba; @@ -1448,7 +1459,7 @@ static void start(va_list args) openning=0; update_mysky(); schovej_mysku(); - if (!skip_intro) + if (!any_save()) { show_jrc_logo("LOGO.PCX"); play_anim(7); diff --git a/game/sndandmus.c b/game/sndandmus.c index fa6046e..c32cd94 100644 --- a/game/sndandmus.c +++ b/game/sndandmus.c @@ -384,6 +384,7 @@ static void build_dungeon_sound_map(int sector, int side) { if (mapsize != (int)current_sound_sector_map_size) { free(current_sound_sector_map); current_sound_sector_map = NewArr(TSOUND_SIDE_MAP, mapsize); + memset(current_sound_sector_map,0,sizeof(TSOUND_SIDE_MAP)*mapsize); current_sound_sector_map_size = mapsize; } int32_t counter = ++current_sound_sector_map_counter; diff --git a/game/souboje.c b/game/souboje.c index 8b46d91..e260c52 100644 --- a/game/souboje.c +++ b/game/souboje.c @@ -1947,6 +1947,10 @@ void programming_keyboard(EVENT_MSG *msg,void **unused) wire_inv_mode(human_selected); break; case 82:group_all();break; + case 0x2E: if (get_control_key_state() && get_shift_key_state()) { + console_show(!console_is_visible()); + } + break; CASE_KEY_1_6:c=group_sort[c-2]; if (postavy[c].used) { diff --git a/game/wizard.c b/game/wizard.c index a2ba00c..185549e 100644 --- a/game/wizard.c +++ b/game/wizard.c @@ -450,6 +450,8 @@ void wizard_kbd(EVENT_MSG *msg,void **usr) return; } +c + void install_wizard() { send_message(E_ADD,E_KEYBOARD,wizard_kbd); diff --git a/libs/bgraph.h b/libs/bgraph.h index 3a9a09e..aded251 100644 --- a/libs/bgraph.h +++ b/libs/bgraph.h @@ -1,3 +1,4 @@ +#include #include "types.h" diff --git a/libs/bgraph2a.c b/libs/bgraph2a.c index 0a2089e..1b8b849 100644 --- a/libs/bgraph2a.c +++ b/libs/bgraph2a.c @@ -153,7 +153,7 @@ chr5: ax = charcolors[(al-1)]; if (ax == 0xFFFF) goto chr4; if (ax & BGSWITCHBIT) { - ax = avg_pixels(*ebx ,ax); + ax = avg_pixels(*ebx ,ax) & ~BGSWITCHBIT; } *ebx = ax; goto chr4; diff --git a/libs/gui.c b/libs/gui.c index 9875c59..d84d837 100644 --- a/libs/gui.c +++ b/libs/gui.c @@ -352,7 +352,12 @@ void define(int id,int x,int y,int xs,int ys,char align,void (*initproc)(OBJREC o->font=default_font; o->datasize=0; initproc(o); - if (o->datasize) o->data=(void *)getmem(o->datasize); else o->data=NULL; + if (o->datasize) { + o->data=(void *)getmem(o->datasize); + memset(o->data,0,o->datasize); + }else { + o->data=NULL; + } va_list vlst; va_start(vlst, initproc); o->call_init(o,vlst); diff --git a/libs/mgifmapmem.c b/libs/mgifmapmem.c index f3df66e..5e367ed 100644 --- a/libs/mgifmapmem.c +++ b/libs/mgifmapmem.c @@ -7,10 +7,8 @@ #include "mgifmem.h" #include -static MGIF_HEADER_T *mgif_header; -static short mgif_accnums[2]; -static int32_t mgif_writepos; + static const word *paleta; @@ -128,34 +126,31 @@ static void PlayMGFFile(const void *file, MGIF_PROC proc,int ypos,char full) int32_t scr_linelen2 = GetScreenPitch(); mgif_install_proc(proc); sound=PrepareVideoSound(22050,256*1024); - mgif_accnums[0]=mgif_accnums[1]=0; - mgif_writepos=65536; picture=getmem(2*3+320*180*2); picture[0]=320; picture[1]=180; picture[2]=15; memset(picture+3,0,320*180*2); anim_render_buffer=picture+3; - mgif_header=(MGIF_HEADER_T *)file; file=open_mgif(file); if (file==NULL) return; - while (file) + MGIF_HEADER_T *hdr =(MGIF_HEADER_T *)file; + hdr->accnums[0] = hdr->accnums[1] = 0; + hdr->sound_write_pos = 65536; + char f = 1; + while (f) { - file=mgif_play(file); + f=mgif_play(file); StretchImageHQ(picture, GetScreenAdr()+ypos*scr_linelen2, scr_linelen2,full); showview(0,ypos,0,360); if (game_display_is_quit_requested()) { break; - } else if (_bios_keybrd(_KEYBRD_READY)==0) { - mix_back_sound(0); - } - else - { + } else if (_bios_keybrd(_KEYBRD_READY)) { _bios_keybrd(_KEYBRD_READ); break; } } - close_mgif(); + close_mgif(file); DoneVideoSound(sound); free(picture); } @@ -169,7 +164,7 @@ void show_full_lfb12e_dx(void *target,void *buff,void *paleta); -void BigPlayProc(int act,const void *data,int csize) +void BigPlayProc(MGIF_HEADER_T *hdr,int act,const void *data,int csize) { switch (act) { @@ -178,7 +173,7 @@ void BigPlayProc(int act,const void *data,int csize) case MGIF_DELTA:show_delta_lfb12e(anim_render_buffer,data,paleta);break; case MGIF_PAL:paleta=data;break; case MGIF_SOUND: - while (LoadNextVideoFrame(sound,data,csize,mgif_header->ampl_table,mgif_accnums,&mgif_writepos)==0); + while (LoadNextVideoFrame(sound,data,csize,hdr->ampl_table,hdr->accnums,&hdr->sound_write_pos)==0); } } diff --git a/libs/mgifmem.c b/libs/mgifmem.c index 8cdc82d..096faac 100644 --- a/libs/mgifmem.c +++ b/libs/mgifmem.c @@ -10,8 +10,6 @@ #define LZW_BUFFER 64000 MGIF_PROC show_proc; -static int mgif_frames; -static int cur_frame; typedef struct double_s @@ -93,21 +91,29 @@ struct mgif_header load_mgif_header(const char **mgif) { const void *open_mgif(const void *mgif) //vraci ukazatel na prvni frame { const char *c = mgif; - struct mgif_header mgh = load_mgif_header(&c); + MGIF_HEADER_T hdr = load_mgif_header(&c); - if (strncmp(mgh.sign,MGIF,4)) return NULL; - mgif_frames=mgh.frames; - cur_frame=0; + if (strncmp(hdr.sign,MGIF,4)) return NULL; + MGIF_HEADER_T *ins = getmem(sizeof(MGIF_HEADER_T)); + *ins = hdr; + ins->nx_frame = c; + ins->cur_frame = 0; + ins->sound_write_pos = 0; + ins->accnums[0] = 0; + ins->accnums[1] = 0; init_lzw_compressor(8); if (lzw_buffer==NULL) lzw_buffer=getmem(LZW_BUFFER); - return c; + return ins; } -void close_mgif(void) //dealokuje buffery pro prehravani +void close_mgif(const void *mgif) //dealokuje buffery pro prehravani { - done_lzw_compressor(); - free(lzw_buffer); - lzw_buffer=NULL; + if (mgif) { + done_lzw_compressor(); + free(lzw_buffer); + lzw_buffer=NULL; + free((void *)mgif); + } } @@ -350,8 +356,9 @@ FRAME_HEADER_T read_frame_header(const char **iter) { return ret; } -const void *mgif_play(const void *mgif) //dekoduje a zobrazi frame +char mgif_play(const void *mgif) //dekoduje a zobrazi frame { + MGIF_HEADER_T *hdr = (MGIF_HEADER_T *)mgif; const char *pf; const char *pc; char *ff; @@ -361,7 +368,7 @@ const void *mgif_play(const void *mgif) //dekoduje a zobrazi frame - pf=mgif; + pf=hdr->nx_frame; FRAME_HEADER_T frame_hdr = read_frame_header(&pf); pc = pf; pf += frame_hdr.size; @@ -378,14 +385,15 @@ const void *mgif_play(const void *mgif) //dekoduje a zobrazi frame scr_sav = pc; scr_act = chunk_hdr.type; } else { - show_proc(chunk_hdr.type,pc,chunk_hdr.size); + show_proc(hdr,chunk_hdr.type,pc,chunk_hdr.size); } pc+=chunk_hdr.size; } - if (scr_act!=-1) show_proc(scr_act,scr_sav,0); - cur_frame+=1; - if (cur_frame==mgif_frames) return NULL; - return pf; + if (scr_act!=-1) show_proc(hdr, scr_act,scr_sav,0); + hdr->cur_frame+=1; + if (hdr->cur_frame==hdr->frames) return 0; + hdr->nx_frame = pf; + return 1; } /* acts=*pf++; diff --git a/libs/mgifmem.h b/libs/mgifmem.h index 0f3b5dd..9a5dc2b 100644 --- a/libs/mgifmem.h +++ b/libs/mgifmem.h @@ -1,7 +1,7 @@ //!!!! POZOR, NUTNE LINKOVAT SOUBOR LZWA.ASM #ifndef _MGIFMEM_H -typedef void (*MGIF_PROC)(int,const void *,int csize); //prvni cislo akce, druhy data akce + #define _MGIFMEM_H #define MGIF "MGIF" @@ -29,12 +29,17 @@ typedef struct mgif_header word snd_chans; int32_t snd_freq; short ampl_table[256]; - short reserved[32]; + const void *nx_frame; + int32_t cur_frame; + short accnums[2]; + int32_t sound_write_pos; }MGIF_HEADER_T; + typedef void (*MGIF_PROC)(MGIF_HEADER_T *hdr, int,const void *,int csize); //prvni cislo akce, druhy data akce + void mgif_install_proc(MGIF_PROC proc); const void *open_mgif(const void *mgif); //vraci ukazatel na prvni frame -const void *mgif_play(const void *mgif); //dekoduje a zobrazi frame -void close_mgif(void); //dealokuje buffery pro prehravani +char mgif_play(const void *mgif); //dekoduje a zobrazi frame +void close_mgif(const void *mgif); //dealokuje buffery pro prehravani #endif diff --git a/platform/file_access.cpp b/platform/file_access.cpp index a154efd..7cbfebd 100644 --- a/platform/file_access.cpp +++ b/platform/file_access.cpp @@ -103,3 +103,26 @@ char change_current_directory(const char *path) { std::filesystem::current_path(std::filesystem::path(path), ec); return ec == std::error_code{}?1:0; } + +int list_files(const char *directory, int type, LIST_FILES_CALLBACK cb, void *ctx) { + std::error_code ec; + std::filesystem::directory_iterator iter(std::string(directory), ec); + if (ec == std::error_code{}) { + while (iter != std::filesystem::directory_iterator()) { + int r = 0; + const auto &entry = *iter; + if (entry.is_regular_file(ec) && (type & file_type_normal)) { + r = cb(entry.path().c_str(), file_type_normal, entry.file_size(ec), ctx); + } else if (entry.is_directory(ec)) { + int dot = entry.path().filename() == "." || entry.path().filename() == ".."; + if (!dot && (type & file_type_directory)) { + r = cb(entry.path().c_str(), file_type_directory, 0, ctx); + } else if (dot & (type & file_type_dot)) { + r = cb(entry.path().c_str(), file_type_dot, 0, ctx); + } + } + if (r) return r; + } + } + return 0; +} diff --git a/platform/platform.h b/platform/platform.h index bc676ef..4d92b3d 100644 --- a/platform/platform.h +++ b/platform/platform.h @@ -79,6 +79,16 @@ int get_timer_value(void); uint32_t get_game_tick_count(void); void sleep_ms(uint32_t); +typedef enum { + file_type_normal = 1, + file_type_directory = 2, + file_type_dot = 4 +} LIST_FILE_TYPE; + +typedef int (*LIST_FILES_CALLBACK)(const char *, LIST_FILE_TYPE , size_t, void *); +int list_files(const char *directory, int type, LIST_FILES_CALLBACK cb, void *ctx); + + #ifdef __cplusplus } #endif diff --git a/platform/sdl/sound.cpp b/platform/sdl/sound.cpp index 9b65ba8..7f00de7 100644 --- a/platform/sdl/sound.cpp +++ b/platform/sdl/sound.cpp @@ -134,12 +134,14 @@ void fade_music() { size_t wrsamples = music_buffer_write_pos / sizeof(WaveSource::StereoInt16); size_t l =music_source->length(); float_t size = (rdpos < wrsamples?0:l) + wrsamples - rdpos; - for (size_t i = 0; i < size; ++i) { - float fact = (size - i)/size; - rdptr[rdpos].left = rdptr[rdpos].left * fact; - rdptr[rdpos].right = rdptr[rdpos].right * fact; - ++rdpos; - if (rdpos >=l) rdpos = 0; + if (l) { + for (size_t i = 0; i < size; ++i) { + float fact = (size - i)/size; + rdptr[rdpos].left = rdptr[rdpos].left * fact; + rdptr[rdpos].right = rdptr[rdpos].right * fact; + ++rdpos; + if (rdpos >=l) rdpos = 0; + } } } @@ -161,21 +163,21 @@ static void stop_music() { music_source.reset(); } -void create_new_music_track(int freq) { +void create_new_music_track(int freq, int buffsize) { stop_music(); static int track_id = music_track_id_base; double basef = base_freq; double rel_speed = freq/basef; - music_buffer = new uint8_t[BACK_BUFF_SIZE]; - std::memset(music_buffer, 0, BACK_BUFF_SIZE); + music_buffer = new uint8_t[buffsize]; + std::memset(music_buffer, 0, buffsize); music_source = std::make_shared( WaveSource::WavePtr(music_buffer,music_buffer_deleter), WaveSource::Format::stereo_int16, rel_speed, - BACK_BUFF_SIZE/sizeof(WaveSource::StereoInt16),0); + buffsize/sizeof(WaveSource::StereoInt16),0); - sound_mixer.set_track(track_id, WaveMixer<2>(music_source,{music_volume,music_volume},1.0)); + sound_mixer.set_track(track_id, WaveMixer<2>(music_source,{music_volume*master_volume,music_volume*master_volume},1.0)); track_id = track_id ^ 1; - music_buffer_write_pos = BACK_BUFF_SIZE/2; + music_buffer_write_pos = buffsize/2; } static std::unique_ptr load_music_ex(const char *name) { @@ -203,7 +205,7 @@ static void handle_end_of_song() { current_music = load_music_ex(new_music); if (current_music) { auto nfo = current_music->get_info(); - create_new_music_track(nfo.freq); + create_new_music_track(nfo.freq, BACK_BUFF_SIZE); mix_back_sound(0); } } @@ -242,7 +244,7 @@ void change_music(const char *filename) { current_music = load_music_ex(filename); if (current_music) { auto nfo = current_music->get_info(); - create_new_music_track(nfo.freq); + create_new_music_track(nfo.freq, BACK_BUFF_SIZE); mix_back_sound(0); } } @@ -317,15 +319,31 @@ int get_snd_effect(AUDIO_PROPERTY funct) { } void *PrepareVideoSound(int mixfreq, int buffsize) { + create_new_music_track(mixfreq, buffsize); return 0; } char LoadNextVideoFrame(void *buffer, const char *data, int size, const short *xlat, short *accnums, int32_t *writepos) { - std::this_thread::sleep_for(std::chrono::milliseconds(20)); + std::size_t rdpos = music_source->get_output_position_bytes(); + std::size_t wrpos = *writepos; + auto l = music_source->length_bytes(); + auto space = (rdpos < wrpos?l:0) + rdpos - wrpos; + if (space < static_cast(size)*2) { + sound_mixer.wait_for_advance_write_pos(); + return 0; + } + short *wave = reinterpret_cast(music_buffer); + auto w = wrpos/2; + auto ls = l /2; + for (int i = 0; i < size; ++i) { + auto acc = accnums+(i & 1); + *acc = wave[(w+i) % ls] = xlat[static_cast(data[i])]+*acc; + } + music_buffer_write_pos = *writepos = (wrpos + size*2)%l; return 1; } void DoneVideoSound(void *buffer) { - + //empty } const char *device_name(int ) diff --git a/platform/sdl/sound_mixer.h b/platform/sdl/sound_mixer.h index 8245f6c..1045e4a 100644 --- a/platform/sdl/sound_mixer.h +++ b/platform/sdl/sound_mixer.h @@ -22,6 +22,13 @@ public: --i; } } + ++_calls; + _calls.notify_all(); + } + + void wait_for_advance_write_pos() { + auto v = _calls.load(); + _calls.wait(v); } template &> Fn> @@ -99,6 +106,7 @@ protected: std::mutex _mx; std::vector _tracks; + std::atomic _calls = {0}; }; diff --git a/platform/sdl/wave_source.h b/platform/sdl/wave_source.h index 92c1bde..96b0b3f 100644 --- a/platform/sdl/wave_source.h +++ b/platform/sdl/wave_source.h @@ -58,6 +58,7 @@ public: */ std::size_t get_output_position_samples() const { std::lock_guard _(_mx); + if (_position == 0) return _length-1; //assume loop return static_cast(std::round(wrap_pos(_position - 1.0))); } @@ -229,7 +230,7 @@ protected: double wrap_pos(double position) const { if (position >= _length) { if (_loop_pos == _length) { - position = _length; + position = _length-1; } else { position = std::fmod((position - _length),(_length - _loop_pos)) + _loop_pos; }