Merge branch 'main' into sse

This commit is contained in:
Ondřej Novák 2025-05-09 08:04:02 +02:00
commit 5931c6eab4
37 changed files with 739 additions and 147 deletions

View file

@ -40,6 +40,30 @@ else()
endif()
set(VERSION_IN "${CMAKE_SOURCE_DIR}/version.in.h")
set(VERSION_OUT "${CMAKE_BINARY_DIR}/version.h")
find_package(Git QUIET)
if(GIT_FOUND)
execute_process(
COMMAND ${GIT_EXECUTABLE} describe --tags --always
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_VERSION
OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE GIT_RESULT
)
if(NOT GIT_RESULT EQUAL 0)
set(GIT_VERSION "unknown")
endif()
else()
set(GIT_VERSION "unknown")
endif()
set(APP_VERSION "${GIT_VERSION}")
configure_file(${VERSION_IN} ${VERSION_OUT} @ONLY)
include_directories(${CMAKE_BINARY_DIR})
include_directories(.)

View file

@ -1109,3 +1109,9 @@ void free_map_description() {
if (texty_v_mape!=NULL)release_list(texty_v_mape);
texty_v_mape = NULL;
}
TSTR_LIST swap_map_description(TSTR_LIST new_list) {
TSTR_LIST old = texty_v_mape;
texty_v_mape = new_list;
return old;
}

View file

