more controller support and fix some crashes

This commit is contained in:
Ondřej Novák 2025-03-04 12:07:40 +01:00
parent 3f946405b9
commit 0e251dcd05
19 changed files with 608 additions and 195 deletions

View file

@ -44,6 +44,32 @@ A script error in the White Tower map in the puzzle located on the top floor of
This fix will only work with the new code. (It will not work in earlier releases of the game, i.e. in the DOS, Windows, Android and iOS versions). The reason is that a new scripting action has been introduced to enable this fix, which will ensure the correct evaluation of the puzzle This fix will only work with the new code. (It will not work in earlier releases of the game, i.e. in the DOS, Windows, Android and iOS versions). The reason is that a new scripting action has been introduced to enable this fix, which will ensure the correct evaluation of the puzzle
## Controller support
Controller support is experimental. Tested on PS4 controller connected on bluetooth.
Controller can be configured in INI file. If it is connected when program starts,
it is detected and can be used.
Following mapping is defined by default (you can change it in INI)
Left stick - walking turning, strafing with meta, list selection
Right stick - cursor movement
Key X - cursor action (left mouse click)
Key [] - ENTER/RETURN, accept selection, start battle, finish move
Key O - cancel action, walk by cursor, (right mouse click)
Key /\ - SPACE, wall action, fast trade, next PC in battle, accept selection
Key Ps - settings
Key Share - SAVE
Key Options - LOAD
Key on right stick - Split group
Key R1 - mod/meta key
Key L1 - with meta - sleep, without - backspace
Key DPAD UP - map, with meta cast spell
Key DPAD DOWN - merge group
Key DPAD left - move left
KEY DPAD right - move right
Key X,[],O,/\ with meta - actions during battle
## Goals ## Goals
1. to rewrite all Intel 386 depend code to independed variant. 1. to rewrite all Intel 386 depend code to independed variant.

View file

@ -17,6 +17,7 @@
#include <libs/pcx.h> #include <libs/pcx.h>
#include "globals.h" #include "globals.h"
#include <ctype.h>
#include <string.h> #include <string.h>
#define AUTOMAP_BACK RGB555(8,4,0) #define AUTOMAP_BACK RGB555(8,4,0)
#define AUTOMAP_VODA RGB555(0,15,31) #define AUTOMAP_VODA RGB555(0,15,31)
@ -141,11 +142,15 @@ void save_text_to_map(int x,int y,int depth,char *text)
{ {
char c[512],*d; char c[512],*d;
if (text[0]==0) return; if (text[0]==0) return;
d = text;
while (*d && isspace(*d)) ++d;
if (!*d) return;
memset(c,1,sizeof(c)); memset(c,1,sizeof(c));
strncpy(c+12,text,sizeof(c)-13); strncpy(c+12,text,sizeof(c)-13);
c[511] = 0; c[511] = 0;
if (texty_v_mape==NULL) texty_v_mape=create_list(8); if (texty_v_mape==NULL) texty_v_mape=create_list(8);
d=texty_v_mape[str_add(&texty_v_mape,c)]; int id = str_add(&texty_v_mape,c);
d=texty_v_mape[id];
x=(x-320)+map_xr; x=(x-320)+map_xr;
y=(y-197)+map_yr; y=(y-197)+map_yr;
memcpy(d,&x,4);memcpy(d+4,&y,4);memcpy(d+8,&depth,4); memcpy(d,&x,4);memcpy(d+4,&y,4);memcpy(d+8,&depth,4);

View file

@ -110,41 +110,14 @@ void wire_dialog_drw(void);
static void (*old_wire_proc)(void) = NULL; static void (*old_wire_proc)(void) = NULL;
void wire_dialog_drw_restore(void) {
wire_proc = old_wire_proc ;
wire_dialog_drw();
}
static char dlg_konec(int id,int xa,int ya,int xr,int yr) {
old_wire_proc = wire_proc;
wire_proc = wire_dialog_drw_restore;
konec(id,xa,ya,xr,yr);
return 1;
}
static char dlg_game_setup(int id,int xa,int ya,int xr,int yr) {
old_wire_proc = wire_proc;
wire_proc = wire_dialog_drw_restore;
game_setup(id,xa,ya,xr,yr);
return 1;
}
static char dlg_clk_saveload(int id,int xa,int ya,int xr,int yr) {
old_wire_proc = wire_proc;
wire_proc = wire_dialog_drw_restore;
clk_saveload(id,xa,ya,xr,yr);
return 1;
}
#define CLK_DIALOG 5 #define CLK_DIALOG 5
static T_CLK_MAP clk_dialog[CLK_DIALOG]= static T_CLK_MAP clk_dialog[CLK_DIALOG]=
{ {
{0,TEXT_X,TEXT_Y,TEXT_X+TEXT_XS,TEXT_Y+TEXT_YS,case_click,3,H_MS_DEFAULT}, {0,TEXT_X,TEXT_Y,TEXT_X+TEXT_XS,TEXT_Y+TEXT_YS,case_click,3,H_MS_DEFAULT},
{-1,30,0,85,14,dlg_konec,2,H_MS_DEFAULT}, {-1,30,0,85,14,konec,2,H_MS_DEFAULT},
{-1,87,0,142,14,dlg_game_setup,2,H_MS_DEFAULT}, {-1,87,0,142,14,game_setup,2,H_MS_DEFAULT},
{0,207,0,265,14,dlg_clk_saveload,2,H_MS_DEFAULT}, {0,207,0,265,14,clk_saveload,2,H_MS_DEFAULT},
{0,0,0,639,479,empty_clk,0xff,H_MS_DEFAULT}, {0,0,0,639,479,empty_clk,0xff,H_MS_DEFAULT},
}; };
@ -719,6 +692,7 @@ static void dialog_cont()
save_jump=vol_n[(uint8_t)vyb_volba]; save_jump=vol_n[(uint8_t)vyb_volba];
remove_all_cases(); remove_all_cases();
echo(" "); echo(" ");
wire_proc = old_wire_proc;
his_line=get_last_his_line(); his_line=get_last_his_line();
if (halt_flag) goto_paragraph(save_jump); if (halt_flag) goto_paragraph(save_jump);
schovej_mysku(); schovej_mysku();
@ -736,7 +710,7 @@ static void key_check(EVENT_MSG *msg,void **unused)
int c = va_arg(msg->data, int) >> 8; int c = va_arg(msg->data, int) >> 8;
char redraw = 0; char redraw = 0;
switch (c) { switch (c) {
case 1:dlg_konec(0,0,0,0,0);break; case 1:konec(0,0,0,0,0);break;
case 17: case 17:
case 'H':if (vyb_volba==0) his_line-=(his_line>0); case 'H':if (vyb_volba==0) his_line-=(his_line>0);
else vyb_volba--; else vyb_volba--;
@ -749,6 +723,8 @@ static void key_check(EVENT_MSG *msg,void **unused)
break; break;
case 28: case 28:
case 57:dialog_cont();break; case 57:dialog_cont();break;
case 61:clk_saveload(0, 0, 0, 0, 0);break;
case 59:game_setup(0,0,0,0,0);break;
} }
if (redraw) { if (redraw) {
schovej_mysku(); schovej_mysku();
@ -776,7 +752,7 @@ static void key_check(EVENT_MSG *msg,void **unused)
} }
else if (c==27) { else if (c==27) {
dlg_konec(0,0,0,0,0); dlg_konec(0,0,0,0,0);
}*/ }*/
} }
} }
@ -788,13 +764,13 @@ void wire_dialog_drw()
wire_dialog(); wire_dialog();
draw_all(); draw_all();
ukaz_mysku(); ukaz_mysku();
effect_show(NULL); effect_show(NULL);
} }
void unwire_dialog(void) void unwire_dialog(void)
{ {
send_message(E_DONE,E_KEYBOARD,key_check); send_message(E_DONE,E_KEYBOARD,key_check);
disable_click_map(); disable_click_map();
// wire_proc=wire_dialog_drw;
} }
void wire_dialog() void wire_dialog()
@ -934,7 +910,9 @@ void dialog_select(char halt)
unwire_proc(); unwire_proc();
draw_all(); draw_all();
ukaz_mysku(); ukaz_mysku();
old_wire_proc = wire_proc;
wire_dialog(); wire_dialog();
wire_proc = wire_dialog_drw;
halt_flag=halt && (pocet_voleb>0); halt_flag=halt && (pocet_voleb>0);
} }

