From 2d7697174d40e59206489e415c3563624ffc681c Mon Sep 17 00:00:00 2001 From: Ondrej Novak Date: Tue, 11 Feb 2025 11:04:30 +0100 Subject: [PATCH] several fixes and improvements (combat log) - windows --- game/builder.c | 2 +- game/clk_map.c | 2 +- game/console.c | 33 ++++-- game/enemy.c | 35 ++++++- game/gamesave.c | 216 +++++++++++++++++++++++---------------- game/globals.h | 6 +- game/globmap.c | 2 +- game/inv.c | 7 +- game/macros.c | 4 +- game/realgame.c | 2 +- game/souboje.c | 141 +++++++++++++++++-------- libs/strlite.c | 12 +++ libs/strlite.h | 1 + platform/file_access.cpp | 13 ++- platform/platform.h | 14 ++- 15 files changed, 332 insertions(+), 158 deletions(-) diff --git a/game/builder.c b/game/builder.c index 470068d..943ccf9 100644 --- a/game/builder.c +++ b/game/builder.c @@ -1273,7 +1273,7 @@ void death_screen() { int ys; int y = 160; const char *t = texty[65]; - char buff[strlen(t)+4]; + DECL_VLA(char, buff, strlen(t)+4); set_font(H_FBOLD, RGB555_ALPHA(31,31,31)); zalamovani(t,buff, 440, &xs, &ys); t = buff; diff --git a/game/clk_map.c b/game/clk_map.c index f90ea07..f51d765 100644 --- a/game/clk_map.c +++ b/game/clk_map.c @@ -136,7 +136,7 @@ char clk_touch(int id,int xa,int ya,int xr,int yr) return 0; } -char clk_fly_cursor(int id,int xa,int ya,int xr,int yr) +static char clk_fly_cursor(int id,int xa,int ya,int xr,int yr) { id; diff --git a/game/console.c b/game/console.c index 1e14055..bc36de6 100644 --- a/game/console.c +++ b/game/console.c @@ -4,7 +4,7 @@ #include #define console_max_characters 120 -#define console_max_lines 16 +#define console_max_lines 300 void macro_drop_item(int sector,int smer,short item); /****/ @@ -371,21 +371,22 @@ extern char pass_all_mobs; static char console_input_line[console_max_characters+1] = ""; static char *console_output_lines[console_max_lines] = {}; +static int console_top_line = 0; static const int console_x = 0; -static const int console_y = 20; +static const int console_y = SCREEN_OFFLINE; static const int console_width = 640; -static const int console_height = 160; +static const int console_height = 165; static const int console_padding = 3; static int console_blink = 0; static char console_visible = 0; - +#define CONSOLE_FONT H_FTINY 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)); + set_font(CONSOLE_FONT, RGB555(31,31,16)); int y = console_y+console_height-text_height("X")-console_padding; position(console_x+console_padding, y); outtext("$ "); @@ -395,14 +396,16 @@ void draw_console_window() { } ++console_blink; - set_font(H_FLITT5, RGB888(255,255,255)); + set_font(CONSOLE_FONT, RGB555(31,31,31)); y-=3*text_height("X")/2; for (int i = 0; i < console_max_lines;++i) { + int p = i + console_top_line; + if (p>=console_max_lines) break; position(console_x+console_padding,y); - if (console_output_lines[i]) outtext(console_output_lines[i]); + if (console_output_lines[p]) outtext(console_output_lines[p]); y-=text_height("X"); if (y < console_y+console_padding) break; } @@ -416,6 +419,7 @@ 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 { @@ -755,7 +759,8 @@ static int process_command(PARSED_COMMAND cmd) { static void console_keyboard(EVENT_MSG *msg, void **_) { if (msg->msg == E_KEYBOARD) { - int c = va_arg(msg->data, int) & 0xFF; + int code = va_arg(msg->data, int); + int c = code & 0xFF; if (c == E_QUIT_GAME_KEY) return; if (c) { int len = strlen(console_input_line); @@ -774,6 +779,7 @@ static void console_keyboard(EVENT_MSG *msg, void **_) { char ok = process_command(cmd); if (ok) { console_add_line(console_input_line); + console_top_line = 0; console_input_line[0] = 0; } free(cmd.cmd_buffer); @@ -783,6 +789,17 @@ static void console_keyboard(EVENT_MSG *msg, void **_) { console_input_line[len+1] = 0; msg->msg = -1; } + } else { + switch (code >> 8) { + case 'I': console_top_line = MIN(console_max_lines-10, console_top_line+10);break; + case 'Q': console_top_line = MAX(0, console_top_line-10);break; + case 'H': console_top_line = MIN(console_max_lines-10, console_top_line+1);break; + case 'P': console_top_line = MAX(0, console_top_line-1);break; + case 'G': console_top_line = console_max_characters-10; + case 'O': console_top_line = 0; + default: return; + } + msg->msg = -1; } } } diff --git a/game/enemy.c b/game/enemy.c index 4f62963..ebc6a2e 100644 --- a/game/enemy.c +++ b/game/enemy.c @@ -1449,7 +1449,12 @@ void mob_strelba(TMOB *p) t->zmeny[VLS_MGZIVEL]=p->vlastnosti[VLS_MGZIVEL]; spell_throw(-((p-mobs)+1),i); letici_veci->flags &=~FLY_DESTROY; - letici_veci->hit_bonus=p->vlastnosti[VLS_UTOK_L]+rnd(p->vlastnosti[VLS_UTOK_H]-p->vlastnosti[VLS_UTOK_L]+1); + int att = p->vlastnosti[VLS_OBRAT]/5; + letici_veci->hit_bonus=p->vlastnosti[VLS_UTOK_L]+rnd(p->vlastnosti[VLS_UTOK_H]-p->vlastnosti[VLS_UTOK_L]+1) + att; + if (log_combat) { + wzprintf("%s shoots: %d (roll %d-%d) + %d (%s/5) = %d\n", + p->vlastnosti[VLS_UTOK_L],p->vlastnosti[VLS_UTOK_H],att,texty[13],letici_veci->hit_bonus); + } letici_veci->damage=p->vlastnosti[VLS_DAMAGE]; p->dostal=0; } @@ -1556,12 +1561,13 @@ void mobs_hit(TMOB *p) spec=vlastnosti[VLS_KOUZLA]; if (game_extras & EX_SHIELD_BLOCKING) PodporaStitu(h,vlastnosti); else uprav_podle_kondice(h,&pocet); - h->dostal=vypocet_zasahu(p->vlastnosti,vlastnosti,pocet,0,0); //vypocet zasahu + h->dostal=vypocet_zasahu(p->vlastnosti,vlastnosti,pocet,0,0,1); //vypocet zasahu if (h->dostal) p->dostal=0; if (spec & SPL_OKO) //oko za oko pro hrace { vybrana_zbran=-1; mob_hit(p,h->dostal); + if (log_combat) wzprintf("%s was hit (eye for an eye): %d\n", p->name, h->dostal); mob_check_death(p-mobs,p); } if (h->dostal && p->vlastnosti[VLS_KOUZLA] & SPL_KNOCK) knock_player_back(h,p->dir); @@ -1569,6 +1575,7 @@ void mobs_hit(TMOB *p) { p->lives+=h->dostal; if (p->lives>p->vlastnosti[VLS_MAXHIT])p->lives=p->vlastnosti[VLS_MAXHIT]; + if (log_combat) wzprintf("%s drained HP : %d, lives %d\n", p->name, h->dostal, p->lives); } dead=player_hit(h,h->dostal,1); if (h->lives>h->vlastnosti[VLS_MAXHIT]) h->lives=h->vlastnosti[VLS_MAXHIT]; @@ -2169,11 +2176,31 @@ static void knock_mob_back(TMOB *mm,int dir) recheck_button(sek,1); } -int utok_na_sektor(THUMAN *p,TMOB *mm,int ch,int bonus) + static void remove_other_weapon_from_calc(THUMAN *p, short *vlastnosti, int poz) { + int otherpoz = poz == PO_RUKA_L?PO_RUKA_R:PO_RUKA_L; + int itnum = p->wearing[otherpoz]; + if (itnum == 0) return; + const TITEM *it = glob_items + itnum-1; + if (it->druh != TYP_UTOC) return; + int vls[] = {VLS_MGSIL_H,VLS_MGSIL_L,VLS_UTOK_H,VLS_UTOK_L,VLS_DAMAGE}; + for (int i = 0; i < countof(vls); ++i) { + vlastnosti[vls[i]] -= it->zmeny[vls[i]]; + } + } + + +int utok_na_sektor(THUMAN *p,TMOB *mm,int ch,int bonus, int ruka) { int dostal; + short vlastnosti[VLS_MAX]; + const short *use_vls = p->vlastnosti; - dostal=vypocet_zasahu(p->vlastnosti,mm->vlastnosti,ch,bonus,0); + if (ruka == PO_RUKA_L || ruka == PO_RUKA_R) { + memcpy(vlastnosti, p->vlastnosti, sizeof(vlastnosti)); + remove_other_weapon_from_calc(p, vlastnosti, ruka); + use_vls = vlastnosti; + } + dostal=vypocet_zasahu(use_vls,mm->vlastnosti,ch,bonus,0,ruka != PL_OBOUR); mob_hit(mm,dostal); if (dostal && p->vlastnosti[VLS_KOUZLA] & SPL_KNOCK) knock_mob_back(mm,p->direction); if (mm->vlastnosti[VLS_KOUZLA] & SPL_OKO) //oko za oko pro potvoru diff --git a/game/gamesave.c b/game/gamesave.c index 827bc62..078a865 100644 --- a/game/gamesave.c +++ b/game/gamesave.c @@ -41,6 +41,8 @@ static TMPFILE_WR *story=NULL; static char load_another; static unsigned long current_campaign = 0; +static long prev_game_time_save = 0; + char reset_mobiles=0; typedef struct s_save @@ -749,7 +751,7 @@ static int load_global_events() return 0; } -int save_game(int game_time,char *gamename, char skip_if_exists) +int save_game(int game_time,char *gamename) { char *gn; FILE *svf; @@ -762,17 +764,13 @@ int save_game(int game_time,char *gamename, char skip_if_exists) } char str_buff[50]; - snprintf(str_buff,sizeof(str_buff),"sav.%010lx.%08X", current_campaign, game_time); + snprintf(str_buff,sizeof(str_buff),"sav.%08lx.%08X", current_campaign, game_time); SEND_LOG("(SAVELOAD) Saving game slot %d",game_time); save_map_state(); const char *sn = build_pathname(2,gpathtable[SR_SAVES],str_buff); sn = local_strdup(sn); - if (skip_if_exists && check_file_exists(sn)) { - SEND_LOG("(SAVELOAD) Save skipped - already exists"); - return 0; - } create_directories(gpathtable[SR_SAVES]); gn=alloca(SAVE_NAME_SIZE); strcopy_n(gn,gamename,SAVE_NAME_SIZE); @@ -807,7 +805,7 @@ int load_game(const char *fname) FILE *svf; int r,t; - sscanf(fname,"sav.%lx", ¤t_campaign); + sscanf(fname,"sav.%lx.%lx", ¤t_campaign, &prev_game_time_save); SEND_LOG("(SAVELOAD) Loading file: %s",fname); if (battle) konec_kola(); @@ -881,7 +879,7 @@ static char load_mode; #define SLOT_SPACE 33 #define SLOT_FONT H_FBOLD #define SELECT_COLOR RGB555(31,31,31) -#define NORMAL_COLOR RGB555(20,31,20) +#define NORMAL_COLOR RGB555(12,31,12) #define STORY_X 57 #define STORY_Y 50 #define STORY_XS (298-57) @@ -924,6 +922,7 @@ typedef struct { } TSAVEGAME_LIST; static TSAVEGAME_LIST current_game_slot_list = {}; +static int current_slot_list_top_line = 0; typedef struct { TSTR_LIST files; @@ -941,13 +940,23 @@ static char is_same_prefix(const char *name, const char *prev_name) { return 0; } -static int get_all_savegames_callback(const char *name, LIST_FILE_TYPE type , size_t size, void *ctx) { +static int get_all_savegames_callback(const char *name, LIST_FILE_TYPE type , size_t tm, void *ctx) { if (istrncmp(name, "sav.", 4) != 0 && istrcmp(name+strlen(name)-4,".sav") != 0) return 0; TSAVEGAME_CB_STATE *st = (TSAVEGAME_CB_STATE *)ctx; if (st->prefix_len == 0 || strncmp(name, st->prefix, st->prefix_len) == 0) { - str_replace(&(st->files), st->count, name); + size_t nlen = strlen(name); + if (st->count == (size_t)str_count(st->files)) { + TSTR_LIST nw = create_list(st->count * 3/2); + str_move_list(nw, st->files);; + release_list(st->files); + st->files = nw; + } + char *buff = NewArr(char, nlen + 1 + sizeof(tm)); + strncpy(buff, name, nlen+1); + memcpy(buff+nlen+1, &tm, sizeof(tm)); + st->files[st->count] = buff; ++st->count; } return 0; @@ -957,6 +966,16 @@ static int compare_strings (const void *a, const void *b) { return strcmp(*(const char **)a, *(const char **)b); } +static int compare_by_time (const void *a, const void *b) { + const char *s1 = *(const char **)a; + const char *s2 = *(const char **)b; + size_t tm1; + size_t tm2; + memcpy(&tm1, s1 + strlen(s1)+1, sizeof(tm1)); + memcpy(&tm2, s2 + strlen(s2)+1, sizeof(tm2)); + return tm1tm2?-1:0; +} + static int dedup_strings_prefix(TSTR_LIST lst, int count) { int j = -1; for (int i = 0; i < count; ++i) { @@ -1008,27 +1027,22 @@ static void load_specific_file(int slot_num,char *filename,void **out,int32_t *s static TSAVEGAME_LIST get_all_savegames(unsigned long kampan) { //sav.creation_time.game_save_time char prefix[50]; - snprintf(prefix,50,"sav.%010lx.",kampan); + snprintf(prefix,50,"sav.%08lx.",kampan); TSAVEGAME_CB_STATE st; st.files = create_list(32); st.prefix = kampan?prefix:NULL; st.prefix_len = kampan?strlen(prefix):0; st.count = 0; - list_files(gpathtable[SR_SAVES], file_type_just_name|file_type_normal, get_all_savegames_callback, &st); + list_files(gpathtable[SR_SAVES], file_type_just_name|file_type_need_timestamp|file_type_normal, get_all_savegames_callback, &st); qsort(st.files, st.count, sizeof(char *), compare_strings); if (kampan == 0) { st.count =dedup_strings_prefix(st.files, (int)st.count); } - TSTR_LIST files = create_list(st.count); - for (size_t i = 0; i < st.count; ++i) { - files[st.count-i-1] = st.files[i]; - st.files[i] = NULL; - } - release_list(st.files); + qsort(st.files, st.count, sizeof(char *), compare_by_time); TSTR_LIST names = create_list(st.count); for (size_t i = 0; i < st.count; ++i) { - FILE *f=fopen_icase(build_pathname(2, gpathtable[SR_SAVES], files[i]), "rb"); + FILE *f=fopen_icase(build_pathname(2, gpathtable[SR_SAVES], st.files[i]), "rb"); if (f!=NULL) { char slotname[SAVE_NAME_SIZE+1]; fread(slotname,1,SAVE_NAME_SIZE,f); @@ -1041,7 +1055,7 @@ static TSAVEGAME_LIST get_all_savegames(unsigned long kampan) { } TSAVEGAME_LIST out; - out.files = files; + out.files = st.files; out.names = names; out.count = st.count; return out; @@ -1057,10 +1071,11 @@ static void free_savegame_list(TSAVEGAME_LIST *lst) { static void place_name(int c,int i,char show, char sel) { int z,x; - if ((size_t)i >= current_game_slot_list.count) return; + int p = i + current_slot_list_top_line; + if ((size_t)p >= current_game_slot_list.count) return; if (c) x=SAVE_SLOT_S;else x=LOAD_SLOT_S; if (show) schovej_mysku(); - const char *name = current_game_slot_list.names[i]; + const char *name = current_game_slot_list.names[p]; set_font(SLOT_FONT,sel?SELECT_COLOR:NORMAL_COLOR); int w = text_width(name); int spc = 0; @@ -1199,23 +1214,14 @@ static int get_list_count() return max-20; } + static void select_slot(int i); + static int bright_slot(int yr) { int id; - id=yr/SLOT_SPACE; - if ((yr % SLOT_SPACE)<18 && yr>0) - { - if (id!=last_select) - { - if (last_select!=-1) place_name(force_save,last_select,1,0); - place_name(force_save,id,1,1); - last_select=id; - read_story(id); - } - } - else - id=-1; + id=yr/SLOT_SPACE+current_slot_list_top_line; + select_slot(id); return id; } @@ -1307,12 +1313,14 @@ T_CLK_MAP clk_load_error[]= }; + static char clk_load_proc_menu(int id,int xa,int ya,int xr,int yr) { id=bright_slot(yr-18); xa;ya;xr;yr; - if (ms_last_event.event_type & 0x2 && id>=0 && (size_t)id < current_game_slot_list.count) + if (ms_last_event.event_type & 0x2 && id>=0 && (size_t)id < current_game_slot_list.count) { send_message(E_CLOSE_MAP,current_game_slot_list.files[id]); + } return 1; } @@ -1326,38 +1334,43 @@ T_CLK_MAP clk_load_menu[]= {-1,0,0,639,479,empty_clk,0xff,H_MS_DEFAULT}, }; +static void load_save_pos_ingame(int id) { + if (load_game(current_game_slot_list.files[id])) + { + message(1,0,0,"",texty[79],texty[80]); + redraw_load(); + showview(0,0,0,0); + change_click_map(clk_load_error,CLK_LOAD_ERROR); + } +else + { + unwire_proc(); + wire_proc(); + if (battle) konec_kola(); + unwire_proc(); + if (!load_another) +{ +wire_main_functs(); +cur_mode=MD_GAME; +bott_draw(1); +pick_set_cursor(); +for(id=0;id=0 && (size_t)id < current_game_slot_list.count) { - if (load_game(current_game_slot_list.files[id])) - { - message(1,0,0,"",texty[79],texty[80]); - redraw_load(); - showview(0,0,0,0); - change_click_map(clk_load_error,CLK_LOAD_ERROR); - } - else - { - unwire_proc(); - wire_proc(); - if (battle) konec_kola(); - unwire_proc(); - if (!load_another) - { - wire_main_functs(); - cur_mode=MD_GAME; - bott_draw(1); - pick_set_cursor(); - for(id=0;idmsg=-2; @@ -1409,7 +1422,7 @@ static void save_it(char ok) { if (ok) { - save_game(slot_pos,global_gamename,1); + save_game(slot_pos,global_gamename); // read_slot_list(); wire_proc(); GlobEvent(MAGLOB_AFTERSAVE,viewsector,viewdir); @@ -1465,7 +1478,7 @@ T_CLK_MAP clk_load[]= static char clk_save_proc(int id,int xa,int ya,int xr,int yr) { - id=bright_slot(yr-18); + id=bright_slot(yr-18)+current_slot_list_top_line; xa;ya;xr;yr; if (ms_last_event.event_type & 0x2 && id>=0) { @@ -1491,6 +1504,32 @@ T_CLK_MAP clk_save[]= {-1,0,0,639,479,close_saveload,9,H_MS_DEFAULT}, }; +static void select_slot(int i) { + int rel = i-current_slot_list_top_line; + char unbright = 1; + while (rel < 0) { + --current_slot_list_top_line; + schovej_mysku(); + redraw_load(); + showview(0,0,0,0); + ukaz_mysku(); + rel++; + unbright = 0; + } + while (rel > SLOTS_MAX-1) { + ++current_slot_list_top_line; + schovej_mysku(); + redraw_load(); + showview(0,0,0,0); + ukaz_mysku(); + unbright = 0; + rel--; + } + if (last_select != -1) place_name(0,last_select-current_slot_list_top_line,1,0); + place_name(0,i-current_slot_list_top_line,1,1); + last_select = i; + } + static void saveload_keyboard(EVENT_MSG *msg,void **_) { if (msg->msg == E_KEYBOARD) @@ -1499,15 +1538,9 @@ static void saveload_keyboard(EVENT_MSG *msg,void **_) switch (v>>8) { case 1:unwire_proc();wire_proc();break; - case 'H':if (last_select>0) bright_slot((last_select-1)*SLOT_SPACE+1);break; - case 'P':if (last_select0) select_slot(last_select-1);break; + case 'P':if (last_select=0) load_save_pos_ingame(last_select);break; } } } @@ -1520,17 +1553,15 @@ static void saveload_keyboard_menu(EVENT_MSG *msg,void **_) switch (v>>8) { case 1:send_message(E_CLOSE_MAP,NULL);break; - case 'H':if (last_select>0) bright_slot((last_select-1)*SLOT_SPACE+1);break; - case 'P':if (last_select0) select_slot(last_select-1);break; + case 'P':if (last_select= 0 && last_select < current_game_slot_list.count) { + send_message(E_CLOSE_MAP, current_game_slot_list.files[last_select]); + break; } + } + } } void unwire_save_load(void) @@ -1662,23 +1693,36 @@ int load_map_automap(char *mapfile) return load_map_state_partial(mapfile,mapsize); //nahrej ulozenou mapu } +static void herni_cas_for_savegame(char *c) { + int32_t inmin = game_time/6; + if (inmin >= 96*60) { + int32_t inhours = inmin/60; + sprintf(c,"%dd %dh", inhours/24, inhours%24); + } else { + sprintf(c,"%02d:%02d", inmin/60, inmin%60); + } +} + #define DEFAULT_GAME_NAME(extra) \ char game_name[100];\ char hernicas[50];\ - herni_cas(hernicas);\ + herni_cas_for_savegame(hernicas);\ snprintf(game_name, sizeof(game_name), "%s %s" extra, mglob.mapname, hernicas); void do_autosave() { DEFAULT_GAME_NAME(" (A)"); - save_game(game_time, game_name,1); + if (game_time - prev_game_time_save<360) return; + prev_game_time_save = game_time; + save_game(game_time, game_name); } void do_save_dialog() { DEFAULT_GAME_NAME(""); if (ask_save_dialog(game_name, sizeof(game_name))) { - save_game(game_time, game_name, 0); + prev_game_time_save = game_time; + save_game(game_time, game_name); } diff --git a/game/globals.h b/game/globals.h index f4bad5d..15c8733 100644 --- a/game/globals.h +++ b/game/globals.h @@ -1404,7 +1404,7 @@ int save_map_state(void); //uklada stav mapy pro savegame (neuklada aktualni poz int load_map_state(void); //obnovuje stav mapy; nutno volat po zavolani load_map; void restore_current_map(void); //pouze obnovuje ulozeny stav aktualni mapy int load_game(const char *fname); -int save_game(int game_time,char *gamename, char skip_if_exists); +int save_game(int game_time,char *gamename); void wire_save_load(char save); void do_save_dialog(); char ask_save_dialog(char *name_buffer, size_t name_size); @@ -1547,7 +1547,7 @@ void check_all_mobs_battle(void); //kontroluje zda je nekdo v battle void manashield_check(short *vls,short *lives,short *mana,int dostal); char track_mob(int sect,int dir);//trackuje pritomnost potvory v urcitem smeru void stop_all_mobs(void); -int utok_na_sektor(THUMAN *p,TMOB *m,int chaos,int bonus); +int utok_na_sektor(THUMAN *p,TMOB *m,int chaos,int bonus, int ruka); int vyber_potvoru(int sect,int dir,int *chaos); //vybere potvoru ze sektoru a smeru. Vraci take pocet potvor v promenne *chaos void load_enemies(short *data,int size,int *grptr,TMOB *template,int32_t tsize); char mob_test_na_bitvu(TMOB *p); //nastavi p->vlajky|MOB_INBATTLE pokud potvora muze vstoupit do bitvy; @@ -1572,7 +1572,7 @@ void zacni_souboj(TMOB *p,int delka,short sector); char q_zacit_souboj(TMOB *p,int d,short sector); void stop_mob(TMOB *p); void start_battle(void); -int vypocet_zasahu(short *utocnik,short *obrance, int chaos,int zbran,int bonusplus); +int vypocet_zasahu(const short *utocnik,const short *obrance, int chaos,int zbran,int bonusplus, char enable_finesse_rule); void rozhodni_o_smeru(TMOB *p); void krok_moba(TMOB *p); void pomala_regenerace_postavy(THUMAN *p); diff --git a/game/globmap.c b/game/globmap.c index c4627ce..933536a 100644 --- a/game/globmap.c +++ b/game/globmap.c @@ -484,7 +484,7 @@ static char load_index_map(int index) */ if (!GlobEvent(MAGLOB_LEAVEMAP,viewsector,viewdir)) return 0; viewsector=lv; - strcopy_n(x.name,index_tab[index].mapname,12); + strcopy_n(x.name,index_tab[index].mapname,sizeof(x.name)); x.start_pos=0; x.dir=0; macro_load_another_map(&x); diff --git a/game/inv.c b/game/inv.c index b226278..76868d0 100644 --- a/game/inv.c +++ b/game/inv.c @@ -853,7 +853,7 @@ void prepocitat_postavu(THUMAN *human_selected) } p=sr1+VLS_DAMAGE; //vypocet damage (bez omezeni) q=&glob_items[c-1].zmeny[VLS_DAMAGE]; - *(p++)+=*q++; + *(p++)+=*q++; p=sr1+VLS_KOUZLA; //aplikace kouzel q=&glob_items[c-1].zmeny[VLS_KOUZLA]; (*p++)|=*q++; @@ -1357,8 +1357,7 @@ static T_INV_SCRIPT script[]= {0,37,NULL,0,97,1,0}, {30,5,"%d-%d",pvls(VLS_UTOK_L),pvls(VLS_UTOK_H),2,2}, {30,7,"%d-%d",pvls(VLS_OBRAN_L),pvls(VLS_OBRAN_H),2,2}, - {28,9,"%d",INFO_AP,0,2,2}, - {28,9,".%d",INFO_APF,0,2,0}, + {30,9,"%d",INFO_AP,0,2,2}, {17,5,NULL,0,18,1,0}, {17,7,NULL,0,17,1,0}, {17,9,NULL,0,20,1,0}, @@ -2055,7 +2054,7 @@ static char check_double_wield() { if (!i1 || !i2) return 0; const TITEM *it1 = glob_items+i1; const TITEM *it2 = glob_items+i2; - if (it1->typ_zbrane!=TYP_UTOC || it2->typ_zbrane!=TYP_UTOC ) return 0; + if (it1->druh!=TYP_UTOC || it2->druh!=TYP_UTOC ) return 0; for (int i = VLS_SILA; i <=VLS_OBRAT; ++i) { if ((it1->podminky[i] + it2->podminky[i] > human_selected->vlastnosti[i]) && (MAX(it1->podminky[i], it2->podminky[i]) > human_selected->vlastnosti[VLS_OBRAT])) { diff --git a/game/macros.c b/game/macros.c index 7d8c7e8..a914227 100644 --- a/game/macros.c +++ b/game/macros.c @@ -409,7 +409,7 @@ static void hit_1_player(int postava,const TMA_WOUND *w,int chaos) memset(vls,0,sizeof(vls)); vls[VLS_UTOK_L]=w->minor; vls[VLS_UTOK_H]=w->major; - dostal=vypocet_zasahu(vls,h->vlastnosti,chaos,0,0); + dostal=vypocet_zasahu(vls,h->vlastnosti,chaos,0,0,0); } else { @@ -419,7 +419,7 @@ static void hit_1_player(int postava,const TMA_WOUND *w,int chaos) vls[VLS_MGSIL_L]=w->minor; vls[VLS_MGSIL_H]=w->major; vls[VLS_MGZIVEL]=zivel; - dostal=vypocet_zasahu(vls,h->vlastnosti,chaos,0,0); + dostal=vypocet_zasahu(vls,h->vlastnosti,chaos,0,0,0); } player_hit(h,dostal,0); } diff --git a/game/realgame.c b/game/realgame.c index 22c1371..f4e0aa0 100644 --- a/game/realgame.c +++ b/game/realgame.c @@ -1335,7 +1335,7 @@ char chod_s_postavama(char sekupit) { postavy[i].sektor=viewsector; postavy[i].direction=viewdir; - postavy[i].utek=1; + postavy[i].utek=0; postavy[i].kondice-=weigth_defect(postavy+i); if (postavy[i].kondice<0) postavy[i].kondice=0; group_nums[cur_group]=1; diff --git a/game/souboje.c b/game/souboje.c index bcaf06f..822e74e 100644 --- a/game/souboje.c +++ b/game/souboje.c @@ -108,6 +108,8 @@ static char ask_who_proc(int id,int xa,int ya,int xr,int yr); void wire_programming(); void souboje_vybrano(int d); void program_draw(); +static void souboje_turn(int smer); +static char clk_fly_cursor(int id,int xa,int ya,int xr,int yr); void (*after_spell_wire)(); @@ -126,7 +128,7 @@ HUM_ACTION *magic_data; static int minwait=0,maxwait=-1; -#define CLK_SOUBOJE 15 +#define CLK_SOUBOJE 16 T_CLK_MAP clk_souboje[]= { {-1,337,0,357,14,go_map,2,H_MS_DEFAULT}, @@ -143,6 +145,7 @@ T_CLK_MAP clk_souboje[]= {-1,528,378,630,479,mask_click_help,1,-1}, {-1,0,0,640,480,mask_click_help_clear,1,-1}, {MS_GAME_WIN,0,17,639,377,souboje_clk_throw,2,-1}, + {MS_GAME_WIN,0,17,639,377,clk_fly_cursor,8,-1}, {-1,54,378,497,479,start_invetory,2+8,-1}, }; @@ -350,17 +353,21 @@ void zacni_souboj(TMOB *p,int d,short sector) -int vypocet_zasahu(short *utocnik,short *obrance, int chaos,int zbran,int external_force) +int vypocet_zasahu(const short *utocnik,const short *obrance, int chaos,int zbran,int external_force, char enable_finesse_rule) { int zasah,mutok,flg; flg=obrance[VLS_KOUZLA]; - short attack_attribute = MAX(utocnik[VLS_SILA], utocnik[VLS_OBRAT]); + short attbonus = enable_finesse_rule?MAX(utocnik[VLS_SILA], utocnik[VLS_OBRAT]):utocnik[VLS_SILA]; + char finesse = utocnik[VLS_SILA] != attbonus; + attbonus/=5; int utok,obrana; int ospod; int attack_roll,defense_roll,mag_att_roll,mg_def; int dmzhit = 0; int ddostal = 0; int disadv = 0; + int obrbonus = obrance[VLS_OBRAT]/5; + int magbonus = utocnik[VLS_SMAGIE]/5; /* if (game_extras & EX_ALTERNATEFIGHT) { @@ -398,11 +405,11 @@ int vypocet_zasahu(short *utocnik,short *obrance, int chaos,int zbran,int exter mag_att_roll=utocnik[VLS_MGSIL_L]+rnd(utocnik[VLS_MGSIL_H]-utocnik[VLS_MGSIL_L]+1); //hit=attack_roll+max(str,dex)+external_force - utok=attack_roll+attack_attribute/5+external_force; + utok=attack_roll+attbonus+external_force; //def=defense_roll+dex/5+(10 if invisible) - obrana=defense_roll+(obrance[VLS_OBRAT]/5)+(flg & SPL_INVIS?10:0); + obrana=defense_roll+obrbonus+(flg & SPL_INVIS?10:0); //mg_attack = magic_roll - mutok=mag_att_roll+(mag_att_roll?(utocnik[VLS_SMAGIE]/5):0); + mutok=mag_att_roll+(mag_att_roll?magbonus:0); //mg_deffense (100-x) mg_def=obrance[VLS_OHEN+utocnik[VLS_MGZIVEL]]; //adjust magic attack @@ -411,44 +418,62 @@ int vypocet_zasahu(short *utocnik,short *obrance, int chaos,int zbran,int exter } if (zasah<0) zasah=0; int damage = utocnik[VLS_DAMAGE]+zbran; - if (zasah<0 || damage<0) damage = 0; + if (zasah<=0 || damage<=0) damage = 0; ddostal=zasah; zasah+=damage; if (log_combat) { - wzprintf("Combat: Attack roll (%d-%d) = %d, " - "Defense disadv.: %d*2/(%d+1)=%d , " - "Defense roll (%d-%d) = %d, " - "Magic roll (%d-%d) = %d\n", - (int)utocnik[VLS_UTOK_L],(int)utocnik[VLS_UTOK_H],attack_roll, - (int)obrance[VLS_OBRAN_L],chaos, ospod, - ospod,(int)obrance[VLS_OBRAN_H], defense_roll, - (int)utocnik[VLS_MGSIL_L],(int)utocnik[VLS_MGSIL_H], mag_att_roll); - wzprintf("Combat: phys.hit: %d(att.roll) + %d(%s)/5 +%d(ext.force) - %d(def.roll)-%d(%s)/5 + %d(damage)=%d(%d)\n", - attack_roll, attack_attribute, - attack_attribute==utocnik[VLS_SILA]?texty[10]:texty[13], - external_force, defense_roll, (int)obrance[VLS_OBRAT], - texty[13], damage, utok-obrana, zasah); - if (mag_att_roll) { - wzprintf("Combat: %d(magic roll) + %d(%s)/5 = %d, magic resistance = %d(%s), magic hit: %d * (100 - %d)/100 = %d\n", - mag_att_roll, (int)utocnik[VLS_SMAGIE], texty[11], mutok, mg_def,texty[22+utocnik[VLS_MGZIVEL]], mutok, mg_def, dmzhit); - + wzprintf(">"); + if (utocnik[VLS_UTOK_H]) { + wzprintf("Attack (physical): %d (roll %d-%d) + %d (%s/5) + %d (ext.force) = %d\n", + attack_roll, (int)utocnik[VLS_UTOK_L],(int)utocnik[VLS_UTOK_H], + attbonus, finesse?texty[13]:texty[10], + external_force,utok); + } else if (external_force) { + wzprintf("Attack (physical): %d (ext.force)\n", external_force); + } + if (obrance[VLS_OBRAN_H] && utok > 0) { + char chaos[50]; + if (disadv > 1) snprintf(chaos, 50, ", disadvantage %d", disadv); + else strcpy(chaos,""); + wzprintf(" Defense (physical): %d (roll %d-%d%s) + %d (%s/5) = %d\n", + defense_roll, ospod, obrance[VLS_OBRAN_H], chaos, obrbonus, texty[13], obrana); + } + if (zasah>0) { + if (damage) { + wzprintf(" Psychical hit: %d - %d + %d (damage) + %d (weapon) = %d\n", + utok, obrana, utocnik[VLS_DAMAGE], zbran, zasah); + } else { + wzprintf(" Psychical hit: %d - %d = %d\n", + utok, obrana, zasah); + } } } if (flg & SPL_SANC) { zasah/=2; - if (log_combat) wzprintf("Physical resistance applied: %d/2 = %d", ddostal, zasah); + if (log_combat) wzprintf( "Physical resistance applied: %d - %d (half)= %d\n", ddostal,ddostal - zasah, zasah); ddostal = zasah; } - zasah=zasah+dmzhit; + int total_hit = zasah+dmzhit; + if (log_combat) { + if ((int)utocnik[VLS_MGSIL_H]) { + wzprintf(" Attack (magical): %d (roll %d-%d) + %d (%s/5) = %d\n", + mag_att_roll,(int)utocnik[VLS_MGSIL_L],(int)utocnik[VLS_MGSIL_H], magbonus, texty[11], mutok); + wzprintf(" Magical hit: %d - %d (resistance %s: %d%%) = %d\n", + mutok, mutok - dmzhit, texty[22+utocnik[VLS_MGZIVEL]], mg_def, dmzhit); + wzprintf(" Total hit: %d (physical) + %d (magical) = %d\n", + zasah, dmzhit, total_hit); + } + } if (flg & SPL_HSANC) { - zasah/=2; - if (log_combat) wzprintf("Total resistance applied: %d/2 = %d", ddostal, zasah); + int tmp = total_hit; + total_hit/=2; + if (log_combat) wzprintf("Total resistance applied: %d - %d (half) = %d\n", tmp, total_hit - tmp); } if (flg & SPL_TVAR) { - if (log_combat) wzprintf("Set Face spell applied: %d = -%d (heal)", zasah, zasah); - zasah=-zasah; + if (log_combat) wzprintf("Set Face spell applied: %d = -%d (heal)\n", total_hit, -total_hit); + total_hit=-total_hit; } - return zasah; + return total_hit; } void rozhodni_o_poradi() @@ -628,7 +653,7 @@ void zacatek_kola() if (p->kondice && p->lives && p->inmaphash == current_map_hash) { pc_gain_action(p); - p->actions=pc_get_actions(p); + p->actions=MAX(1, postavy[i].vlastnosti[VLS_POHYB]/15); // if (p->actions) autostart_round=0; } else postavy[i].actions=0; @@ -1181,14 +1206,22 @@ void pouzij_zbran(THUMAN *p,int ruka) mm=vyber_potvoru(p->sektor,p->direction,&chaos); if (mm>=0) { - TITEM *it=glob_items+itm-1; + TITEM *it=itm?glob_items+itm-1:NULL; m=mobs+mm; bott_draw(1); anim_mirror=ruka==0; prejdi_na_pohled(p); if (itm) play_weapon_anim(it->weapon_attack,it->hitpos); - if (utok_na_sektor(p,m,chaos,bonus)>0 && itm && (int)rnd(100)+1magie) - thing_cast(it->spell,p-postavy,p->sektor,m,1); + if (utok_na_sektor(p,m,chaos,bonus,it==NULL || it->umisteni == PL_OBOUR?0:where)>0 && itm ) { + int roll = (int)rnd(100)+1; + char cast = roll magie; + if (cast) { + if (log_combat) wzprintf(" Weapon cast: %s - %d (roll) > %d (probability)\n",it->jmeno, roll, it->magie); + thing_cast(it->spell,p-postavy,p->sektor,m,1); + } + } + + } } else @@ -1904,6 +1937,27 @@ char mask_click_help_clear(int id,int xa,int ya,int xr,int yr) return 1; } + static char clk_fly_cursor(int id,int xa,int ya,int xr,int yr) + { + id; + + if (spell_cast) + { + spell_cast=0; + pick_set_cursor(); + return 1; + } + if (xr<160) { + souboje_turn(-1); + } else if (xr > 480) { + souboje_turn(1); + } else { + return 0; + } + return 1; + } + + static void zahajit_kolo(char prekvapeni) { int i,j; @@ -2027,7 +2081,7 @@ void fix_group_direction() if (postavy[i].used && postavy[i].groupnum==g && !postavy[i].programovano) postavy[i].direction=viewdir; } -void souboje_turn(int smer) +static void souboje_turn(int smer) { if (pass_zavora) return; norefresh=1; @@ -2257,15 +2311,15 @@ char zasah_veci(int sector,TFLY *fl) if (m2 == NULL) { mob_hit(m1, vypocet_zasahu(it->zmeny, m1->vlastnosti, 1, fl->damage, - fl->hit_bonus)); + fl->hit_bonus,0)); m1->dir = (fl->smer + 2) & 3; } else { mob_hit(m1, vypocet_zasahu(it->zmeny, m1->vlastnosti, 2, fl->damage, - fl->hit_bonus)); + fl->hit_bonus,0)); mob_hit(m2, vypocet_zasahu(it->zmeny, m1->vlastnosti, 2, fl->damage, - fl->hit_bonus)); + fl->hit_bonus,0)); m1->dir = (fl->smer + 2) & 3; m2->dir = (fl->smer + 2) & 3; } @@ -2288,7 +2342,7 @@ char zasah_veci(int sector,TFLY *fl) short vlastnosti[VLS_MAX]; memcpy(vlastnosti,p->vlastnosti,sizeof(vlastnosti)); if (game_extras & EX_SHIELD_BLOCKING) PodporaStitu(p, vlastnosti); - death=player_hit(p,vypocet_zasahu(it->zmeny,vlastnosti,kolik,fl->damage,fl->hit_bonus),1); + death=player_hit(p,vypocet_zasahu(it->zmeny,vlastnosti,kolik,fl->damage,fl->hit_bonus,0),1); if (death && owner && hlubina_level) mobs[-owner-1].lives=0; //hlubina - nestvura je mrtva c=1; } @@ -2318,7 +2372,7 @@ char zasah_veci(int sector,TFLY *fl) if (abs(x1-m1->locx+128)+abs(y1-m1->locy+128)>abs(x1-m2->locx+128)+abs(y1-m2->locy+128)) m1=m2; } if (m1->vlajky & MOB_PASSABLE) return 0; - mob_hit(m1,vypocet_zasahu(it->zmeny,m1->vlastnosti,(m2!=NULL)+1,fl->damage,fl->hit_bonus)); + mob_hit(m1,vypocet_zasahu(it->zmeny,m1->vlastnosti,(m2!=NULL)+1,fl->damage,fl->hit_bonus,0)); if (it->druh==TYP_VRHACI) fl->flags|=FLY_DESTROY; if (it->umisteni!=PL_SIP && !(it->flags & ITF_DESTROY)) { @@ -2347,7 +2401,7 @@ char zasah_veci(int sector,TFLY *fl) short vlastnosti[VLS_MAX]; memcpy(vlastnosti,p->vlastnosti,sizeof(vlastnosti)); if (game_extras & EX_SHIELD_BLOCKING) PodporaStitu(p, vlastnosti);else uprav_podle_kondice(p,&kolik); - death=player_hit(p,vypocet_zasahu(it->zmeny,vlastnosti,kolik,fl->damage,fl->hit_bonus),1); + death=player_hit(p,vypocet_zasahu(it->zmeny,vlastnosti,kolik,fl->damage,fl->hit_bonus,0),1); if (death && owner && hlubina_level) mobs[-owner-1].lives=0; //hlubina - nestvura je mrtva c=1; } @@ -2463,7 +2517,7 @@ void send_experience(TMOB *p,int dostal) if (dostal>0) { int exp = ((float)p->experience*(float)dostal/p->vlastnosti[VLS_MAXHIT]); if (log_combat && p->bonus) { - wzprintf("%s experience: %d\n", postavy[select_player].jmeno, p->bonus); + wzprintf("%s experience: %d\n", postavy[select_player].jmeno, exp); } postavy[select_player].exp+=(int32_t)exp; @@ -2552,6 +2606,7 @@ char player_hit(THUMAN *p,int zraneni,char manashield) { THE_TIMER *tt;int h; + if (log_combat) wzprintf("%s was hit: %d, lives: %d\n", p->jmeno, zraneni, p->lives-zraneni); if (zraneni>p->lives) zraneni=p->lives; p->dostal=zraneni; if (manashield) manashield_check(p->vlastnosti,&p->lives,&p->mana,p->dostal); //manashield pro hrace diff --git a/libs/strlite.c b/libs/strlite.c index 70dc25c..a29c0e7 100644 --- a/libs/strlite.c +++ b/libs/strlite.c @@ -69,6 +69,18 @@ int str_add(TSTR_LIST *list,const char *text) return i; } +int str_move_list(TSTR_LIST to, TSTR_LIST from) { + int cnt1 = str_count(from); + int cnt2 = str_count(to); + int cnt = MIN(cnt1,cnt2); + for (int i = 0; i < cnt; ++i) { + if (to[i]) free(to[i]); + to[i] = from[i]; + from[i] = NULL; + } + return cnt; +} + const char *str_insline(TSTR_LIST *list,int before,const char *text) { int i,count,punkt; diff --git a/libs/strlite.h b/libs/strlite.h index 464bc6d..e68ffdf 100644 --- a/libs/strlite.h +++ b/libs/strlite.h @@ -19,6 +19,7 @@ void str_remove(TSTR_LIST *list,int line); void str_delfreelines(TSTR_LIST *list); int str_count(TSTR_LIST p); void release_list(TSTR_LIST list); +int str_move_list(TSTR_LIST to, TSTR_LIST from); TSTR_LIST sort_list(TSTR_LIST list,int direction); TSTR_LIST read_directory(const char *mask,int view_type,int attrs); //void name_conv(const char *c); diff --git a/platform/file_access.cpp b/platform/file_access.cpp index 266a532..bf9b55f 100644 --- a/platform/file_access.cpp +++ b/platform/file_access.cpp @@ -121,21 +121,28 @@ int list_files(const char *directory, int type, LIST_FILES_CALLBACK cb, void *ct int r = 0; const auto &entry = *iter; const char *name; + size_t szortm = 0; std::string tmp; if (type & file_type_just_name) { tmp = entry.path().filename().string(); } else { tmp = entry.path().string(); + } + if (type & file_type_need_timestamp) { + auto tm = std::chrono::clock_cast(entry.last_write_time(ec)); + szortm = std::chrono::system_clock::to_time_t(tm); + } else { + szortm = entry.file_size(ec); } name = tmp.c_str(); if (entry.is_regular_file(ec) && (type & file_type_normal)) { - r = cb(name, file_type_normal, entry.file_size(ec), ctx); + r = cb(name, file_type_normal, szortm, ctx); } else if (entry.is_directory(ec)) { int dot = entry.path().filename() == "." || entry.path().filename() == ".."; if (!dot && (type & file_type_directory)) { - r = cb(name, file_type_directory, 0, ctx); + r = cb(name, file_type_directory, szortm, ctx); } else if (dot & (type & file_type_dot)) { - r = cb(name, file_type_dot, 0, ctx); + r = cb(name, file_type_dot, szortm, ctx); } } if (r) return r; diff --git a/platform/platform.h b/platform/platform.h index 763cbb0..10b94e7 100644 --- a/platform/platform.h +++ b/platform/platform.h @@ -17,9 +17,19 @@ #pragma warning(disable: 4457) #pragma warning(disable: 4702) #pragma warning(disable: 4100) +//microsoft doesn't support FALLTHROUGH #define CASE_FALLTHROUGH + +//microsoft doesn't support VLA +#define DECL_VLA(type, variable, count) type *variable = (type *)alloca((count)*sizeof(type)); +#define GET_VLA_SIZE(variable, count) ((count)*sizeof(*variable)) + #else +//support FALLTHROUGH #define CASE_FALLTHROUGH [[fallthrough]] +//support VLA +#define DECL_VLA(type, variable, count) type variable[count]; +#define GET_VLA_SIZE(variable, count) sizeof(variable) #endif @@ -90,6 +100,7 @@ const char *file_icase_find(const char *pathname); int istrcmp(const char *a, const char *b); int istrncmp(const char *a, const char *b, size_t sz); int imatch(const char *haystack, const char *needle); +#define SAFESTRCOPY(target, source) strcopy_n(target, source, sizeof(target) ) const char *strcopy_n(char *target, const char *source, int target_size); #define MIN(a, b) ((a)<(b)?(a):(b)) #define MAX(a, b) ((a)>(b)?(a):(b)) @@ -104,7 +115,8 @@ typedef enum { file_type_normal = 1, file_type_directory = 2, file_type_dot = 4, - file_type_just_name = 8 + file_type_just_name = 8, + file_type_need_timestamp = 16 } LIST_FILE_TYPE; typedef int (*LIST_FILES_CALLBACK)(const char *, LIST_FILE_TYPE , size_t, void *);