@ -327,14 +327,14 @@ static const void *bott_draw_normal(const void *pp, int32_t *s)
{
char c[]=" ";int z,lv,llv;
put_picture(x,0,ablock(H_OKNO));lv=p->lives;llv=p->vlastnosti[VLS_MAXHIT];
if (lv || p->used & 0x80 || p->kondice > 0)
if (lv || p->used & 0x80)
{
z=3-((lv-1)*4/llv);if (lv==llv) z=0;
z*=75;
if (p->xicht>=0)put_8bit_clipped(ablock(H_XICHTY+i),bott_scr+PIC_X+x+PIC_Y*scr_linelen2,z,54,75);
if (!lv && !(p->used & 0x80) && p->kondice>0) {
/* if (!lv && !(p->used & 0x80) && p->kondice>0) {
greyscale_rectangle(PIC_X+x,PIC_Y, 54, 75);
}
}*/
if (p->bonus) draw_small_icone(0,PIC_X+x+1,PIC_Y+1);
if (p->spell) draw_small_icone(1,PIC_X+x+1,PIC_Y+1);
if (!p->voda) draw_small_icone(2,PIC_X+x+1,PIC_Y+1);

View file

@ -745,7 +745,7 @@ static void wait_timer(EVENT_MSG *msg, void **udata) {
}
}
void effect_show(va_list args)
void effect_show(void)
{
int i;
char s = exit_wait;
@ -861,7 +861,7 @@ char enter_generator()
memset(&cur_stats,0,sizeof(cur_stats));
vypocet_vlastnosti(cur_angle,&cur_vls);
b_disables=0x7;
redraw_generator(rep);if (!rep)effect_show(NULL);rep=1;
redraw_generator(rep);if (!rep)effect_show();rep=1;
edit_name();
change_click_map(clk_page1,CLK_PAGE1);
was_enter=0;

View file

@ -766,7 +766,7 @@ void wire_dialog_drw(void)
wire_dialog();
draw_all();
ukaz_mysku();
effect_show(NULL);
effect_show();
}
void unwire_dialog(void)
{

View file

@ -1317,18 +1317,24 @@ void vymaz_zasahy(THE_TIMER *q)
bott_draw(0);
}
static int select_drop_inventory_place(TMOB *p) {
int x,y,pl;
if (p->locx>128) x=1;else if (p->locx<128) x=-1;else x=rnd(2)*2-1;
if (p->locy>128) y=1;else if (p->locy<128) y=-1;else y=rnd(2)*2-1;
pl=0;if (x>0) pl++;
if (y>0) pl=3-pl;
return pl;
}
static int drop_inventory(TMOB *p)
{
int i,x,y,pl;
int i,pl;
short c[]={0,0};
for(i=-1;i<MOBS_INV;i++)
for(i=-1;i<MOBS_INV;i++) {
if (p->inv[i] || (i<0 && p->money))
{
if (p->locx>128) x=1;else if (p->locx<128) x=-1;else x=rnd(2)*2-1;
if (p->locy>128) y=1;else if (p->locy<128) y=-1;else y=rnd(2)*2-1;
pl=0;if (x>0) pl++;
if (y>0) pl=3-pl;
pl = select_drop_inventory_place(p);
if (i<0)
{
int z=(int)p->money+(int)(rnd(40)-20)*(int)p->money/(int)100;
@ -1341,6 +1347,16 @@ static int drop_inventory(TMOB *p)
}
push_item(p->sector,pl,c);
}
}
if (destroyed_items) {
int cnt = count_items_total(destroyed_items);
if (cnt) {
int idx = cnt -1;
pl = select_drop_inventory_place(p);
push_item(p->sector,pl, destroyed_items+idx);
destroyed_items[idx] = 0;
}
}
return 0;
}

View file

@ -30,6 +30,9 @@
#define SLOTS_MAX 10
#define GM_MAPENABLE 0x1
#define GM_FASTBATTLES 0x2
#define GM_GAMESPEED_SHIFT 2
#define GM_GAMESPEED_MASK 0x1F
#define SAVE_SLOT_S 34
#define LOAD_SLOT_S (372+34)
@ -583,6 +586,14 @@ int unpack_all_status(FILE *f)
return -1;
}
static void save_destroyed_items(TMPFILE_WR *f) {
short c = (short)count_items_total(destroyed_items);
temp_storage_write(&c,sizeof(c), f);
if (c) {
temp_storage_write(destroyed_items,sizeof(short)*c, f);
}
}
int save_basic_info()
{
TMPFILE_WR *f;
@ -618,7 +629,14 @@ int save_basic_info()
s.swapchans=MIN(get_snd_effect(SND_SWAP),255);
s.out_filter=MIN(get_snd_effect(SND_OUTFILTER),255);
s.autosave=autosave_enabled;
s.game_flags=(enable_glmap!=0);
s.game_flags=0;
if (enable_glmap!=0) s.game_flags |= GM_MAPENABLE;
if (gamespeedbattle<gamespeed) s.game_flags |= GM_FASTBATTLES;
if (timerspeed_val <= GM_GAMESPEED_MASK) {
s.game_flags |= (timerspeed_val & GM_GAMESPEED_MASK) << GM_GAMESPEED_SHIFT;
}
strcopy_n(s.level_name,level_fname,sizeof(s.level_name));
for(i=0;i<5;i++) s.runes[i]=runes[i];
if (picked_item!=NULL)
@ -635,11 +653,26 @@ int save_basic_info()
for(i=0,h=postavy;i<POCET_POSTAV;h++,i++) if (h->demon_save!=NULL)
temp_storage_write(h->demon_save,sizeof(THUMAN)*1,f); //ulozeni polozek s demony
res|=save_dialog_info(f);
save_destroyed_items(f);
temp_storage_close_wr(f);
SEND_LOG("(SAVELOAD) Done... Result: %d",res);
return res;
}
static int load_destroyed_items(TMPFILE_RD *f) {
int res = 0;
short destroyed_items_count = 0;
temp_storage_read(&destroyed_items_count,sizeof(destroyed_items_count), f);
free(destroyed_items);
destroyed_items = NULL;
if (destroyed_items_count) {
destroyed_items = NewArr(short, destroyed_items_count+1);
res|=temp_storage_read(destroyed_items,destroyed_items_count*sizeof(short), f) != destroyed_items_count*sizeof(short);
destroyed_items[destroyed_items_count] = 0;
}
return res;
}
int load_basic_info()
{
TMPFILE_RD *f;
@ -654,6 +687,9 @@ int load_basic_info()
if (f==NULL) return 1;
res|=(temp_storage_read(&s,1*sizeof(s),f)!=sizeof(s));
if (s.game_flags & GM_MAPENABLE) enable_glmap=1;else enable_glmap=0;
gamespeedbattle =s.game_flags & GM_FASTBATTLES? GAMESPEED_FASTBATTLE:gamespeed;
int tmsp = (s.game_flags >> GM_GAMESPEED_SHIFT) & GM_GAMESPEED_MASK;
if (tmsp) timerspeed_val = tmsp;
i=s.picks;
if (picked_item!=NULL) free(picked_item);
if (i)
@ -685,6 +721,7 @@ int load_basic_info()
}
}
res|=load_dialog_info(f);
res|=load_destroyed_items(f);
temp_storage_close_rd(f);
viewsector=s.viewsector;
viewdir=s.viewdir;
@ -776,11 +813,12 @@ int save_game(long game_time,char *gamename, char is_autosave)
temp_storage_store("playtime",&new_play_time, sizeof(new_play_time));
svf=fopen_icase(sn,"wb");
if (svf==NULL)
{
char buff[256];
sprintf(buff,"Nelze ulozit pozici na cestu: %s", sn);
display_error(buff);
if (svf==NULL){
if (!is_autosave) {
char buff[256];
sprintf(buff,"Failed to create savegame at path %s", sn);
message(1,0,0,"",buff,texty[80]);
}
}
else
{
@ -1769,12 +1807,12 @@ void wire_save_load(char save) {
change_click_map(clk_save,CLK_SAVELOAD);
redraw_save();
send_message(E_ADD, E_KEYBOARD, saveload_keyboard);
effect_show(NULL);
effect_show();
} else {
curcolor = 0;
redraw_load();
effect_show(NULL);
effect_show();
if (save == 2)
change_click_map(clk_load_error, CLK_LOAD_ERROR);
else if (save == 4) {

View file

@ -12,6 +12,10 @@
#define POCET_POSTAV 6
#define HODINA 360
#define GAMESPEED 5
#define GAMESPEED_FASTBATTLE 2
#define MAX_FILESYSTEM_PATH 256
#define A_SIDEMAP 0x8001
@ -573,6 +577,7 @@ extern int mapsize; //pocet sektoru v mape
extern int hl_ptr; //ukazatel na konec staticke tabulky registraci
extern int end_ptr; //ukazatel na uplny konec tabulky registraci
extern short **map_items; //ukazatel na mapu predmetu
extern short *destroyed_items; //list of destroyed items to be returned to the game
extern int default_ms_cursor; //cislo zakladniho mysiho kurzoru
extern void (*unwire_proc)(void); //procedura zajistujici odpojeni prave ukoncovane interakce
extern void (*wire_proc)(void); //procedura zajistujici pripojeni drive ukoncene interakce
@ -581,8 +586,8 @@ extern word minimap[VIEW3D_Z+1][VIEW3D_X*2+1]; //minimalizovana mapa s informace
extern char norefresh; //vypina refresh obrazovky
extern char cancel_pass; //okamzite zrusi plynuly prechod
extern char reverse_draw ; //kresba odpredu dozadu
extern char gamespeed; //rychlost hry
extern char gamespeedbattle; //akcelerace rychlosti pro bitvy
extern uint8_t gamespeed; //rychlost hry
extern uint8_t gamespeedbattle; //akcelerace rychlosti pro bitvy
extern int num_ofsets[]; //tabulka offsetu pro steny
extern int back_color; //cislo barvy pozadi
extern uint8_t cur_group; //cislo aktualni skupiny
@ -986,10 +991,10 @@ char pick_item_(int id,int xa,int ya,int xr,int yr);
void wire_inv_mode(THUMAN *select);
void init_inventory(void);
void init_items(void);
void push_item(int sect,int pos,short *picked_item);
void push_item(int sect,int pos,const short *picked_item);
void pop_item(int sect,int pos,int mask,short **picked_item);
int count_items_inside(short *place);
int count_items_total(short *place);
int count_items_inside(const short *place);
int count_items_total(const short *place);
char put_item_to_inv(THUMAN *p,short *picked_items); //funkce vklada predmet(y) do batohu postavy
void pick_set_cursor(void); //nastavuje kurzor podle vlozeneho predmetu;
void calc_fly(THE_TIMER *t);
@ -1402,7 +1407,7 @@ void destroy_all_fly();
void stop_fly(LETICI_VEC *p,char zvuk);
void herni_cas(char *s);
typedef char **TSTR_LIST;
//gamesaver
void leave_current_map(void);
@ -1415,6 +1420,7 @@ int save_game(long game_time,char *gamename, char is_autosave);
void save_map_description(TMPFILE_WR *f);
void load_map_description(TMPFILE_RD *f);
void free_map_description();
TSTR_LIST swap_map_description(TSTR_LIST new_list);
void wire_save_load(char save);
void do_save_dialog();
char ask_save_dialog(char *name_buffer, size_t name_size, char allow_remove);
@ -1762,8 +1768,8 @@ char clk_enter(int id,int xa,int ya,int xr,int yr);
//menu
int enter_menu(char open); //task!
void titles(va_list args); //task!
void run_titles(va_list args); //task!
void effect_show(va_list args); //effektni zobrazeni // task!
void run_titles(void );
void effect_show(void); //effektni zobrazeni
void konec_hry(void);

View file

@ -630,13 +630,14 @@ struct _tag_map_save_state{
TSTENA *_map_sides;
TSECTOR *_map_sectors;
TMAP_EDIT_INFO *_map_coord;
TSTR_LIST _map_desc;
int _map_size;
int _viewsector;
int _viewdir;
uint32_t _hash;
} MAP_SAVE_STATE;
static struct _tag_map_save_state save_state = {NULL,NULL,NULL,0,0,0,0};
static struct _tag_map_save_state save_state = {NULL,NULL,NULL,NULL,0,0,0,0};
static void save_current_map() {
if (save_state._map_coord) {
@ -647,6 +648,7 @@ static void save_current_map() {
save_state._map_coord = map_coord;
save_state._map_sectors = map_sectors;
save_state._map_size = mapsize;
save_state._map_desc = swap_map_description(NULL);
save_state._viewsector = viewsector;
save_state._viewdir = viewdir;
save_state._hash = current_map_hash;
@ -661,6 +663,7 @@ static void restore_saved_map() {
free(map_sides);
free(map_sectors);
free(map_coord);
free_map_description();
mapsize =save_state._map_size;
map_sides = save_state._map_sides;
map_sectors = save_state._map_sectors;
@ -668,9 +671,11 @@ static void restore_saved_map() {
viewsector = save_state._viewsector;
viewdir = save_state._viewdir;
current_map_hash = save_state._hash;
swap_map_description(save_state._map_desc);
save_state._map_sides = NULL;
save_state._map_coord = NULL;
save_state._map_sectors = NULL;
save_state._map_desc = NULL;
}
}

View file

@ -1486,8 +1486,9 @@ int smlouvat_prodej(int cena,int ponuka,int posledni,int puvod,int pocet)
if (ponuka==0) return 0;
if (ponuka<=cena) return 0;
if (posledni!=0) if (ponuka>=posledni || ponuka>min) return 1;
if (p_ok>r_ok) return 0;
if (ponuka <= min && (posledni==0 || ponuka<posledni)) {
if (p_ok>r_ok) return 0;
}
if (p_ok>75) return 2;
if (p_ok>50) return 3;
if (p_ok>25) return 4;
@ -1544,7 +1545,7 @@ THAGGLERESULT smlouvat_dlg(int cena,int puvod,int pocet,int posledni, int money,
define(-1,150,15,100,13,0,label,int2ascii(cena,buffer,10));
set_font(H_FBOLD,MSG_COLOR1);
define(-1,10,30,1,1,0,label,texty[238]);
define(10,150,30,100,13,0,input_line,8,0,0,"");property(def_border(5,BAR_COLOR),NULL,NULL,0);set_default("");
define(10,150,30,100,13,0,input_line,7,0,0,"");property(def_border(5,BAR_COLOR),NULL,NULL,0);set_default("");
on_control_event(smlouvat_enter);
define(20,20,20,80,20,2,button,texty[239]);property(def_border(5,BAR_COLOR),NULL,NULL,BAR_COLOR);on_control_change(terminate_gui);
define(30,110,20,80,20,2,button,texty[230]);property(def_border(5,BAR_COLOR),NULL,NULL,BAR_COLOR);on_control_change(terminate_gui);

View file

@ -432,7 +432,7 @@ void draw_placed_items_normal(int celx,int cely,int sect,int side)
}
}
int count_items_total(short *place)
int count_items_total(const short *place)
{
int c=0;
@ -441,7 +441,7 @@ int count_items_total(short *place)
return c;
}
int count_items_visible(short *place)
int count_items_visible(const short *place)
{
int c=0;
@ -455,7 +455,7 @@ int count_items_visible(short *place)
}
int count_items_inside(short *place)
int count_items_inside(const short *place)
{
int c=1;
@ -479,43 +479,37 @@ int find_item(short *place,int mask)
return lastitem;
}
static int lastsector;
static char ValidateSector(word sector, void *_)
{
int pp=map_sectors[sector].sector_type;
if (pp==S_NORMAL || pp==S_SMER || pp==S_LEAVE || pp==S_FLT_SMER)
{
lastsector=sector;
return 1;
}
return 0;
void push_to_destroyed_items(const short *picked_items) {
int new_count = count_items_total(picked_items);
if (new_count == 0) return;
int cur_destroyed = count_items_total(destroyed_items);
short *nw = NewArr(short, new_count+cur_destroyed+1);
for (int i = 0; i < new_count; ++i) {
nw[i] = abs(picked_items[i]);
}
for (int i = 0; i < cur_destroyed; ++i) {
nw[new_count+i] = destroyed_items[i];
}
nw[new_count+cur_destroyed] = 0;
free(destroyed_items);
destroyed_items = nw;
}
void push_item(int sect,int pos,short *picked_item)
void push_item(int sect,int pos,const short *picked_item)
{
int bc;
int pc;
int tc;
short *p;
char s = map_sectors[sect].sector_type;
if (map_sectors[sect].sector_type==S_DIRA || ISTELEPORTSECT(sect))
if (s==S_DIRA || ISTELEPORTSECT(sect) || s == S_SCHODY)
sect=map_sectors[sect].sector_tag;
if (sect==0 || map_sectors[sect].sector_type==S_VODA)
{
if (game_extras & EX_RECOVER_DESTROYED_ITEMS)
{
labyrinth_find_path(viewsector,65535,SD_PLAY_IMPS,ValidateSector,NULL, NULL);
push_item(lastsector,viewdir,picked_item);
return;
}
else
{
free(picked_item);
picked_item=NULL;
return;
}
}
if (sect==0 || s==S_VODA || s == S_LAVA || s == S_SSMRT || s == S_LODKA) {
push_to_destroyed_items(picked_item);
return;
}
sect=(sect<<2)+pos;
bc=count_items_total(map_items[sect]);
pc=count_items_total(picked_item);
@ -682,7 +676,7 @@ char pick_item_(int id,int xa,int ya,int xr,int yr)
idd=(id+viewdir)&0x3;
if (picked_item!=NULL)
{
if (map_sectors[sect].sector_type==S_DIRA)
if (map_sectors[sect].sector_type==S_DIRA)
{
throw_fly(xa,ya,0);
letici_veci->speed=0;
@ -2494,7 +2488,6 @@ static int shop_sector;
T_CLK_MAP clk_shop[]=
{
{-1,54,378,497,479,shop_change_player,2+8,-1},
{-1,0,0,639,479,_exit_shop,8,-1},
{-1,INV_X,INV_Y,INV_X+INV_XS*6,INV_Y+INV_YS*5,shop_bag_click,MS_EVENT_MOUSE_LPRESS,-1},
{1,2+BUYBOX_X,39+BUYBOX_Y,22+BUYBOX_X,76+BUYBOX_Y,shop_block_click,2,H_MS_DEFAULT},
{2,246+BUYBOX_X,39+BUYBOX_Y,266+BUYBOX_X,76+BUYBOX_Y,shop_block_click,2,H_MS_DEFAULT},
@ -2503,6 +2496,7 @@ T_CLK_MAP clk_shop[]=
{-1,337,0,357,14,go_map,2,H_MS_DEFAULT},
{-1,87,0,142,14,game_setup,2,H_MS_DEFAULT},
{-1,30,0,85,14,konec,2,H_MS_DEFAULT},
{-1,0,0,639,479,_exit_shop,8,-1},
};
static void shop_mouse_event(EVENT_MSG *msg,void **unused)

View file

@ -20,6 +20,7 @@
#include "ach_events.h"
#include "lang.h"
#include <version.h>
#define MUSIC "TRACK06.MUS"
@ -334,6 +335,12 @@ static void klavesnice(EVENT_MSG *msg,void **unused)
}
}
static void show_version() {
const char *verstr = "Version: " SKELDAL_VERSION;
set_font(H_FLITT5, RGB888(255,255,255));
set_aligned_position(639, 479, 2, 2, verstr);
outtext(verstr);
}
int enter_menu(char open)
{
@ -350,8 +357,9 @@ int enter_menu(char open)
put_picture(0,0,ablock(H_MENU_BAR));
put_picture(0,56,ablock(H_ANIM));
ukaz_mysku();
effect_show(NULL);
//if (open) effect_show(NULL);else showview(0,0,0,0);
show_version();
effect_show();
change_click_map(clk_main_menu,CLK_MAIN_MENU);
send_message(E_ADD,E_TIMER,prehraj_animaci_v_menu);
send_message(E_ADD,E_KEYBOARD,klavesnice);
@ -552,7 +560,7 @@ void titles(va_list args)
alock(H_PICTURE);
picture=ablock(H_PICTURE);
put_picture(0,0,picture);
effect_show(NULL);
effect_show();
titlefont=H_FBIG;
set_font(titlefont,RGB(158,210,25));charcolors[1]=0;
counter=get_timer_value();newc=counter;
@ -604,7 +612,7 @@ void titles(va_list args)
if (send_back)send_message(E_KEYBOARD,27);
}
void run_titles(va_list args)
void run_titles(void)
{
int task_id;
task_id=add_task(8196,titles,1,"titulky.TXT");
@ -612,16 +620,16 @@ void run_titles(va_list args)
term_task(task_id);
}
void konec_hry()
void konec_hry(void)
{
int task_id;
int timer;
schovej_mysku();
curcolor=0;
bar32(0,0,639,479);
effect_show(NULL);
effect_show();
create_playlist(texty[205]);
change_music(get_next_music_from_playlist());
timer=get_timer_value();
@ -641,7 +649,7 @@ void konec_hry()
curcolor=0;
bar32(0,0,639,479);
ukaz_mysku();
effect_show(NULL);
effect_show();
timer=get_timer_value();
while (get_timer_value()-timer<150) task_sleep();
}

View file

@ -62,7 +62,8 @@ TSTENA *map_sides;
TSECTOR *map_sectors;
TVYKLENEK *map_vyk; //mapa vyklenku
word vyk_max; //pocet vyklenku v mape
short **map_items;
short **map_items = 0;
short *destroyed_items = 0;;
char *flag_map;
TMAP_EDIT_INFO *map_coord;
TSTR_LIST level_texts;

View file

@ -44,7 +44,7 @@ static void checkbox_animator(THE_TIMER *t)
animate_checkbox(10,130,10);
}
static int effects[]={SND_GVOLUME,SND_MUSIC,SND_GFX,SND_TREBL,SND_BASS,SND_XBASS};
static int effects[]={SND_GVOLUME,SND_MUSIC,SND_GFX,SND_TREBL,SND_BASS};
static void do_setup_change(void)
{
@ -55,6 +55,7 @@ static void do_setup_change(void)
{
case 10:set_snd_effect(SND_SWAP,c & 1);break;
case 20:set_snd_effect(SND_OUTFILTER,c & 1);break;
case 250:timerspeed_val = TIMERSPEED- c;break;
default:set_snd_effect(effects[o_aktual->id/10-20],c);break;
}
}
@ -111,7 +112,7 @@ static void unwire_setup(void)
enable_sort=f_get_value(0,100) & 1;
autoattack=f_get_value(0,110) & 1;
autosave_enabled=f_get_value(0,120) & 1;
level_preload=f_get_value(0,130) & 1;
gamespeedbattle=(f_get_value(0,130) & 1)?GAMESPEED_FASTBATTLE:gamespeed;
delete_from_timer(TM_CHECKBOX);
mix_back_sound(32768);
close_current();
@ -187,8 +188,8 @@ void new_setup()
case 0:c_default(show_names);break;
case 1:c_default(enable_sort);break;
case 2:c_default(autoattack);break;
case 3:c_default(1);break;
case 4:c_default(level_preload);break;
case 3:c_default(autosave_enabled);break;
case 4:c_default(gamespeedbattle < gamespeed);break;
}
}
@ -201,6 +202,9 @@ void new_setup()
define(200+i*10,50+i*60,30,30,200,0,skeldal_soupak,effects[i]==SND_MUSIC?127:255);c_default(get_snd_effect(effects[i]));
on_control_change(do_setup_change);
}
define(200+5*10,50+5*60,30,30,200,0,skeldal_soupak,TIMERSPEED-1);c_default(timerspeed_val >TIMERSPEED?0:TIMERSPEED - timerspeed_val);
on_control_change(do_setup_change);
define(300,559,336,81,21,0,setup_ok_button,texty[174]);on_control_change(exit_setup_action);
property(NULL,ablock(H_FTINY),&color_topbar,0);
redraw_window();

View file

@ -75,12 +75,13 @@ typedef struct inis
THE_TIMER timer_tree;
int hl_ptr=H_FIRST_FREE;
int debug_enabled=0;
char sound_detection=1;
int snd_devnum,snd_parm1,snd_parm2,snd_parm3,snd_mixing=22000;
char gamespeed=5;
char gamespeedbattle=0;
uint8_t gamespeed=GAMESPEED;
uint8_t gamespeedbattle=GAMESPEED;
char level_preload=1;
char *level_fname=NULL;
int game_extras=0;
@ -827,6 +828,8 @@ void cti_texty(void)
//patch stringtable
if (!texty[98]) str_replace(&texty,98,"Ulo\x91it hru jako");
if (!texty[99]) str_replace(&texty,99,"CRT Filter (>720p)");
str_replace(&texty, 144, "Zrychlit souboje");
str_replace(&texty, 51, "Celkov\x88 Hudba Efekty V\x98\xA8ky Basy Rychlost");
str_replace(&texty,0,"Byl nalezen p\xA9ipojen\x98 ovlada\x87\nPro aktivaci ovlada\x87""e stiskn\x88te kter\x82koliv tla\x87\xA1tko na ovlada\x87i");
lang_patch_stringtable(&texty, "ui.csv", "");
}
@ -1622,7 +1625,7 @@ static void start(va_list args)
openning =0;
break;
case V_OBNOVA_HRY:load_saved_game();break;
case V_AUTORI:run_titles(NULL);break;
case V_AUTORI:run_titles();break;
}
}
while (!exit_wait);

View file

@ -678,6 +678,7 @@ void zacatek_kola()
viewsector=postavy[select_player].sektor;
viewdir=postavy[select_player].direction;
redraw_scene();
recalc_volumes(viewsector,viewdir);
}
char check_end_game()
@ -878,7 +879,7 @@ char JePozdrzeno()
void pozdrz_akci()
{
int battlespeed=gamespeed-gamespeed*gamespeedbattle/5;
int battlespeed=gamespeedbattle;
SPozdrzeno=get_game_tick_count()+battlespeed*2000/6;
}
@ -905,6 +906,7 @@ void prejdi_na_pohled(THUMAN *p)
{
viewsector=p->sektor;
viewdir=p->direction;
recalc_volumes(viewsector,viewdir);
pozdrz_akci();
hold_timer(TM_SCENE,1);
redraw_scene();
@ -1144,7 +1146,7 @@ static void pouzij_svitek(THUMAN *p,int ruka)
static void play_weapon_anim(int anim_num,int hitpos)
{
char count_save=global_anim_counter;
int battlespeed=gamespeed-gamespeed*gamespeedbattle/5;
int battlespeed=gamespeedbattle;
if (anim_num==0) return;
hold_timer(TM_SCENE,1);
@ -1440,6 +1442,7 @@ void jadro_souboje(EVENT_MSG *msg,void **unused) //!!!! Jadro souboje
viewsector=postavy[i].sektor;
viewdir=postavy[i].direction;
build_player_map();
recalc_volumes(viewsector,viewdir);
GlobEvent(MAGLOB_AFTERBATTLE,viewsector,viewdir);
autosave();
}
@ -1450,7 +1453,7 @@ void jadro_souboje(EVENT_MSG *msg,void **unused) //!!!! Jadro souboje
void wire_jadro_souboje(void)
{
int battlespeed=gamespeed-gamespeed*gamespeedbattle/5;
int battlespeed=gamespeedbattle;
recalc_volumes(viewsector,viewdir);
if (battlespeed<1) battlespeed=1;
add_to_timer(TM_SCENE,battlespeed,-1,hrat_souboj);
@ -1924,6 +1927,7 @@ static void souboje_dalsi()
while ((!postavy[select_player].used || postavy[select_player].inmaphash != current_map_hash || !postavy[select_player].actions || (postavy[select_player].groupnum!=cd && j>6)) && j);
viewsector=postavy[select_player].sektor;
viewdir=postavy[select_player].direction;
recalc_volumes(viewsector,viewdir);
cur_group=postavy[select_player].groupnum;
}
@ -1944,6 +1948,7 @@ static void souboje_dalsi_user() {
viewsector=postavy[select_player].sektor;
viewdir=postavy[select_player].direction;
cur_group=postavy[select_player].groupnum;
recalc_volumes(viewsector,viewdir);
}
void souboje_vybrano(int d)

View file

@ -45,7 +45,7 @@ To activate the controller, press any button on the controller"
48,Start
49,Throw
50,Combat in Progress
51,Overall Music Sounds Treble Bass
51,Overall Music Sounds Treble Bass Speed
52,Stereo Settings (Ultrasound)
53,Swap Sides
54,Output Filter (SBPro)
@ -117,7 +117,7 @@ To activate the controller, press any button on the controller"
141,Rearrange Portraits
142,Auto Attack
143,Auto Save
144,Load All Into Memory
144,Speed up battles
145,Adventure Length:
146,%d day and
147,%d days and

1 id string
45 49 Throw
46 50 Combat in Progress
47 51 Overall Music Sounds Treble Bass Overall Music Sounds Treble Bass Speed
48 52 Stereo Settings (Ultrasound)
49 53 Swap Sides
50 54 Output Filter (SBPro)
51 55 Walking
117 142 Auto Attack
118 143 Auto Save
119 144 Load All Into Memory Speed up battles
120 145 Adventure Length:
121 146 %d day and
122 147 %d days and
123 148 %d days and

View file

@ -12,7 +12,7 @@ SET(files basicobj.c
mgifplaya.c
pcx.c
wav_mem.c
strlists.c
strlite.c
cztable.c
music.cpp
string_table.cpp )

View file

@ -95,9 +95,10 @@ elseif(APPLE)
target_sources(skeldal PRIVATE
linux/app_start.cpp
)
target_compile_definitions(mylib PRIVATE PLATFORM_MACOS)
set(STEAMLIB ${STEAMWORKS_SDK_DIR}/redistributable_bin/osx/libsteam_api.dylib)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations")
if(STEAM_ENABLED)
set(STEAMLIB ${STEAMWORKS_SDK_DIR}/redistributable_bin/osx/libsteam_api.dylib)
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations")
message(STATUS "Building for macOS")
target_link_libraries(skeldal ${all_libs} ${STEAMLIB})
else()

View file

@ -4,6 +4,7 @@
#include <cstdarg>
#include <cstdint>
#include <iostream>
#include <sstream>
#include "error.h"
#include "platform.h"
@ -38,3 +39,18 @@ void send_log_impl(const char *format, ...) {
void throw_exception(const char *text) {
throw std::runtime_error(std::string("Invoked crash:") + text);
}
std::string exception_to_string(const std::exception& e) {
std::ostringstream oss;
oss << e.what();
try {
std::rethrow_if_nested(e);
} catch (const std::exception& nested) {
oss << "\n\n Reason: " << exception_to_string(nested);
} catch (...) {
oss << "\n\n Reason: unknown exception of crash";
}
return std::move(oss).str();
}

View file

@ -2,6 +2,11 @@
#ifdef __cplusplus
#include <string>
#include <exception>
std::string exception_to_string(const std::exception& e);
extern "C" {
#endif
@ -10,7 +15,8 @@ void send_log_impl(const char *format, ...);
void display_error(const char *format, ...);
void throw_exception(const char *text);
#ifdef __cplusplus
}
#endif

View file

@ -7,23 +7,37 @@
#include "../libs/logfile.h"
std::filesystem::path break_and_compose_path(const std::string_view &pathname, char sep) {
std::filesystem::path break_and_compose_path(std::string_view pathname, char sep) {
auto utf8_to_path = [](std::string_view sv) -> std::filesystem::path {
return std::filesystem::path(std::u8string(reinterpret_cast<const char8_t*>(sv.data()), sv.size()));
};
auto p = pathname.rfind(sep);
if (p == pathname.npos) {
if (pathname == "." || pathname == "..") {
return std::filesystem::canonical(".");
} else if (pathname.empty()) {
return std::filesystem::current_path().root_path();
} else if (pathname == std::filesystem::current_path().root_name()) {
return std::filesystem::current_path().root_path();
} else {
return std::filesystem::current_path()/pathname;
}
}
return break_and_compose_path(pathname.substr(0,p), sep) / pathname.substr(p+1);
}
// Detekce Windows drive letter jako "C:"
if (pathname.size() == 2 && std::isalpha(static_cast<unsigned char>(pathname[0])) && pathname[1] == ':') {
return utf8_to_path(std::string(pathname) + "\\"); // vždy konstruujeme s \ pro root disku
}
// Kontrola na root (např. "/") musíme převést pro porovnání
if (utf8_to_path(pathname) == std::filesystem::current_path().root_path()) {
return std::filesystem::current_path().root_path();
}
// Vše ostatní relativně vůči current_path
return std::filesystem::current_path() / utf8_to_path(pathname);
} else if (p == 0) {
return std::filesystem::current_path().root_path() / utf8_to_path(pathname);
}
return break_and_compose_path(pathname.substr(0, p), sep) / utf8_to_path(pathname.substr(p + 1));
}
std::filesystem::path convert_pathname_to_path(const std::string_view &pathname) {
auto p = pathname.find('\\');
@ -81,7 +95,12 @@ const char *file_icase_find(const char *pathname) {
FILE *fopen_icase(const char *pathname, const char *mode) {
std::filesystem::path path = try_to_find_file(convert_pathname_to_path(pathname));
#ifdef _WIN32
std::wstring wmode(mode, mode + std::strlen(mode)); // bezpečnější převod
return _wfopen(path.wstring().c_str(), wmode.c_str());
#else
return fopen(path.string().c_str(), mode);
#endif
}
static thread_local std::string build_pathname_buffer;

View file

@ -1,6 +1,7 @@
#include "../../game/skeldal.h"
#include "../getopt.h"
#include "../platform.h"
#include "../error.h"
#include <iostream>
#include <string>
@ -67,7 +68,7 @@ int main(int argc, char **argv) {
}
} catch (const std::exception &e) {
std::cerr << "ERROR: " << e.what() << std::endl;
std::cerr << "ERROR: " << exception_to_string(e) << std::endl;
return 1;
}

View file

@ -1,9 +1,7 @@
extern "C" {
#include "map_file.h"
#include "../error.h"
}
#include <stdio.h>
#include <stdlib.h>

View file

@ -1,4 +1,13 @@
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
void *map_file_to_memory(const char *name, size_t *sz);
void unmap_file(void *ptr, size_t sz);
#ifdef __cplusplus
}
#endif

View file

@ -2,6 +2,7 @@
temp_file=$(mktemp /tmp/skeldal.XXXXXX.log)
CURDIR=`dirname "$0"`
chmod +x "$CURDIR/skeldal_bin"
LD_LIBRARY_PATH=$CURDIR:$LD_LIBRARY_PATH "$CURDIR/skeldal_bin" $* > "$temp_file" 2>&1
exit_code=$?
@ -25,4 +26,3 @@ fi
rm $temp_file
exit $exit_code

View file

@ -1,2 +1,6 @@
#include <string.h>
#include <malloc.h>
#if defined(__linux__)
#include <malloc.h>
#elif defined(__APPLE__)
#include <stdlib.h>
#endif

View file

@ -0,0 +1,184 @@
#pragma once
#include <SDL_surface.h>
template<Uint32 format>
struct FormatMapping {
static_assert(false, "Unsupported pixel format");
};
template<>
struct FormatMapping<SDL_PIXELFORMAT_ARGB2101010> {
static constexpr int RShift = 20;
static constexpr int GShift = 10;
static constexpr int BShift = 0;
static constexpr int AShift = 30;
static constexpr int RBits = 10;
static constexpr int GBits = 10;
static constexpr int BBits = 10;
static constexpr int ABits = 2;
};
template<>
struct FormatMapping<SDL_PIXELFORMAT_ABGR8888> {
static constexpr int RShift = 0;
static constexpr int GShift = 8;
static constexpr int BShift = 16;
static constexpr int AShift = 24;
static constexpr int RBits = 8;
static constexpr int GBits = 8;
static constexpr int BBits = 8;
static constexpr int ABits = 8;
};
template<>
struct FormatMapping<SDL_PIXELFORMAT_ARGB8888> {
static constexpr int RShift = 16;
static constexpr int GShift = 8;
static constexpr int BShift = 0;
static constexpr int AShift = 24;
static constexpr int RBits = 8;
static constexpr int GBits = 8;
static constexpr int BBits = 8;
static constexpr int ABits = 8;
};
template<>
struct FormatMapping<SDL_PIXELFORMAT_RGBA8888> {
static constexpr int RShift = 24;
static constexpr int GShift = 16;
static constexpr int BShift = 8;
static constexpr int AShift = 0;
static constexpr int RBits = 8;
static constexpr int GBits = 8;
static constexpr int BBits = 8;
static constexpr int ABits = 8;
};
template<>
struct FormatMapping<SDL_PIXELFORMAT_BGRA8888> {
static constexpr int RShift = 8;
static constexpr int GShift = 16;
static constexpr int BShift = 24;
static constexpr int AShift = 0;
static constexpr int RBits = 8;
static constexpr int GBits = 8;
static constexpr int BBits = 8;
static constexpr int ABits = 8;
};
template<>
struct FormatMapping<SDL_PIXELFORMAT_ABGR4444> {
static constexpr int RShift = 0;
static constexpr int GShift = 4;
static constexpr int BShift = 8;
static constexpr int AShift = 12;
static constexpr int RBits = 4;
static constexpr int GBits = 4;
static constexpr int BBits = 4;
static constexpr int ABits = 4;
};
template<>
struct FormatMapping<SDL_PIXELFORMAT_ARGB4444> {
static constexpr int RShift = 8;
static constexpr int GShift = 4;
static constexpr int BShift = 0;
static constexpr int AShift = 12;
static constexpr int RBits = 4;
static constexpr int GBits = 4;
static constexpr int BBits = 4;
static constexpr int ABits = 4;
};
template<>
struct FormatMapping<SDL_PIXELFORMAT_RGBA4444> {
static constexpr int RShift = 12;
static constexpr int GShift = 8;
static constexpr int BShift = 4;
static constexpr int AShift = 0;
static constexpr int RBits = 4;
static constexpr int GBits = 4;
static constexpr int BBits = 4;
static constexpr int ABits = 4;
};
template<>
struct FormatMapping<SDL_PIXELFORMAT_BGRA4444> {
static constexpr int RShift = 4;
static constexpr int GShift = 8;
static constexpr int BShift = 12;
static constexpr int AShift = 0;
static constexpr int RBits = 4;
static constexpr int GBits = 4;
static constexpr int BBits = 4;
static constexpr int ABits = 4;
};
template<>
struct FormatMapping<SDL_PIXELFORMAT_ABGR1555> {
static constexpr int RShift = 0;
static constexpr int GShift = 5;
static constexpr int BShift = 10;
static constexpr int AShift = 15;
static constexpr int RBits = 5;
static constexpr int GBits = 5;
static constexpr int BBits = 5;
static constexpr int ABits = 1;
};
template<>
struct FormatMapping<SDL_PIXELFORMAT_ARGB1555> {
static constexpr int RShift = 10;
static constexpr int GShift = 5;
static constexpr int BShift = 0;
static constexpr int AShift = 15;
static constexpr int RBits = 5;
static constexpr int GBits = 5;
static constexpr int BBits = 5;
static constexpr int ABits = 1;
};
template<>
struct FormatMapping<SDL_PIXELFORMAT_RGBA5551> {
static constexpr int RShift = 11;
static constexpr int GShift = 6;
static constexpr int BShift = 1;
static constexpr int AShift = 0;
static constexpr int RBits = 5;
static constexpr int GBits = 5;
static constexpr int BBits = 5;
static constexpr int ABits = 1;
};
template<>
struct FormatMapping<SDL_PIXELFORMAT_BGRA5551> {
static constexpr int RShift = 1;
static constexpr int GShift = 6;
static constexpr int BShift = 11;
static constexpr int AShift = 0;
static constexpr int RBits = 5;
static constexpr int GBits = 5;
static constexpr int BBits = 5;
static constexpr int ABits = 1;
};

View file

@ -1,9 +1,11 @@
#include "sdl_context.h"
#include "keyboard_map.h"
#include "format_mapping.h"
#include <atomic>
#include <cassert>
#include "../platform.h"
#include "../error.h"
#include <cmath>
#include <iostream>
@ -34,6 +36,9 @@ void SDLContext::SDL_Deleter::operator ()(SDL_Surface* surface) {
void SDLContext::SDL_Deleter::operator ()(SDL_Texture* texture) {
SDL_DestroyTexture(texture);
}
void SDLContext::SDL_Deleter::operator ()(SDL_PixelFormat* f) {
SDL_FreeFormat(f);
}
void SDLContext::SDL_Audio_Deleter::operator()(SDL_AudioDeviceID x) {
SDL_CloseAudioDevice(x);
@ -74,10 +79,24 @@ SDLContext::SDLContext() {
void handle_sdl_error(const char *msg) {
char buff[512];
snprintf(buff, sizeof(buff), "SDL critical error (check video driver): %s %s",msg, SDL_GetError());
snprintf(buff, sizeof(buff), "SDL critical error: %s %s",msg, SDL_GetError());
throw std::runtime_error(buff);
}
bool isFormatSupported(SDL_Renderer *renderer, Uint32 pixel_format) {
SDL_RendererInfo info;
if (SDL_GetRendererInfo(renderer, &info) != 0) {
handle_sdl_error("Failed to get renderer info");
return false;
}
for (Uint32 i = 0; i < info.num_texture_formats; ++i) {
if (info.texture_formats[i] == pixel_format) {
return true;
}
}
return false;
}
void SDLContext::generateCRTTexture(SDL_Renderer* renderer, SDL_Texture** texture, int width, int height, CrtFilterType type) {
@ -95,6 +114,8 @@ void SDLContext::generateCRTTexture(SDL_Renderer* renderer, SDL_Texture** textur
default: break;
}
if (type == CrtFilterType::scanlines || type == CrtFilterType::scanlines_2) {
width = 32;
} else {
@ -105,8 +126,11 @@ void SDLContext::generateCRTTexture(SDL_Renderer* renderer, SDL_Texture** textur
unsigned int mult_of_base = std::max<unsigned int>((height+240)/480,interfer);
height = height * interfer / mult_of_base;
}
// Vytvoř novou texturu ve správné velikosti
*texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, width, height);
*texture = SDL_CreateTexture(renderer, _texture_render_format, SDL_TEXTUREACCESS_STREAMING, width, height);
if (!*texture) {
type = CrtFilterType::none;
return; //crt filter failed to create, do not use filter
@ -126,10 +150,12 @@ void SDLContext::generateCRTTexture(SDL_Renderer* renderer, SDL_Texture** textur
Uint32* pixelArray = (Uint32*)pixels;
if (type == CrtFilterType::scanlines) {
Uint32 darkPixel = 0xA0A0A0FF;
Uint32 transparentPixel = 0xFFFFFFC0;
Uint32 darkPixel = SDL_MapRGBA(_main_pixel_format.get(), 0xA0, 0xA0, 0xA0, 0xFF);
Uint32 transparentPixel = SDL_MapRGBA(_main_pixel_format.get(), 0xFF, 0xFF, 0xFF, 0xC0);
for (int y = 0; y < height; y++) {
Uint32 color = ((y & 1)== 0) ? darkPixel : transparentPixel;
@ -141,8 +167,8 @@ void SDLContext::generateCRTTexture(SDL_Renderer* renderer, SDL_Texture** textur
else if (type == CrtFilterType::scanlines_2) {
Uint32 darkPixel = 0x808080FF;
Uint32 transparentPixel = 0xFFFFFFE0;
Uint32 darkPixel = SDL_MapRGBA(_main_pixel_format.get(), 0x80, 0x80, 0x80, 0xFF);
Uint32 transparentPixel = SDL_MapRGBA(_main_pixel_format.get(), 0xFF, 0xFF, 0xFF, 0xE0);
for (int y = 0; y < height; y++) {
Uint32 color = (y % 3== 2) ? darkPixel : transparentPixel;
@ -152,10 +178,10 @@ void SDLContext::generateCRTTexture(SDL_Renderer* renderer, SDL_Texture** textur
}
} else {
static Uint32 red_pixel = 0xFF8080A0;
static Uint32 green_pixel = 0x80FF80A0;
static Uint32 blue_pixel = 0x8080FFA0;
static Uint32 dark_pixel = 0x000000C0;
static Uint32 red_pixel = SDL_MapRGBA(_main_pixel_format.get(), 0xFF, 0x80, 0x80, 0xA0);
static Uint32 green_pixel = SDL_MapRGBA(_main_pixel_format.get(), 0x80, 0xFF, 0x80, 0xA0);
static Uint32 blue_pixel = SDL_MapRGBA(_main_pixel_format.get(), 0x80, 0x80, 0xFF, 0xA0);
static Uint32 dark_pixel = SDL_MapRGBA(_main_pixel_format.get(), 0x0, 0x0, 0x00, 0xA0);
for (int y = 2; y < height; y++) {
if (type == CrtFilterType::rgb_matrix_2) {
for (int x = 2; x < width; x+=3) {
@ -199,6 +225,48 @@ static void crash_sdl_exception() {
abort();
}
// Seznam akceptovatelných formátů odpovídajících RGBA8888 (v různém pořadí)
constexpr Uint32 acceptable_formats[] = {
SDL_PIXELFORMAT_RGBA8888,
SDL_PIXELFORMAT_ARGB8888,
SDL_PIXELFORMAT_BGRA8888,
SDL_PIXELFORMAT_ABGR8888,
SDL_PIXELFORMAT_RGBA4444,
SDL_PIXELFORMAT_ARGB4444,
SDL_PIXELFORMAT_BGRA4444,
SDL_PIXELFORMAT_ABGR4444,
SDL_PIXELFORMAT_ARGB2101010,
};
constexpr bool is_acceptable_format(Uint32 format) {
for (size_t i = 0; i < sizeof(acceptable_formats)/sizeof(acceptable_formats[0]); ++i) {
if (format == acceptable_formats[i]) {
return true;
}
}
return false;
}
static Uint32 find_best_rgba_like_format(SDL_Renderer* renderer) {
SDL_RendererInfo info;
if (SDL_GetRendererInfo(renderer, &info) != 0) {
return 0;
}
if ((info.max_texture_width != 0 && info.max_texture_width < 640) ||
(info.max_texture_height!= 0 && info.max_texture_height < 480)) return 0;
for (Uint32 i = 0; i < info.num_texture_formats; ++i) {
Uint32 fmt = info.texture_formats[i];
if (is_acceptable_format(fmt)) {
return fmt;
}
}
return 0;
}
void SDLContext::init_video(const VideoConfig &config, const char *title) {
static Uint32 update_request_event = SDL_RegisterEvents(1);
@ -219,15 +287,17 @@ void SDLContext::init_video(const VideoConfig &config, const char *title) {
_enable_crt = false;
}
_fullscreen_mode = config.fullscreen;
_mouse_size = config.cursor_size;
std::atomic<bool> done = false;
std::exception_ptr e;
std::string_view stage;
std::string rname;
_render_thread = std::jthread([&](std::stop_token stp){
bool err = false;
try {
stage = "window";
SDL_Window *window = SDL_CreateWindow(title,
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
width, height, SDL_WINDOW_RESIZABLE|(_fullscreen_mode?SDL_WINDOW_FULLSCREEN_DESKTOP:0));
@ -237,13 +307,49 @@ void SDLContext::init_video(const VideoConfig &config, const char *title) {
}
_window.reset(window);
SDL_Renderer *renderer = SDL_CreateRenderer(_window.get(), -1, config.composer);
if (!renderer) {
handle_sdl_error("Failed to create composer");
auto composer = config.composer;
stage = "renderer";
while (true) {
SDL_Renderer *renderer = SDL_CreateRenderer(_window.get(), -1, composer);
if (!renderer) {
if (config.composer & SDL_RENDERER_SOFTWARE) {
handle_sdl_error("Failed to create composer");
} else {
composer |= SDL_RENDERER_SOFTWARE;
continue;
}
}
_texture_render_format = find_best_rgba_like_format(renderer);
if (_texture_render_format == 0) {
if (composer & SDL_RENDERER_SOFTWARE) {
throw std::runtime_error("Failed to create composer, failed software fallback");
} else {
SDL_DestroyRenderer(renderer);
composer |= SDL_RENDERER_SOFTWARE;
continue;
}
}
_renderer.reset(renderer);
break;
}
SDL_RendererInfo rinfo;
SDL_GetRendererInfo(renderer, &rinfo);
SDL_GetRendererInfo(_renderer.get(), &rinfo);
rname = rinfo.name;
stage = "pixel format";
_main_pixel_format.reset(SDL_AllocFormat(_texture_render_format));
if (!_main_pixel_format) {
handle_sdl_error("Failed to create texture format");
}
if (istrcmp(config.scale_quality, "auto") == 0) {
if (rinfo.flags & SDL_RENDERER_ACCELERATED) {
@ -253,20 +359,30 @@ void SDLContext::init_video(const VideoConfig &config, const char *title) {
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, config.scale_quality);
}
_renderer.reset(renderer);
SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB1555, SDL_TEXTUREACCESS_STREAMING, 640, 480);
stage = "main render target";
SDL_Texture *texture = SDL_CreateTexture(_renderer.get(), _texture_render_format, SDL_TEXTUREACCESS_STREAMING, 640, 480);
if (!texture) {
handle_sdl_error("Failed to create render target");
}
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
_texture.reset(texture);
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB1555, SDL_TEXTUREACCESS_STREAMING, 640, 480);
stage = "secondary render target";
texture = SDL_CreateTexture(_renderer.get(), _texture_render_format, SDL_TEXTUREACCESS_STREAMING, 640, 480);
if (!texture) {
handle_sdl_error("Failed to create second render target");
}
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
_texture2.reset(texture);
stage = "all done";
_visible_texture = _texture.get();
_hidden_texture = _texture2.get();
} catch (...) {
@ -294,7 +410,17 @@ void SDLContext::init_video(const VideoConfig &config, const char *title) {
done.wait(false);
if (e) {
_render_thread.join();
std::rethrow_exception(e);
try {
std::rethrow_exception(e);
} catch (...) {
std::throw_with_nested(
std::runtime_error(std::string("Oops! The application couldn't start properly (problem during SDL initialization). Stage: [")
.append(stage).append("]\n\n"
"Renderer: ").append(rname).append("\n\n"
"This may be caused by outdated or missing graphics or audio drivers."
"To fix this, please try the following:\n- Restart your computer and try again\n- "
"Make sure your graphics and sound drivers are up to date.")));
}
}
@ -335,6 +461,102 @@ int SDLContext::adjust_deadzone(int v, short deadzone) {
return 0;
}
template<int shift>
constexpr Uint32 shift_bits_5(Uint32 val) {
if constexpr(shift > 0) {
return val << shift | shift_bits_5<shift-5>(val);
} else if constexpr(shift < 0) {
return val >> (-shift);
} else {
return val;
}
}
template<Uint32 pixel_format>
void SDLContext::convert_bitmap(const void *pixels, SDL_Rect rect, int pitch) {
constexpr auto RShift = FormatMapping<pixel_format>::RShift;
constexpr auto GShift = FormatMapping<pixel_format>::GShift;
constexpr auto BShift = FormatMapping<pixel_format>::BShift;
constexpr auto AShift = FormatMapping<pixel_format>::AShift;
constexpr auto RBits = FormatMapping<pixel_format>::RBits;
constexpr auto GBits = FormatMapping<pixel_format>::GBits;
constexpr auto BBits = FormatMapping<pixel_format>::BBits;
constexpr auto ABits = FormatMapping<pixel_format>::ABits;
const Uint16 *src = static_cast<const Uint16*>(pixels);
auto trg = converted_pixels.data();
for (int y = 0; y < rect.h; ++y) {
for (int x = 0; x < rect.w; ++x) {
Uint16 pixel = src[x];
Uint32 a = (pixel & 0x8000) ? 0 : 0x1F;
Uint32 r = ((pixel >> 10) & 0x1F);
Uint32 g = ((pixel >> 5) & 0x1F);
Uint32 b = (pixel & 0x1F);
r = shift_bits_5<RBits-5>(r);
g = shift_bits_5<GBits-5>(g);
b = shift_bits_5<BBits-5>(b);
a = shift_bits_5<ABits-5>(a);
trg[x] = (r << RShift) | (g << GShift) | (b << BShift) | (a << AShift);
}
trg += rect.w;
src = src + pitch / 2;
}
}
void SDLContext::update_texture_with_conversion(SDL_Texture *texture, const SDL_Rect *rect, const void *pixels, int pitch)
{
SDL_Rect r;
if (rect) {
r = *rect;
} else {
SDL_QueryTexture(texture, nullptr, nullptr, &r.w, &r.h);
r.x = 0;
r.y = 0;
}
converted_pixels.clear();
converted_pixels.resize(r.w * r.h);
switch (_texture_render_format) {
case SDL_PIXELFORMAT_ABGR8888:
convert_bitmap<SDL_PIXELFORMAT_ABGR8888>(pixels, r, pitch);break;
case SDL_PIXELFORMAT_ARGB8888:
convert_bitmap<SDL_PIXELFORMAT_ARGB8888>(pixels, r, pitch);break;
case SDL_PIXELFORMAT_ARGB2101010:
convert_bitmap<SDL_PIXELFORMAT_ARGB2101010>(pixels, r, pitch);break;
case SDL_PIXELFORMAT_RGBA8888:
convert_bitmap<SDL_PIXELFORMAT_RGBA8888>(pixels, r, pitch);break;
case SDL_PIXELFORMAT_BGRA8888:
convert_bitmap<SDL_PIXELFORMAT_BGRA8888>(pixels, r, pitch);break;
case SDL_PIXELFORMAT_ABGR4444:
convert_bitmap<SDL_PIXELFORMAT_ABGR4444>(pixels, r, pitch);break;
case SDL_PIXELFORMAT_ARGB4444:
convert_bitmap<SDL_PIXELFORMAT_ARGB4444>(pixels, r, pitch);break;
case SDL_PIXELFORMAT_BGRA4444:
convert_bitmap<SDL_PIXELFORMAT_BGRA4444>(pixels, r, pitch);break;
case SDL_PIXELFORMAT_RGBA4444:
convert_bitmap<SDL_PIXELFORMAT_RGBA4444>(pixels, r, pitch);break;
case SDL_PIXELFORMAT_ABGR1555:
convert_bitmap<SDL_PIXELFORMAT_ABGR1555>(pixels, r, pitch);break;
case SDL_PIXELFORMAT_ARGB1555:
convert_bitmap<SDL_PIXELFORMAT_ARGB1555>(pixels, r, pitch);break;
case SDL_PIXELFORMAT_RGBA5551:
convert_bitmap<SDL_PIXELFORMAT_RGBA5551>(pixels, r, pitch);break;
case SDL_PIXELFORMAT_BGRA5551:
convert_bitmap<SDL_PIXELFORMAT_BGRA5551>(pixels, r, pitch);break;
default:
return;
}
if (SDL_UpdateTexture(texture, &r, converted_pixels.data(), r.w * 4) < 0) {
handle_sdl_error("Failed to update texture");
}
}
static int axis_dynamic(int c) {
double f = std::floor(std::pow(std::abs(c)*0.001,2)*0.025);
@ -698,19 +920,19 @@ void SDLContext::update_screen(bool force_refresh) {
SDL_Rect r;
pop_item(iter, r);
std::string_view data = pop_data(iter, r.w*r.h*2);
if (SDL_UpdateTexture(_texture.get(), &r, data.data(), r.w*2)<0) handle_sdl_error("Update of render target failed");
update_texture_with_conversion(_texture.get(), &r, data.data(), r.w*2);
}
break;
case DisplayRequest::show_mouse_cursor: {
SDL_Rect r;
pop_item(iter, r);
std::string_view data = pop_data(iter, r.w*r.h*2);
_mouse.reset(SDL_CreateTexture(_renderer.get(), SDL_PIXELFORMAT_ARGB1555,SDL_TEXTUREACCESS_STATIC, r.w, r.h));
_mouse.reset(SDL_CreateTexture(_renderer.get(), _texture_render_format,SDL_TEXTUREACCESS_STATIC, r.w, r.h));
if (!_mouse) handle_sdl_error("Failed to create surface for mouse cursor");
SDL_SetTextureBlendMode(_mouse.get(), SDL_BLENDMODE_BLEND);
_mouse_rect.w = r.w;
_mouse_rect.h = r.h;
if (SDL_UpdateTexture(_mouse.get(), NULL, data.data(), r.w*2)<0) handle_sdl_error("Update of mouse cursor failed");
update_texture_with_conversion(_mouse.get(), NULL, data.data(), r.w*2);
}
break;
case DisplayRequest::hide_mouse_cursor: {
@ -747,10 +969,10 @@ void SDLContext::update_screen(bool force_refresh) {
if (iter == _sprites.end()) {
iter = _sprites.insert(iter,{id});
}
iter->_txtr.reset(SDL_CreateTexture(_renderer.get(), SDL_PIXELFORMAT_ARGB1555, SDL_TEXTUREACCESS_STATIC,r.w, r.h));
iter->_txtr.reset(SDL_CreateTexture(_renderer.get(), _texture_render_format, SDL_TEXTUREACCESS_STATIC,r.w, r.h));
if (!iter->_txtr) handle_sdl_error("Failed to create compositor sprite");
SDL_SetTextureBlendMode(iter->_txtr.get(), SDL_BLENDMODE_BLEND);
if (SDL_UpdateTexture(iter->_txtr.get(), NULL, data.data(), r.w*2)<0) handle_sdl_error("Update of sprite failed");
update_texture_with_conversion(iter->_txtr.get(), NULL, data.data(), r.w*2);
iter->_rect = r;
update_zindex();
} break;
@ -851,10 +1073,8 @@ void SDLContext::push_update_msg(const SDL_Rect &rc, const uint16_t *data, int p
_display_update_queue.resize(sz+rc.w*rc.h*2);
short *trg = reinterpret_cast<short *>(_display_update_queue.data()+sz);
for (int yp = 0; yp < rc.h; ++yp) {
for (int xp = 0; xp < rc.w; ++xp) {
*trg = data[xp] ^ 0x8000;
++trg;
}
std::copy(data, data+rc.w, trg);
trg += rc.w;
data += pitch;
}
}
@ -1009,7 +1229,7 @@ void put_picture_ex(unsigned short x,unsigned short y,const void *p, unsigned sh
}
void SDLContext::push_hi_image(const unsigned short *image) {
SDL_Rect rc;
SDL_Rect rc = {};
rc.w= image[0];
rc.h =image[1];
push_item(rc);
@ -1019,7 +1239,6 @@ void SDLContext::push_hi_image(const unsigned short *image) {
unsigned short *trg = reinterpret_cast<unsigned short *>(_display_update_queue.data()+sz);
std::fill(trg, trg+imgsz, 0x8000);
put_picture_ex(0, 0, image, trg, rc.w);
std::transform(trg, trg+imgsz, trg, [](unsigned short &x)->unsigned short {return x ^ 0x8000;});
}
void SDLContext::show_mouse_cursor(const unsigned short *ms_hi_format, SDL_Point finger) {

View file

@ -170,6 +170,7 @@ protected:
void operator()(SDL_Renderer *);
void operator()(SDL_Surface *);
void operator()(SDL_Texture *);
void operator()(SDL_PixelFormat* f);
};
struct BlendTransitionReq {
@ -237,13 +238,16 @@ protected:
std::unique_ptr<SDL_Texture, SDL_Deleter> _texture2;
std::unique_ptr<SDL_Texture, SDL_Deleter> _crt_effect;
std::unique_ptr<SDL_Texture, SDL_Deleter> _mouse;
std::unique_ptr<SDL_PixelFormat, SDL_Deleter> _main_pixel_format;
unique_value<SDL_AudioDeviceID, SDL_Audio_Deleter> _audio;
SDL_Texture *_visible_texture;
SDL_Texture *_hidden_texture;
SDL_Texture *_visible_texture = nullptr;
SDL_Texture *_hidden_texture = nullptr;
uint32_t _texture_render_format = SDL_PIXELFORMAT_ARGB1555;
bool _fullscreen_mode = false;
bool _present = false;
bool _convert_format = false;
std::atomic<bool> _key_control = false;
std::atomic<bool> _key_shift = false;
std::atomic<bool> _key_capslock = false;
@ -252,11 +256,12 @@ protected:
std::vector<char> _display_update_queue;
std::vector<uint32_t> converted_pixels;
using QueueIter = const char *;
std::queue<uint16_t> _keyboard_queue;
SDL_Rect _mouse_rect;
SDL_Point _mouse_finger;
float _mouse_size;
float _mouse_size = 1;
SpriteList _sprites;
@ -307,4 +312,11 @@ protected:
void generate_j_event(int button, char up);
static int adjust_deadzone(int v, short deadzone);
void update_texture_with_conversion(SDL_Texture * texture,
const SDL_Rect * rect,
const void *pixels, int pitch);
template<Uint32 pixel_format>
void convert_bitmap(const void *pixels, SDL_Rect r, int pitch);
};

View file

@ -299,7 +299,8 @@ static void update_music_volume(){
float v = music_volume * master_volume;
for (int i = 0; i <2; i++)
sound_mixer.visit_track(music_track_id_base+i,[&](WaveMixer<2> &m){
m.set_channel_volume(v, v);
m.set_channel_volume(0, v);
m.set_channel_volume(1, v);
});
}

View file

@ -91,8 +91,8 @@ public:
} else {
(*iter) += value.left * vol[0];
++iter;
(*iter) += value.right * vol[0];
++iter;
(*iter) += value.right * vol[1];
std::advance(iter, channels-1);
}
}

View file

@ -1,6 +1,7 @@
#include "../../game/skeldal.h"
#include "../getopt.h"
#include "../platform.h"
#include "../error.h"
#include <iostream>
#include <string>
#include <sstream>
@ -86,7 +87,7 @@ int main(int argc, char **argv) {
}
} catch (const std::exception &e) {
cfg.show_error(e.what());
cfg.show_error(exception_to_string(e).c_str());
return 1;
}
catch (...) {

View file

@ -15,13 +15,17 @@ std::string getSavedGamesDirectory() {
PWSTR path = nullptr;
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_SavedGames, 0, NULL, &path))) {
fs::path savedGamesPath(path);
CoTaskMemFree(path);
return (savedGamesPath / SAVEGAME_FOLDERNAME).string();
CoTaskMemFree(path);
// Převod na UTF-8 std::string
std::u8string utf8 = (savedGamesPath / SAVEGAME_FOLDERNAME).u8string();
return std::string(reinterpret_cast<const char*>(utf8.data()), utf8.size());
} else {
display_error("Failed to retrieve FOLDEROD_SavedGames");
display_error("Failed to retrieve FOLDERID_SavedGames");
abort();
}
}
const char *get_default_savegame_directory() {
static std::string dir = getSavedGamesDirectory();

View file

@ -47,6 +47,7 @@
#crt_filter=auto
#scale_quality=auto
#composer=auto
#sdl_renderer_driver=software
#aspect_ratio=4:3
#cursor_size=100

View file

@ -45,7 +45,7 @@ DDLArchive::Extracted DDLArchive::extract_file(std::ifstream &s,
std::vector<char> data;
data.resize(sz);
s.read(data.data(), sz);
if (s.gcount() != sz) return {fname, false, {}};
if (static_cast<uint32_t>(s.gcount()) != sz) return {fname, false, {}};
return {fname, true, std::move(data)};
}

5
version.in.h Normal file
View file

@ -0,0 +1,5 @@
#pragma once
#define SKELDAL_VERSION "@APP_VERSION@"