View file

@ -1651,7 +1651,22 @@ static void saveload_keyboard(EVENT_MSG *msg,void **_)
} else { } else {
load_save_pos_ingame(last_select);break; load_save_pos_ingame(last_select);break;
} }
} }break;
case 60:if (force_save) {
unwire_proc();wire_proc();
} else {
clk_saveload(1, 0, 0, 0, 0);
}
break;
case 61:if (!force_save) {
unwire_proc();wire_proc();
} else {
clk_saveload(0, 0, 0, 0, 0);
}
break;
case 59:game_setup(0,0,0,0,0);break;
case 64:go_book(0, 0, 0, 0, 0);break;
} }
} }
} }

View file

@ -809,6 +809,7 @@ char clk_touch(int id,int xa,int ya,int xr,int yr);
char go_book(int id,int xa,int ya,int xr,int yr); char go_book(int id,int xa,int ya,int xr,int yr);
char clk_saveload(int id,int xa,int ya,int xr,int yr); char clk_saveload(int id,int xa,int ya,int xr,int yr);
char clk_sleep(int id,int xa,int ya,int xr,int yr); char clk_sleep(int id,int xa,int ya,int xr,int yr);
char spell_casting(int id,int xa,int ya,int xr,int yr);
//inventory viewer - items //inventory viewer - items

View file

@ -246,6 +246,18 @@ void open_message_win(int pocet_textu,char **texts)
static char default_action,cancel_action; static char default_action,cancel_action;
static void message_mouse(EVENT_MSG *msg,void **user_ptr) {
if (msg->msg == E_MOUSE) {
const MS_EVENT * msev = va_arg(msg->data, MS_EVENT *);
if (msev->event_type & MS_EVENT_MOUSE_RPRESS) {
goto_control(cancel_action);
terminate_gui();
msg->msg = -1;
}
}
}
void message_keyboard(EVENT_MSG *msg,void **user_ptr) void message_keyboard(EVENT_MSG *msg,void **user_ptr)
{ {
char *c; char *c;
@ -304,9 +316,11 @@ int message(int butts,char def,char canc,char *keys,...)
} }
open_message_win(butts+1,texts); open_message_win(butts+1,texts);
send_message(E_ADD,E_KEYBOARD,message_keyboard,keys); send_message(E_ADD,E_KEYBOARD,message_keyboard,keys);
send_message(E_ADD,E_MOUSE,message_mouse);
escape(); escape();
id=o_aktual->id; id=o_aktual?o_aktual->id:0;
send_message(E_DONE,E_KEYBOARD,message_keyboard,keys); send_message(E_DONE,E_KEYBOARD,message_keyboard,keys);
send_message(E_DONE,E_MOUSE,message_mouse);
close_current(); close_current();
restore_click_map(clksav,clksav2); restore_click_map(clksav,clksav2);
return id; return id;
@ -1495,14 +1509,38 @@ static void smlouvat_enter(EVENT_MSG *msg,OBJREC *o)
} }
} }
static int add_number_cb(EVENT_MSG *msg, void *x) {
o_aktual->call_event(msg, o_aktual);
return 0;
}
static void add_number() {
if (o_aktual) {
int n = o_aktual->id - 40;
goto_control(10);
send_message_to(add_number_cb,NULL, E_KEYBOARD, 'O'<<8);
send_message_to(add_number_cb,NULL, E_KEYBOARD, n+48);
}
}
static void remove_number() {
if (o_aktual) {
goto_control(10);
send_message_to(add_number_cb,NULL, E_KEYBOARD, 'O'<<8);
send_message_to(add_number_cb,NULL, E_KEYBOARD, 8);
}
}
THAGGLERESULT smlouvat_dlg(int cena,int puvod,int pocet,int posledni, int money,char mode) THAGGLERESULT smlouvat_dlg(int cena,int puvod,int pocet,int posledni, int money,char mode)
{ {
char buffer[20]; char buffer[20];
int ponuka; int ponuka;
THAGGLERESULT res; THAGGLERESULT res;
char j = is_joystick_used();
set_font(H_FBOLD,RGB555(31,31,31)); set_font(H_FBOLD,RGB555(31,31,31));
add_window(170,130,300,100,H_WINTXTR,3,20,20); add_window(170,130,300,100+j*20,H_WINTXTR,3,20,20);
define(-1,10,15,1,1,0,label,texty[241]); define(-1,10,15,1,1,0,label,texty[241]);
define(-1,150,15,100,13,0,label,int2ascii(cena,buffer,10)); define(-1,150,15,100,13,0,label,int2ascii(cena,buffer,10));
set_font(H_FBOLD,MSG_COLOR1); set_font(H_FBOLD,MSG_COLOR1);
@ -1511,6 +1549,14 @@ THAGGLERESULT smlouvat_dlg(int cena,int puvod,int pocet,int posledni, int money,
on_control_event(smlouvat_enter); 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(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); 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);
if (j) {
char nstr[2] = "0";
for (int i = 0; i < 10; ++i) {
nstr[0] = i+48;
define(40+i, 10+i*24,50,22,20,0,button,nstr);property(def_border(0,BAR_COLOR),NULL,NULL,BAR_COLOR);on_control_change(add_number);
}
define(50, 20,50,20,20,1,button,"<-");property(def_border(0,BAR_COLOR),NULL,NULL,BAR_COLOR);on_control_change(remove_number);
}
{ {
redraw_window(); redraw_window();
schovej_mysku();set_font(H_FBOLD,RGB555(31,31,31)); schovej_mysku();set_font(H_FBOLD,RGB555(31,31,31));

View file

@ -1546,13 +1546,13 @@ void inv_informuj()
if (cur_shop->list[j].item == i-1) { if (cur_shop->list[j].item == i-1) {
int cena = cur_shop->list[j].cena; int cena = cur_shop->list[j].cena;
if (cena) { if (cena) {
sprintf(c,"%s (%d)",glob_items[i-1].jmeno,cena+cur_shop->koef*cena/100); sprintf(c,"%s (%d)",glob_items[i-1].jmeno,cena-cur_shop->koef*cena/100);
found_price = 1; found_price = 1;
break; break;
} }
} }
} }
} }
if (!found_price) { if (!found_price) {
strcopy_n(c,glob_items[i-1].jmeno,sizeof(c)); strcopy_n(c,glob_items[i-1].jmeno,sizeof(c));
} }
@ -1754,13 +1754,13 @@ void inv_item_info_box(EVENT_MSG *msg,void **data)
if (cur_shop->list[j].item == i-1) { if (cur_shop->list[j].item == i-1) {
int cena = cur_shop->list[j].cena; int cena = cur_shop->list[j].cena;
if (cena) { if (cena) {
sprintf(c,"%s (%d)",glob_items[i-1].jmeno,cena+cur_shop->koef*cena/100); sprintf(c,"%s (%d)",glob_items[i-1].jmeno,cena-cur_shop->koef*cena/100);
found_price = 1; found_price = 1;
break; break;
} }
} }
} }
} }
if (!found_price) { if (!found_price) {
strcopy_n(c,glob_items[i-1].jmeno,sizeof(c)); strcopy_n(c,glob_items[i-1].jmeno,sizeof(c));
} }
@ -1778,8 +1778,7 @@ void inv_item_info_box(EVENT_MSG *msg,void **data)
void unwire_inv_mode(void) void unwire_inv_mode(void)
{ {
send_message(E_DONE,E_KEYBOARD,inv_keyboard); send_message(E_DONE,E_KEYBOARD,inv_keyboard); send_message(E_DONE,E_MOUSE,inv_item_info_box);
send_message(E_DONE,E_MOUSE,inv_item_info_box);
build_all_players(); build_all_players();
} }
@ -3033,6 +3032,10 @@ static void shop_keyboard_proc(EVENT_MSG *msg, void **_) {
switch(c>>8) { switch(c>>8) {
case 1: _exit_shop(0,0,0,0,0);break; case 1: _exit_shop(0,0,0,0,0);break;
case 57: fast_trade_click();break; case 57: fast_trade_click();break;
case 32:
case 'M':shop_block_click(2,0,0,0,0);break;
case 30:
case 'K':shop_block_click(1,0,0,0,0);break;
default:break; default:break;
} }
} }
@ -3047,7 +3050,7 @@ void unwire_shop(void)
send_message(E_DONE,E_KEYBOARD, shop_keyboard_proc); send_message(E_DONE,E_KEYBOARD, shop_keyboard_proc);
norefresh=0; norefresh=0;
wire_proc=wire_shop; wire_proc=wire_shop;
inv_view_mode=old_inv_view_mode; inv_view_mode=old_inv_view_mode;
} }
void wire_shop(void) void wire_shop(void)

View file

@ -1955,13 +1955,15 @@ void game_keyboard(EVENT_MSG *msg,void **usr)
case 1:konec(0,0,0,0,0);break; case 1:konec(0,0,0,0,0);break;
// case 25:GamePause();break; // case 25:GamePause();break;
case 28:enforce_start_battle();break; case 28:enforce_start_battle();break;
case 60:clk_saveload(1, 0, 0, 0, 0);break;
case 61:clk_saveload(0, 0, 0, 0, 0);break;
case 59:game_setup(0,0,0,0,0);break;
case 63:do_autosave();break; case 63:do_autosave();break;
case 62:clk_sleep(0,0,0,0,0);break;
case 64:go_book(0, 0, 0, 0, 0);break;
case 65:spell_casting(0, 0, 0, 0, 0);break;
case 45: case 45:
case 82:group_all();break; case 82:group_all();break;
case '<':if (!battle && GlobEvent(MAGLOB_CLICKSAVE,viewsector,viewdir))
{unwire_proc();cancel_render=1;do_save_dialog();wire_proc();}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()) { case 0x2E: if (get_control_key_state() && get_shift_key_state()) {
console_show(!console_is_visible()); console_show(!console_is_visible());
} }

View file

@ -77,17 +77,21 @@ static void change_turn(void)
turn_speed((id-60)/10); turn_speed((id-60)/10);
} }
char exit_setup(int id,int xa,int ya,int xr,int yr);
static void unwire_setup(void); static void unwire_setup(void);
static void setup_keyboard(EVENT_MSG *msg,void **_) static void setup_keyboard(EVENT_MSG *msg,void **_)
{ {
if (msg->msg == E_KEYBOARD) if (msg->msg == E_KEYBOARD)
{ {
char c= quit_request_as_escape(va_arg(msg->data, int)); int c= quit_request_as_escape(va_arg(msg->data, int));
if (c==27) switch(c>>8) {
{ case 1:
unwire_proc(); case 59: exit_setup(0, 0, 0,0,0); break;
} case 60:clk_saveload(1, 0, 0, 0, 0);break;
case 61:clk_saveload(0, 0, 0, 0, 0);break;
case 64:go_book(0, 0, 0, 0, 0);break;
}
} }
} }
@ -112,7 +116,6 @@ static void unwire_setup(void)
mix_back_sound(32768); mix_back_sound(32768);
close_current(); close_current();
send_message(E_DONE,E_KEYBOARD,setup_keyboard); send_message(E_DONE,E_KEYBOARD,setup_keyboard);
wire_proc();
cancel_render=1; cancel_render=1;
SEND_LOG("(GAME) Setup closed"); SEND_LOG("(GAME) Setup closed");
} }
@ -121,6 +124,7 @@ char exit_setup(int id,int xa,int ya,int xr,int yr)
{ {
id,xa,ya,xr,yr; id,xa,ya,xr,yr;
unwire_setup(); unwire_setup();
wire_proc();
return 0; return 0;
} }

View file

@ -957,6 +957,7 @@ void init_skeldal(const INI_CONFIG *cfg)
} }
showview = game_display_update_rect; showview = game_display_update_rect;
game_display_set_icon(getWindowIcon(), getWindowIconSize()); game_display_set_icon(getWindowIcon(), getWindowIconSize());
init_joystick(ini_section_open(cfg, "controller"));
general_engine_init(); general_engine_init();
atexit(done_skeldal); atexit(done_skeldal);
@ -1382,7 +1383,7 @@ static void game_big_circle(char enforced)
leave_current_map(); leave_current_map();
strcopy_n(s,loadlevel.name,sizeof(s)); strcopy_n(s,loadlevel.name,sizeof(s));
if (s[0]!=0) { if (s[0]!=0) {
err=load_map(s); err=load_map(s);
} }
memset(GlobEventList,0,sizeof(GlobEventList)); memset(GlobEventList,0,sizeof(GlobEventList));

View file

@ -1494,7 +1494,7 @@ static void *runebar;
static char *rune_name=NULL; static char *rune_name=NULL;
static char *rune_info=NULL; static char *rune_info=NULL;
void display_power_bar(THE_TIMER *_); void display_power_bar(char);
void display_rune_bar(THE_TIMER *_) void display_rune_bar(THE_TIMER *_)
{ {
short coords[][2]={{3,26},{32,26},{61,26},{90,26},{18,64},{47,64},{76,64}}; short coords[][2]={{3,26},{32,26},{61,26},{90,26},{18,64},{47,64},{76,64}};
@ -1540,7 +1540,7 @@ void rune_bar_redrawing(THE_TIMER *_)
{ {
schovej_mysku(); schovej_mysku();
program_draw(); program_draw();
display_power_bar(NULL); display_power_bar(0);
ukaz_mysku(); ukaz_mysku();
showview(0,0,0,0); showview(0,0,0,0);
} }
@ -1627,12 +1627,12 @@ void vyber_cil(int typ)
char power_info(int id,int xa,int ya,int xr,int yr) { char power_info(int id,int xa,int ya,int xr,int yr) {
rune_info = NULL; rune_info = NULL;
int x = ms_last_event.x; int x = ms_last_event.x;
int y = ms_last_event.y; int y = ms_last_event.y;
for (int i = 0; i < CLK_POWER; ++i) { for (int i = 0; i < CLK_POWER; ++i) {
const T_CLK_MAP *m = clk_power+i; const T_CLK_MAP *m = clk_power+i;
if (m->proc == &power && m->xlu <= x && m->xrb >= x && m->ylu <= y && m->yrb >= y) { if (m->proc == &power && m->xlu <= x && m->xrb >= x && m->ylu <= y && m->yrb >= y) {
rune_info = powers_info[m->id]; rune_info = powers_info[m->id];
} }
} }
return 1; return 1;
@ -1700,7 +1700,7 @@ char runes_mask(int id,int xa,int ya,int xr,int yr)
} }
else else
{ {
rune_name=get_rune_name(x); rune_name=get_rune_name(x);
} }
} }
} }
@ -1808,7 +1808,7 @@ void program_draw()
x+=74; x+=74;
} }
} else { } else {
for(j=0;j<POCET_POSTAV;j++) for(j=0;j<POCET_POSTAV;j++) {
if (postavy[i=group_sort[j]].used) if (postavy[i=group_sort[j]].used)
{ {
int y; int y;
@ -1816,6 +1816,7 @@ void program_draw()
y=postavy[i].programovano*10; y=postavy[i].programovano*10;
if (y>maxy) maxy=y; if (y>maxy) maxy=y;
} }
}
int m = 0; int m = 0;
if (pgm_help || rune_name!=NULL) m=10*(rune_info?2:1); if (pgm_help || rune_name!=NULL) m=10*(rune_info?2:1);
if (m > maxy) maxy = m; if (m > maxy) maxy = m;
@ -1852,18 +1853,18 @@ void program_draw()
c=rune_name; c=rune_name;
} else { } else {
c=texty[40+pgm_help]; c=texty[40+pgm_help];
} }
set_aligned_position(580,376,1,2,c); set_aligned_position(580,376,1,2,c);
outtext(c); outtext(c);
if (rune_name && rune_info) { if (rune_name && rune_info) {
set_aligned_position(580,362,1,2,rune_info); set_aligned_position(580,362,1,2,rune_info);
outtext(rune_info); outtext(rune_info);
} }
} }
ukaz_mysku(); ukaz_mysku();
} }
@ -1908,11 +1909,31 @@ static void souboje_dalsi()
select_player=group_sort[i]; select_player=group_sort[i];
j--; j--;
} }
while ((!postavy[select_player].used || !postavy[select_player].actions || (postavy[select_player].groupnum!=cd && j>6)) && j); 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; viewsector=postavy[select_player].sektor;
viewdir=postavy[select_player].direction; viewdir=postavy[select_player].direction;
cur_group=postavy[select_player].groupnum;
} }
static void souboje_dalsi_user() {
int i,j=6,k;
for(i=0;group_sort[i]!=select_player;i++);
do
{
i++;
if (i>=POCET_POSTAV) i=0;
k=group_sort[i];
j--;
}
while ((!postavy[k].used
|| !postavy[k].lives
|| postavy[k].inmaphash != current_map_hash) && j);
select_player = k;
viewsector=postavy[select_player].sektor;
viewdir=postavy[select_player].direction;
cur_group=postavy[select_player].groupnum;
}
void souboje_vybrano(int d) void souboje_vybrano(int d)
{ {
if (d==AC_STAND || d==AC_RUN) postavy[select_player].actions=0; if (d==AC_STAND || d==AC_RUN) postavy[select_player].actions=0;
@ -2079,6 +2100,48 @@ static void zahajit_kolo(char prekvapeni)
send_message(E_KOUZLO_KOLO); send_message(E_KOUZLO_KOLO);
} }
static char add_pc_action(int d) {
souboje_stisknout(d);
switch(d)
{
case AC_RUN:
if (lodka) {
group_flee = 1;break;
} else {
postavy[select_player].utek=5+postavy[select_player].actions;
}
CASE_FALLTHROUGH;
case AC_ATTACK:
case AC_STAND:
case AC_ARMOR:
case AC_MOVE:
case AC_MAGIC:if (postavy[select_player].actions && (d != AC_MOVE || !lodka))
{
HUM_ACTION *c;
postavy[select_player].direction=viewdir;
c=postavy[select_player].zvolene_akce;while (c->action) c++;
if (d==AC_MAGIC)
{
wire_select_rune();
return 1;
}
c->action=d;
if (d==AC_ATTACK) c->data1=select_weapon(&postavy[select_player],1);
c++;
c->action=0;
souboje_vybrano(d);
}
break;
case AC_CANCEL:zrusit_akce();group_flee = 0;break;
case AC_START:zahajit_kolo(0);
souboje_stisknout(d);
return 0;
break;
}
return 0;
}
char mask_click(int id,int xa,int ya,int xr,int yr) char mask_click(int id,int xa,int ya,int xr,int yr)
{ {
char *c; char *c;
@ -2090,47 +2153,9 @@ char mask_click(int id,int xa,int ya,int xr,int yr)
c=(char *)mask+6+512; c=(char *)mask+6+512;
c+=yr*mask[0]+xr; c+=yr*mask[0]+xr;
d=*c; d=*c;
if (d) if (d) {
{ return add_pc_action(d);
souboje_stisknout(d); }
switch(d)
{
case AC_RUN:
if (lodka) {
group_flee = 1;break;
} else {
postavy[select_player].utek=5+postavy[select_player].actions;
}
CASE_FALLTHROUGH;
case AC_ATTACK:
case AC_STAND:
case AC_ARMOR:
case AC_MOVE:
case AC_MAGIC:if (postavy[select_player].actions && (d != AC_MOVE || !lodka))
{
HUM_ACTION *c;
postavy[select_player].direction=viewdir;
c=postavy[select_player].zvolene_akce;while (c->action) c++;
if (d==AC_MAGIC)
{
wire_select_rune();
return 1;
}
c->action=d;
if (d==AC_ATTACK) c->data1=select_weapon(&postavy[select_player],1);
c++;
c->action=0;
souboje_vybrano(d);
}
break;
case AC_CANCEL:zrusit_akce();group_flee = 0;break;
case AC_START:zahajit_kolo(0);
souboje_stisknout(d);
return 0;
break;
}
return 0;
}
bott_draw(1); bott_draw(1);
return 1; return 1;
} }
@ -2190,13 +2215,22 @@ void programming_keyboard(EVENT_MSG *msg,void **unused)
case 'M':souboje_turn(1);break; case 'M':souboje_turn(1);break;
case 16: case 16:
case 'K':souboje_turn(-1);break; case 'K':souboje_turn(-1);break;
case '=':unwire_proc();cancel_render=1;wire_save_load(0);break; case 61:clk_saveload(0, 0, 0, 0, 0);break;
case '>':game_setup(0,0,0,0,0);break; case 60:clk_saveload(1, 0, 0, 0, 0);break;
case 57:souboje_dalsi();bott_draw(1);break; case 64:go_book(1, 0, 0, 0, 0);break;
case 15: case 65:add_pc_action(AC_MAGIC);break;
case 66:add_pc_action(AC_ATTACK);break;
case 67:add_pc_action(AC_MOVE);break;
case 68:add_pc_action(AC_ARMOR);break;
case 133:add_pc_action(AC_RUN);break;
case 134:add_pc_action(AC_STAND);break;
case 14:add_pc_action(AC_CANCEL);break;
case 59:game_setup(0,0,0,0,0);break;
case 57:souboje_dalsi_user();bott_draw(1);break;
case 28:zahajit_kolo(0); case 28:zahajit_kolo(0);
souboje_stisknout(AC_START); souboje_stisknout(AC_START);
break; break;
case 15:
case 50: case 50:
if (GlobEvent(MAGLOB_BEFOREMAPOPEN,viewsector,viewdir)) if (GlobEvent(MAGLOB_BEFOREMAPOPEN,viewsector,viewdir))
show_automap(1); show_automap(1);

View file

@ -4,6 +4,7 @@
#include "types.h" #include "types.h"
#include "event.h" #include "event.h"
#include "mouse.h" #include "mouse.h"
typedef struct tms_basic_info typedef struct tms_basic_info
{ {
int mouse_event; int mouse_event;
@ -20,4 +21,5 @@ extern TMS_BASIC_INFO ms_basic_info;
int lock_region (void *address, unsigned length); int lock_region (void *address, unsigned length);
void keyboard(EVENT_MSG *msg,void *user_data); void keyboard(EVENT_MSG *msg,void *user_data);
char ms_get_keycount(void); char ms_get_keycount(void);
#endif #endif

View file

@ -803,7 +803,7 @@ void set_window_modal(void)
static void set_object_value(char redraw,OBJREC *o,const char *value) static void set_object_value(char redraw,OBJREC *o,const char *value)
{ {
if (strncmp(o->data, value, o->datasize)) if (strncmp(o->data, value, o->datasize))
{ {
strcopy_n(o->data,value,o->datasize); strcopy_n(o->data,value,o->datasize);
if (redraw) redraw_object(o); if (redraw) redraw_object(o);
@ -812,7 +812,7 @@ static void set_object_value(char redraw,OBJREC *o,const char *value)
static void set_object_value_bin(char redraw,OBJREC *o,const void *value, size_t sz) static void set_object_value_bin(char redraw,OBJREC *o,const void *value, size_t sz)
{ {
size_t cpsz = MIN(o->datasize, sz); size_t cpsz = MIN((size_t)o->datasize, sz);
if (memcmp(o->data,value,cpsz)) if (memcmp(o->data,value,cpsz))
{ {
memcpy(o->data,value,cpsz); memcpy(o->data,value,cpsz);
@ -856,10 +856,10 @@ void set_value(int win_id,int obj_id,void *value)
void set_value_bin(int win_id,int obj_id,void *value, size_t value_size) { void set_value_bin(int win_id,int obj_id,void *value, size_t value_size) {
OBJREC *o; OBJREC *o;
WINDOW *w; WINDOW *w;
if ((o=find_object_desktop(win_id,obj_id,&w))==NULL)return; if ((o=find_object_desktop(win_id,obj_id,&w))==NULL)return;
set_object_value_bin((w==waktual),o,value, value_size); set_object_value_bin((w==waktual),o,value, value_size);
} }
void set_default(const char *value) void set_default(const char *value)
@ -875,7 +875,10 @@ void goto_control(int obj_id)
{ {
EVENT_MSG msg; EVENT_MSG msg;
if (send_lost()) return; if (send_lost()) return;
o_aktual=find_object(waktual,obj_id);
OBJREC *x = find_object(waktual,obj_id);
if (x == NULL) return;
o_aktual=x;
msg.msg=E_GET_FOCUS; msg.msg=E_GET_FOCUS;
o_aktual->on_event(&msg,o_aktual); o_aktual->on_event(&msg,o_aktual);
o_aktual->call_event(&msg,o_aktual); o_aktual->call_event(&msg,o_aktual);
@ -963,7 +966,8 @@ void background_runner(EVENT_MSG *msg,void **prog)
*prog_ptr=NULL; *prog_ptr=NULL;
return; return;
} }
(*prog_ptr)();
(*prog_ptr)();
msg->msg=-2; msg->msg=-2;
} }

View file

@ -130,6 +130,9 @@ int list_files(const char *directory, int type, LIST_FILES_CALLBACK cb, void *ct
#include "sdl/BGraph2.h" #include "sdl/BGraph2.h"
void init_joystick(const INI_CONFIG_SECTION *section);
char is_joystick_used();
#define WM_RELOADMAP (WM_APP+215) #define WM_RELOADMAP (WM_APP+215)
#define E_RELOADMAP 40 #define E_RELOADMAP 40

View file

@ -39,3 +39,68 @@ void ShareCPU() {
} }
} }
void init_joystick(const INI_CONFIG_SECTION *section) {
SDLContext::JoystickConfig cfg = {};
cfg.buttons[0] = SDLContext::JoystickButton::lclick;
cfg.buttons[1] = SDLContext::JoystickButton::rclick;
cfg.buttons[2] = SDLContext::JoystickButton::enter;
cfg.buttons[3] = SDLContext::JoystickButton::space;
cfg.buttons[5] = SDLContext::JoystickButton::F1;
cfg.buttons[4] = SDLContext::JoystickButton::F2;
cfg.buttons_mod[4] = SDLContext::JoystickButton::F5;
cfg.buttons[6] = SDLContext::JoystickButton::F3;
cfg.buttons[8] = SDLContext::JoystickButton::ctrl_lclick;
cfg.buttons[10] = SDLContext::JoystickButton::mod_key;
cfg.buttons_mod[10] = SDLContext::JoystickButton::mod_key;
cfg.buttons[11] = SDLContext::JoystickButton::map;
cfg.buttons_mod[11] = SDLContext::JoystickButton::F6;
cfg.buttons[12] = SDLContext::JoystickButton::merge;
cfg.buttons[14] = SDLContext::JoystickButton::left;
cfg.buttons[13] = SDLContext::JoystickButton::right;
cfg.buttons[9] = SDLContext::JoystickButton::backspace;
cfg.buttons_mod[5] = SDLContext::JoystickButton::escape;
cfg.buttons_mod[9] = SDLContext::JoystickButton::F4;
cfg.buttons_mod[12] = SDLContext::JoystickButton::F7;
cfg.buttons_mod[0] = SDLContext::JoystickButton::F8;
cfg.buttons_mod[1] = SDLContext::JoystickButton::F9;
cfg.buttons_mod[2] = SDLContext::JoystickButton::F10;
cfg.buttons_mod[3] = SDLContext::JoystickButton::F11;
cfg.buttons_mod[14] = SDLContext::JoystickButton::F12;
cfg.buttons_mod[13] = SDLContext::JoystickButton::backspace;
cfg.enabled = true;
cfg.walk_deadzone = 0x4000;
cfg.cursor_deadzone = 1;
cfg.enabled = ini_get_boolean(section, "enabled", 1) != 0;
cfg.swap_axis = ini_get_boolean(section, "swap_sticks", 0) != 0;
cfg.walk_deadzone = ini_get_int(section,"walk_deadzone", 0x4000);
cfg.cursor_deadzone = ini_get_int(section,"cursor_deadzone", 0x800);
auto bcount = std::distance(std::begin(cfg.buttons),std::end(cfg.buttons));
for (std::ptrdiff_t i = 0; i < bcount; ++i) {
char buff[100];
{
snprintf(buff,sizeof(buff),"button%d", static_cast<int>(i));
const char *v = ini_get_string(section, buff, NULL);
if (v) {
auto n = cfg.buttons[i] = SDLContext::button_from_string(v);
if (n == SDLContext::JoystickButton::mod_key) {
cfg.buttons_mod[i] = n;
}
}
}
{
snprintf(buff,sizeof(buff),"mod+button%d", static_cast<int>(i));
const char *v = ini_get_string(section, buff, NULL);
if (v) {
cfg.buttons_mod[i] = SDLContext::button_from_string(v);
}
}
}
get_sdl_global_context().configure_controller(cfg);
}
char is_joystick_used() {
return get_sdl_global_context().is_joystick_used()?1:0;
}

View file

@ -14,6 +14,7 @@ extern "C" {
#endif #endif
#include <libs/devices.h> #include <libs/devices.h>
#include "../config.h"
char get_control_key_state(void); char get_control_key_state(void);
@ -26,6 +27,9 @@ void SetWheelMapping(char up, char down);
void get_ms_event(MS_EVENT *event); void get_ms_event(MS_EVENT *event);
void ShareCPU(); void ShareCPU();
void init_joystick(const INI_CONFIG_SECTION *section);
char is_joystick_used();
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -255,29 +255,37 @@ void SDLContext::close_video() {
} }
int SDLContext::check_axis_dir(int &cooldown, int value) { int SDLContext::check_axis_dir(int &cooldown, int value) {
if (cooldown>0) { int range = 0x8000-_jcontrol_map.walk_deadzone;
cooldown -= 0x400; int step = range >> 4;
} else { int max_speed = range+(step<<2);
if (value == 0) {
cooldown = -1;
} else if (cooldown>0) {
cooldown -= step;
if (cooldown < 0) cooldown = 0;
} else {
if (value > 0) { if (value > 0) {
cooldown = 0x5000-value; if (cooldown < 0) value = step;
return 1; cooldown = max_speed-value;
} return 1;
if (value < 0) { }
cooldown = 0x5000+value; else if (value < 0) {
if (cooldown < 0) value = -step;
cooldown = max_speed+value;
return -1; return -1;
} }
} }
return 0; return 0;
} }
static int adjust_deadzone(int v) { int SDLContext::adjust_deadzone(int v, short deadzone) {
if (v > 0x4000) return v - 0x4000; if (v > deadzone) return v - deadzone;
if (v < -0x4000) return v + 0x4000; if (v < -deadzone) return v + deadzone;
return 0; return 0;
} }
static int axis_dynamic(int c) { static int axis_dynamic(int c) {
double f = std::floor(std::pow(std::abs(c)*0.001,2)*0.02)+0.5; double f = std::floor(std::pow(std::abs(c)*0.001,2)*0.025);
if (c < 0) return static_cast<int>(-f); if (c < 0) return static_cast<int>(-f);
else return static_cast<int>(f); else return static_cast<int>(f);
@ -285,19 +293,19 @@ static int axis_dynamic(int c) {
} }
void SDLContext::joystick_handle() { void SDLContext::joystick_handle() {
int a1 = SDL_JoystickGetAxis(init_context.controller, 0); int a1 = SDL_JoystickGetAxis(init_context.controller, _jcontrol_map.swap_axis?2:0);
int a2 = SDL_JoystickGetAxis(init_context.controller, 1); int a2 = SDL_JoystickGetAxis(init_context.controller, _jcontrol_map.swap_axis?3:1);
if (std::abs(a1) - std::abs(a2) > 0x1000) a2 = 0; if (std::abs(a1) - std::abs(a2) > 0x2000) a2 = 0;
else if (std::abs(a2) - std::abs(a1) >0x1000) a1 = 0; else if (std::abs(a2) - std::abs(a1) >0x2000) a1 = 0;
else { else {
a1 = 0; a1 = 0;
a2 = 0; a2 = 0;
} }
int axis1 = check_axis_dir(axis1_cooldown,adjust_deadzone(a1)); int axis1 = check_axis_dir(axis1_cooldown,adjust_deadzone(a1, _jcontrol_map.walk_deadzone));
int axis2 = check_axis_dir(axis2_cooldown,adjust_deadzone(a2)); int axis2 = check_axis_dir(axis2_cooldown,adjust_deadzone(a2, _jcontrol_map.walk_deadzone));
int axis3 = axis_dynamic(SDL_JoystickGetAxis(init_context.controller,2)); int axis3 = axis_dynamic(adjust_deadzone(SDL_JoystickGetAxis(init_context.controller,_jcontrol_map.swap_axis?0:2), _jcontrol_map.cursor_deadzone));
int axis4 = axis_dynamic(SDL_JoystickGetAxis(init_context.controller,3)); int axis4 = axis_dynamic(adjust_deadzone(SDL_JoystickGetAxis(init_context.controller,_jcontrol_map.swap_axis?1:3), _jcontrol_map.cursor_deadzone));
int newx = this->ms_event.x + axis3; int newx = this->ms_event.x + axis3;
int newy = this->ms_event.y + axis4; int newy = this->ms_event.y + axis4;
@ -313,7 +321,7 @@ void SDLContext::joystick_handle() {
if (_mouse) { if (_mouse) {
SDL_Point pt(this->ms_event.x, this->ms_event.y); SDL_Point pt(this->ms_event.x, this->ms_event.y);
SDL_Rect winrc = get_window_aspect_rect(); SDL_Rect winrc = get_window_aspect_rect();
pt = to_window_point(winrc,pt); pt = to_window_point(winrc,pt);
_mouse_rect.x = pt.x; _mouse_rect.x = pt.x;
_mouse_rect.y = pt.y; _mouse_rect.y = pt.y;
SDL_Event event; SDL_Event event;
@ -329,8 +337,8 @@ void SDLContext::joystick_handle() {
default:break; default:break;
} }
switch(axis1) { switch(axis1) {
case -1: scn = SDL_SCANCODE_LEFT;break; case -1: if (_jcontrol_mod_key) scn = SDL_SCANCODE_END; else scn = SDL_SCANCODE_LEFT;break;
case 1: scn = SDL_SCANCODE_RIGHT;break; case 1: if (_jcontrol_mod_key) scn = SDL_SCANCODE_PAGEDOWN; else scn = SDL_SCANCODE_RIGHT;break;
default:break; default:break;
} }
if (scn != SDL_Scancode{}) { if (scn != SDL_Scancode{}) {
@ -339,6 +347,84 @@ void SDLContext::joystick_handle() {
} }
} }
void SDLContext::configure_controller(const JoystickConfig &cfg) {
_jcontrol_map = cfg;
if (_jcontrol_map.enabled) {
if (init_context.controller) {
SDL_AddTimer(25,[](Uint32 tm, void *ptr){
SDLContext *me = reinterpret_cast<SDLContext *>(ptr);
me->joystick_handle();
return tm;
}, this);
}
}
}
bool SDLContext::is_joystick_used() const {
return _jcontrol_used;
}
void SDLContext::generate_j_event(int button, char up) {
if (_jcontrol_map.enabled && button >= 0 && button < static_cast<int>(sizeof(_jcontrol_map.buttons)/sizeof(JoystickButton))) {
_jcontrol_used = true;
JoystickButton b = _jcontrol_mod_key?_jcontrol_map.buttons_mod[button]:_jcontrol_map.buttons[button];
SDL_Scancode cd = {};
switch (b) {
default: break;
case JoystickButton::enter: if (!up) cd = SDL_SCANCODE_RETURN;break;
case JoystickButton::space: if (!up) cd = SDL_SCANCODE_SPACE; break;
case JoystickButton::ctrl: _key_control = !up; break;
case JoystickButton::lclick: ms_event.tl1 = !up;
ms_event.event = 1;
ms_event.event_type|= up?MS_EVENT_MOUSE_LRELEASE:MS_EVENT_MOUSE_LPRESS;
break;
case JoystickButton::rclick: ms_event.tl2 = !up;
ms_event.event = 1;
ms_event.event_type|= up?MS_EVENT_MOUSE_RRELEASE:MS_EVENT_MOUSE_RPRESS;
break;
case JoystickButton::ctrl_lclick:_key_control = !up;
ms_event.tl1 = !up;
ms_event.event = 1;
ms_event.event_type|= up?MS_EVENT_MOUSE_LRELEASE:MS_EVENT_MOUSE_LPRESS;
break;
case JoystickButton::escape: if (!up) cd = SDL_SCANCODE_ESCAPE;break;
case JoystickButton::up: if (!up) cd = SDL_SCANCODE_UP;break;
case JoystickButton::down: if (!up) cd = SDL_SCANCODE_DOWN;break;
case JoystickButton::left: if (!up) cd = SDL_SCANCODE_PAGEDOWN;break;
case JoystickButton::right: if (!up) cd = SDL_SCANCODE_END;break;
case JoystickButton::turn_left: if (!up) cd = SDL_SCANCODE_LEFT;break;
case JoystickButton::turn_right: if (!up) cd = SDL_SCANCODE_RIGHT;break;
case JoystickButton::merge: if (!up) cd = SDL_SCANCODE_INSERT;break;
case JoystickButton::map: if (!up) cd = SDL_SCANCODE_TAB;break;
case JoystickButton::split1: if (!up) cd = SDL_SCANCODE_1;break;
case JoystickButton::split2: if (!up) cd = SDL_SCANCODE_2;break;
case JoystickButton::split3: if (!up) cd = SDL_SCANCODE_3;break;
case JoystickButton::split4: if (!up) cd = SDL_SCANCODE_4;break;
case JoystickButton::split5: if (!up) cd = SDL_SCANCODE_5;break;
case JoystickButton::split6: if (!up) cd = SDL_SCANCODE_6;break;
case JoystickButton::F1: if (!up) cd = SDL_SCANCODE_F1;break;
case JoystickButton::F2: if (!up) cd = SDL_SCANCODE_F2;break;
case JoystickButton::F3: if (!up) cd = SDL_SCANCODE_F3;break;
case JoystickButton::F4: if (!up) cd = SDL_SCANCODE_F4;break;
case JoystickButton::F5: if (!up) cd = SDL_SCANCODE_F5;break;
case JoystickButton::F6: if (!up) cd = SDL_SCANCODE_F6;break;
case JoystickButton::F7: if (!up) cd = SDL_SCANCODE_F7;break;
case JoystickButton::F8: if (!up) cd = SDL_SCANCODE_F8;break;
case JoystickButton::F9: if (!up) cd = SDL_SCANCODE_F9;break;
case JoystickButton::F10: if (!up) cd = SDL_SCANCODE_F10;break;
case JoystickButton::F11: if (!up) cd = SDL_SCANCODE_F11;break;
case JoystickButton::F12: if (!up) cd = SDL_SCANCODE_F12;break;
case JoystickButton::backspace: if (!up) cd = SDL_SCANCODE_BACKSPACE;break;
case JoystickButton::mod_key: _jcontrol_mod_key = !up;
}
if (cd != SDL_Scancode{}) {
std::lock_guard _(_mx);
_keyboard_queue.push(sdl_keycode_map.get_bios_code(cd, 0, 0));
}
}
}
void SDLContext::event_loop(std::stop_token stp) { void SDLContext::event_loop(std::stop_token stp) {
static Uint32 exit_loop_event = SDL_RegisterEvents(1); static Uint32 exit_loop_event = SDL_RegisterEvents(1);
@ -348,13 +434,6 @@ void SDLContext::event_loop(std::stop_token stp) {
SDL_PushEvent(&event); SDL_PushEvent(&event);
}); });
if (init_context.controller) {
SDL_AddTimer(25,[](Uint32 tm, void *ptr){
SDLContext *me = reinterpret_cast<SDLContext *>(ptr);
me->joystick_handle();
return tm;
}, this);
}
SDL_Event e; SDL_Event e;
while (SDL_WaitEvent(&e)) { while (SDL_WaitEvent(&e)) {
@ -427,48 +506,13 @@ void SDLContext::event_loop(std::stop_token stp) {
if (e.wheel.y > 0) kbdevent =SDL_SCANCODE_UP; if (e.wheel.y > 0) kbdevent =SDL_SCANCODE_UP;
else if (e.wheel.y < 0) kbdevent =SDL_SCANCODE_DOWN; else if (e.wheel.y < 0) kbdevent =SDL_SCANCODE_DOWN;
} else if (e.type == SDL_JOYBUTTONDOWN) { } else if (e.type == SDL_JOYBUTTONDOWN) {
switch (e.jbutton.button) { generate_j_event(e.jbutton.button, 0);
case 3: kbdevent = SDL_SCANCODE_SPACE; break; } else if (e.type == SDL_JOYBUTTONUP) {
case 2: kbdevent = SDL_SCANCODE_RETURN; break; generate_j_event(e.jbutton.button, 1);
case 9: kbdevent = SDL_SCANCODE_END;break;
case 7: kbdevent = SDL_SCANCODE_ESCAPE;break;
case 10:kbdevent = SDL_SCANCODE_PAGEDOWN;break;
case 11:kbdevent = SDL_SCANCODE_UP;break;
case 12:kbdevent = SDL_SCANCODE_DOWN;break;
case 13:kbdevent = SDL_SCANCODE_LEFT;break;
case 14:kbdevent = SDL_SCANCODE_RIGHT;break;
case 0: ms_event.event = 1;
ms_event.event_type |= MS_EVENT_MOUSE_LPRESS;
ms_event.tl1 = 1;
break;
case 8: ms_event.event = 1;
ms_event.event_type |= MS_EVENT_MOUSE_LPRESS|MS_EVENT_MOUSE_LDBLCLK;
ms_event.tl1 = 1;
break;
case 1: ms_event.event = 1;
ms_event.event_type |= MS_EVENT_MOUSE_RPRESS;
ms_event.tl1 = 1;
break;
default: break;
}
} else if (e.type == SDL_JOYBUTTONUP) {
switch (e.jbutton.button) {
case 0: ms_event.event = 1;
ms_event.event_type |= MS_EVENT_MOUSE_LRELEASE;
ms_event.tl1 = 0;
break;
case 8:
case 1: ms_event.event = 1;
ms_event.event_type |= MS_EVENT_MOUSE_RRELEASE;
ms_event.tl1 = 1;
break;
default: break;
}
} }
if (kbdevent != SDL_Scancode{}) { if (kbdevent != SDL_Scancode{}) {
auto code =sdl_keycode_map.get_bios_code(kbdevent,false, false); auto code =sdl_keycode_map.get_bios_code(kbdevent,false, false);
std::lock_guard _(_mx); std::lock_guard _(_mx);
_keyboard_queue.push(code); _keyboard_queue.push(code);
} }
@ -1000,3 +1044,43 @@ bool SDLContext::is_crt_enabled() const
std::lock_guard _(_mx); std::lock_guard _(_mx);
return _enable_crt; return _enable_crt;
} }
SDLContext::JoystickButton SDLContext::button_from_string(std::string_view s) {
if (s=="enter") return JoystickButton::enter;
if (s=="space") return JoystickButton::space;
if (s=="ctrl") return JoystickButton::ctrl;
if (s=="lclick") return JoystickButton::lclick;
if (s=="rclick") return JoystickButton::rclick;
if (s=="ctrl+lclick") return JoystickButton::ctrl_lclick;
if (s=="escape") return JoystickButton::escape;
if (s=="up") return JoystickButton::up;
if (s=="down") return JoystickButton::down;
if (s=="left") return JoystickButton::left;
if (s=="right") return JoystickButton::right;
if (s=="turn_left") return JoystickButton::turn_left;
if (s=="turn_right") return JoystickButton::turn_right;
if (s=="merge_group") return JoystickButton::merge;
if (s=="split1") return JoystickButton::split1;
if (s=="split2") return JoystickButton::split2;
if (s=="split3") return JoystickButton::split3;
if (s=="split4") return JoystickButton::split4;
if (s=="split5") return JoystickButton::split5;
if (s=="split6") return JoystickButton::split6;
if (s=="map") return JoystickButton::map;
if (s=="F1") return JoystickButton::F1;
if (s=="F2") return JoystickButton::F2;
if (s=="F3") return JoystickButton::F3;
if (s=="F4") return JoystickButton::F4;
if (s=="F5") return JoystickButton::F5;
if (s=="F6") return JoystickButton::F6;
if (s=="F7") return JoystickButton::F7;
if (s=="F8") return JoystickButton::F8;
if (s=="F9") return JoystickButton::F9;
if (s=="F10") return JoystickButton::F10;
if (s=="F11") return JoystickButton::F11;
if (s=="F12") return JoystickButton::F12;
if (s=="backspace") return JoystickButton::backspace;
if (s=="mod_key") return JoystickButton::mod_key;
return JoystickButton::disabled;
}

View file

@ -42,6 +42,57 @@ public:
const char *audioDevice; const char *audioDevice;
}; };
enum class JoystickButton : char{
disabled,
enter,
space,
ctrl,
lclick,
rclick,
ctrl_lclick,
escape,
up,
down,
left,
right,
turn_left,
turn_right,
merge,
split1,
split2,
split3,
split4,
split5,
split6,
map,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
backspace,
mod_key
};
static JoystickButton button_from_string(std::string_view s);
struct JoystickConfig {
bool enabled;
bool swap_axis;
short walk_deadzone;
short cursor_deadzone;
JoystickButton buttons[32];
JoystickButton buttons_mod[32];
};
struct AudioInfo { struct AudioInfo {
int freq; int freq;
}; };
@ -50,6 +101,8 @@ public:
void set_window_icon(const void *icon_data, size_t icon_size); void set_window_icon(const void *icon_data, size_t icon_size);
void configure_controller(const JoystickConfig &cfg);
void close_video(); void close_video();
AudioInfo init_audio(const AudioConfig &config, SDL_AudioCallback cb, void *cb_ctx); AudioInfo init_audio(const AudioConfig &config, SDL_AudioCallback cb, void *cb_ctx);
@ -105,6 +158,8 @@ public:
void enable_crt_filter(bool enable); void enable_crt_filter(bool enable);
bool is_crt_enabled() const; bool is_crt_enabled() const;
bool is_joystick_used() const;
protected: protected:
struct SDL_Deleter { struct SDL_Deleter {
@ -168,6 +223,9 @@ protected:
CrtFilterType _crt_filter= CrtFilterType::autoselect; CrtFilterType _crt_filter= CrtFilterType::autoselect;
bool _enable_crt = true; bool _enable_crt = true;
std::function<void()> _quit_callback; std::function<void()> _quit_callback;
JoystickConfig _jcontrol_map;
bool _jcontrol_mod_key = false;
bool _jcontrol_used = false;
std::unique_ptr<SDL_Window, SDL_Deleter> _window; std::unique_ptr<SDL_Window, SDL_Deleter> _window;
std::unique_ptr<SDL_Renderer, SDL_Deleter> _renderer; std::unique_ptr<SDL_Renderer, SDL_Deleter> _renderer;
@ -198,10 +256,8 @@ protected:
SpriteList _sprites; SpriteList _sprites;
int axis1_cooldown = 0; int axis1_cooldown = -1;
int axis2_cooldown = 0; int axis2_cooldown = -1;
int axis3_cooldown = 0;
int axis4_cooldown = 0;
int check_axis_dir(int &cooldown, int value); int check_axis_dir(int &cooldown, int value);
Uint32 _update_request_event; Uint32 _update_request_event;
@ -242,5 +298,7 @@ protected:
void update_zindex(); void update_zindex();
void joystick_handle(); void joystick_handle();
void generate_j_event(int button, char up);
static int adjust_deadzone(int v, short deadzone);
}; };

View file

@ -56,6 +56,84 @@
[audio] [audio]
#device= #device=
### controller
#
# enable = enable or disable controller (must be connected)
# swap_sticks = swap levers
# buttonX = map button to action
# mod+buttonX = map button pressed with mod button together to action
# disabled - button is disabled
# enter - ENTER key (start battle, etc),
# space - SPACE key (wall action, open door, next in battle, fast action)
# ctrl - control mod key,
# lclick - left mouse click,
# rclick - right mouse click (exit),
# ctrl_lclick - ctrl+lclick (split group, fast action)
# escape - escape key,
# up - go forward, up in lists,
# down - go backward, down in lists
# left - go left
# right - go right
# turn_left - turn left
# turn_right - turn right
# merge - merge group
# split1 - split first character
# split2 - split second character
# split3,
# split4,
# split5,
# split6,
# map, - open map (TAB)
# F1 - Settings
# F2 - Save
# F3 - Load
# F4 - Rest
# F5 - Autosave
# F6 - Book
# F7 - Spell casting
# F8 - Attack (in battle)
# F9 - Move (in battle)
# F10 - Armor and inventory (in battle)
# F11 - Run/Flee (in battle)
# F12 - No action (in battle)
# backspace - cancel action (in battle)
# mod_key
#
# walk_deadzone = specifies deadzone for walk (0-32768)
# cursor_deadzone = specifies deadzone for cursor movement (0-32768)
[controller]
#enabled=on
#swap_sticks=off
#button0=lclick
#button1=rclick
#button2=enter
#button3=space
#button5=F1
#button4=F2
#mod+button4=F5
#button6=F3
#button8=ctrl_lclick
#button10=mod_key
#mod+button10=mod_key
#button11=map
#mod+button11=F6
#button12=merge
#button14=left
#button13=right
#button9=backspace
#mod+button5=escape
#mod+button9=F4
#mod+button12=F7
#mod+button0=F8
#mod+button1=F9
#mod+button2=F10
#mod+button3=F11
#mod+button14=F12
#mod+button13=backspace
### localization settings ### localization settings
# #
# keyboard_layout = cz_querty, cz_quertz, us # keyboard_layout = cz_querty, cz_quertz, us