mirror of
https://github.com/ondra-novak/gates_of_skeldal.git
synced 2025-07-05 14:10:27 -04:00
a lot of changes and support languages
This commit is contained in:
parent
185a6e5382
commit
f55f92a88b
38 changed files with 1221 additions and 467 deletions
|
@ -14,6 +14,9 @@ endif()
|
||||||
|
|
||||||
include_directories(.)
|
include_directories(.)
|
||||||
|
|
||||||
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin/)
|
||||||
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib/)
|
||||||
|
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib/)
|
||||||
|
|
||||||
include_directories( ${SDL2_INCLUDE_DIRS})
|
include_directories( ${SDL2_INCLUDE_DIRS})
|
||||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -funsigned-char")
|
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -funsigned-char")
|
||||||
|
@ -21,3 +24,4 @@ enable_testing()
|
||||||
add_subdirectory(libs)
|
add_subdirectory(libs)
|
||||||
add_subdirectory(platform)
|
add_subdirectory(platform)
|
||||||
add_subdirectory(game)
|
add_subdirectory(game)
|
||||||
|
|
||||||
|
|
|
@ -36,13 +36,8 @@ console.c
|
||||||
gen_stringtable.c
|
gen_stringtable.c
|
||||||
advconfig.c
|
advconfig.c
|
||||||
temp_storage.cpp
|
temp_storage.cpp
|
||||||
|
lang.c
|
||||||
${CMAKE_BINARY_DIR}/default_font.cpp
|
${CMAKE_BINARY_DIR}/default_font.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(skeldal ${files})
|
add_library(skeldal_main ${files})
|
||||||
target_link_libraries(skeldal
|
|
||||||
skeldal_libs
|
|
||||||
skeldal_platform
|
|
||||||
skeldal_sdl
|
|
||||||
skeldal_libs
|
|
||||||
${SDL2_LIBRARIES} pthread)
|
|
||||||
|
|
|
@ -428,7 +428,16 @@ static void draw_amap_sector(int x,int y,int sector,int mode,int turn,int line1,
|
||||||
{
|
{
|
||||||
i=(j+turn)&3;
|
i=(j+turn)&3;
|
||||||
if (!(q[i].flags & SD_TRANSPARENT)||(q[i].flags & SD_SECRET)) curcolor=line1;
|
if (!(q[i].flags & SD_TRANSPARENT)||(q[i].flags & SD_SECRET)) curcolor=line1;
|
||||||
else if (q[i].flags & SD_PLAY_IMPS) curcolor=line2;
|
else if ((q[i].flags & SD_PLAY_IMPS) && (
|
||||||
|
true_seeing || (q[i].flags & SD_TRUESEE) == 0)) {
|
||||||
|
int nx = ss->step_next[i];
|
||||||
|
if (nx && !true_seeing) {
|
||||||
|
if (map_sides[(nx*4)+((j+2)&3)].flags & SD_TRUESEE) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
curcolor=line2;
|
||||||
|
}
|
||||||
else curcolor=AUTOMAP_FORE;
|
else curcolor=AUTOMAP_FORE;
|
||||||
if (q[i].flags & SD_INVIS) curcolor=AUTOMAP_FORE;
|
if (q[i].flags & SD_INVIS) curcolor=AUTOMAP_FORE;
|
||||||
if (curcolor!=AUTOMAP_FORE)
|
if (curcolor!=AUTOMAP_FORE)
|
||||||
|
|
|
@ -828,6 +828,7 @@ static int draw_basic_sector(int celx, int cely, int sector) {
|
||||||
|
|
||||||
int tmask = true_seeing?SD_TRUESEE:0;
|
int tmask = true_seeing?SD_TRUESEE:0;
|
||||||
|
|
||||||
|
|
||||||
w = &map_sides[sector * 4];
|
w = &map_sides[sector * 4];
|
||||||
q = &w[dirs[1]];
|
q = &w[dirs[1]];
|
||||||
obl = GET_OBLOUK(q);
|
obl = GET_OBLOUK(q);
|
||||||
|
@ -836,13 +837,13 @@ static int draw_basic_sector(int celx, int cely, int sector) {
|
||||||
show_cel2(celx, cely, ablock(num_ofsets[OBL_NUM] + obl), 0, 0, 1, ghost_walls );
|
show_cel2(celx, cely, ablock(num_ofsets[OBL_NUM] + obl), 0, 0, 1, ghost_walls );
|
||||||
if (q->flags & SD_RIGHT_ARC && q->oblouk & 0x0f)
|
if (q->flags & SD_RIGHT_ARC && q->oblouk & 0x0f)
|
||||||
show_cel2(celx, cely, ablock(num_ofsets[OBL2_NUM] + obl), 0, 0, 2, ghost_walls);
|
show_cel2(celx, cely, ablock(num_ofsets[OBL2_NUM] + obl), 0, 0, 2, ghost_walls);
|
||||||
if (q->flags & SD_PRIM_VIS && q->prim)
|
if (q->flags & (SD_PRIM_VIS|tmask) && q->prim)
|
||||||
show_cel2(celx, cely,
|
show_cel2(celx, cely,
|
||||||
ablock(
|
ablock(
|
||||||
num_ofsets[MAIN_NUM] + q->prim
|
num_ofsets[MAIN_NUM] + q->prim
|
||||||
+ (q->prim_anim >> 4)), 0, 0,
|
+ (q->prim_anim >> 4)), 0, 0,
|
||||||
1 + (q->oblouk & SD_POSITION), ghost_walls | (q->flags & tmask));
|
1 + (q->oblouk & SD_POSITION), ghost_walls | (q->flags & tmask));
|
||||||
if (q->flags & SD_SEC_VIS && q->sec) {
|
if (q->flags & (SD_SEC_VIS|tmask) && q->sec) {
|
||||||
if (q->side_tag & SD_SHIFTUP) {
|
if (q->side_tag & SD_SHIFTUP) {
|
||||||
if (cely != 0) {
|
if (cely != 0) {
|
||||||
show_cel2(celx, cely - 1,
|
show_cel2(celx, cely - 1,
|
||||||
|
@ -866,13 +867,13 @@ static int draw_basic_sector(int celx, int cely, int sector) {
|
||||||
if (left_shiftup)
|
if (left_shiftup)
|
||||||
show_cel(celx, cely, ablock(num_ofsets[LEFT_NUM] + left_shiftup), 0,
|
show_cel(celx, cely, ablock(num_ofsets[LEFT_NUM] + left_shiftup), 0,
|
||||||
0, 2, ghost_walls), left_shiftup = 0;
|
0, 2, ghost_walls), left_shiftup = 0;
|
||||||
if (q->flags & SD_PRIM_VIS && q->prim )
|
if (q->flags & (SD_PRIM_VIS|tmask) && q->prim )
|
||||||
show_cel(-celx, cely,
|
show_cel(-celx, cely,
|
||||||
ablock(
|
ablock(
|
||||||
num_ofsets[LEFT_NUM] + q->prim
|
num_ofsets[LEFT_NUM] + q->prim
|
||||||
+ (q->prim_anim >> 4)), 0, 0,
|
+ (q->prim_anim >> 4)), 0, 0,
|
||||||
2 + (q->oblouk & SD_POSITION), ghost_walls | (q->flags & tmask));
|
2 + (q->oblouk & SD_POSITION), ghost_walls | (q->flags & tmask));
|
||||||
if (q->flags & SD_SEC_VIS && q->sec) {
|
if (q->flags & (SD_SEC_VIS|tmask) && q->sec) {
|
||||||
if (q->side_tag & SD_SHIFTUP) {
|
if (q->side_tag & SD_SHIFTUP) {
|
||||||
if (celx != 0) {
|
if (celx != 0) {
|
||||||
left_shiftup = q->sec + (q->sec_anim >> 4);
|
left_shiftup = q->sec + (q->sec_anim >> 4);
|
||||||
|
@ -898,13 +899,13 @@ static int draw_basic_sector(int celx, int cely, int sector) {
|
||||||
if (right_shiftup)
|
if (right_shiftup)
|
||||||
show_cel(celx, cely, ablock(num_ofsets[RIGHT_NUM] + right_shiftup),
|
show_cel(celx, cely, ablock(num_ofsets[RIGHT_NUM] + right_shiftup),
|
||||||
0, 0, 3, ghost_walls), right_shiftup = 0;
|
0, 0, 3, ghost_walls), right_shiftup = 0;
|
||||||
if (q->flags & SD_PRIM_VIS && q->prim )
|
if (q->flags & (SD_PRIM_VIS|tmask) && q->prim )
|
||||||
show_cel(celx, cely,
|
show_cel(celx, cely,
|
||||||
ablock(
|
ablock(
|
||||||
num_ofsets[RIGHT_NUM] + q->prim
|
num_ofsets[RIGHT_NUM] + q->prim
|
||||||
+ (q->prim_anim >> 4)), 0, 0,
|
+ (q->prim_anim >> 4)), 0, 0,
|
||||||
3 + (q->oblouk & SD_POSITION), ghost_walls | (q->flags & tmask));
|
3 + (q->oblouk & SD_POSITION), ghost_walls | (q->flags & tmask));
|
||||||
if (q->flags & SD_SEC_VIS && q->sec) {
|
if (q->flags & (SD_SEC_VIS|tmask) && q->sec) {
|
||||||
if (q->side_tag & SD_SHIFTUP) {
|
if (q->side_tag & SD_SHIFTUP) {
|
||||||
if (celx != 0)
|
if (celx != 0)
|
||||||
right_shiftup = q->sec + (q->sec_anim >> 4);
|
right_shiftup = q->sec + (q->sec_anim >> 4);
|
||||||
|
@ -1009,22 +1010,22 @@ int draw_sloup_sector(int celx,int cely,int sector)
|
||||||
show_cel2(celx,cely,ablock(num_ofsets[OBL_NUM]+obl),0,0,1, ghost_walls);
|
show_cel2(celx,cely,ablock(num_ofsets[OBL_NUM]+obl),0,0,1, ghost_walls);
|
||||||
if (q->flags & SD_RIGHT_ARC && q->oblouk)
|
if (q->flags & SD_RIGHT_ARC && q->oblouk)
|
||||||
show_cel2(celx,cely,ablock(num_ofsets[OBL2_NUM]+obl),0,0,2, ghost_walls);
|
show_cel2(celx,cely,ablock(num_ofsets[OBL2_NUM]+obl),0,0,2, ghost_walls);
|
||||||
if (q->flags & SD_PRIM_VIS && q->prim )
|
if (q->flags & (SD_PRIM_VIS|tmask) && q->prim )
|
||||||
show_cel2(celx,cely,ablock(num_ofsets[MAIN_NUM]+q->prim+(q->prim_anim>>4)),0,0,1+(q->oblouk & SD_POSITION), ghost_walls | (q->flags & tmask));
|
show_cel2(celx,cely,ablock(num_ofsets[MAIN_NUM]+q->prim+(q->prim_anim>>4)),0,0,1+(q->oblouk & SD_POSITION), ghost_walls | (q->flags & tmask));
|
||||||
if (celx<=0)
|
if (celx<=0)
|
||||||
{
|
{
|
||||||
q=&w[dirs[0]];
|
q=&w[dirs[0]];
|
||||||
if (q->flags & SD_PRIM_VIS && q->prim)
|
if (q->flags & (SD_PRIM_VIS|tmask) && q->prim)
|
||||||
show_cel(-celx,cely,ablock(num_ofsets[LEFT_NUM]+q->prim+(q->prim_anim>>4)),0,0,2+(q->oblouk & SD_POSITION), ghost_walls| (q->flags & tmask));
|
show_cel(-celx,cely,ablock(num_ofsets[LEFT_NUM]+q->prim+(q->prim_anim>>4)),0,0,2+(q->oblouk & SD_POSITION), ghost_walls| (q->flags & tmask));
|
||||||
}
|
}
|
||||||
if (celx>=0)
|
if (celx>=0)
|
||||||
{
|
{
|
||||||
q=&w[dirs[2]];
|
q=&w[dirs[2]];
|
||||||
if (q->flags & SD_PRIM_VIS && q->prim)
|
if (q->flags & (SD_PRIM_VIS|tmask) && q->prim)
|
||||||
show_cel(celx,cely,ablock(num_ofsets[RIGHT_NUM]+q->prim+(q->prim_anim>>4)),0,0,3+(q->oblouk & SD_POSITION), ghost_walls | (q->flags & tmask));
|
show_cel(celx,cely,ablock(num_ofsets[RIGHT_NUM]+q->prim+(q->prim_anim>>4)),0,0,3+(q->oblouk & SD_POSITION), ghost_walls | (q->flags & tmask));
|
||||||
}
|
}
|
||||||
q=&w[dirs[1]];
|
q=&w[dirs[1]];
|
||||||
if (q->flags & SD_SEC_VIS && q->sec && cely!=0) {
|
if (q->flags & (SD_SEC_VIS|tmask) && q->sec && cely!=0) {
|
||||||
if (q->flags & SD_SPEC)
|
if (q->flags & SD_SPEC)
|
||||||
show_cel2(celx,cely-1,ablock(num_ofsets[MAIN_NUM]+q->sec+(q->sec_anim>>4)),0,0,2, ghost_walls| (q->flags & tmask));
|
show_cel2(celx,cely-1,ablock(num_ofsets[MAIN_NUM]+q->sec+(q->sec_anim>>4)),0,0,2, ghost_walls| (q->flags & tmask));
|
||||||
else
|
else
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <libs/pcx.h>
|
#include <libs/pcx.h>
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include "lang.h"
|
||||||
|
|
||||||
typedef struct t_paragraph
|
typedef struct t_paragraph
|
||||||
{
|
{
|
||||||
|
@ -103,6 +104,7 @@ static char code_page=1;
|
||||||
static char case_click(int id,int xa,int ya,int xr,int yr);
|
static char case_click(int id,int xa,int ya,int xr,int yr);
|
||||||
static char ask_who_proc(int id,int xa,int ya,int xr,int yr);
|
static char ask_who_proc(int id,int xa,int ya,int xr,int yr);
|
||||||
|
|
||||||
|
static TSTRINGTABLE *dialogy_strtable = NULL;
|
||||||
|
|
||||||
#define CLK_DIALOG 3
|
#define CLK_DIALOG 3
|
||||||
static T_CLK_MAP clk_dialog[CLK_DIALOG]=
|
static T_CLK_MAP clk_dialog[CLK_DIALOG]=
|
||||||
|
@ -288,9 +290,10 @@ static void goto_paragraph(int prgf)
|
||||||
while (1);
|
while (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *transfer_text(char *source,char *target)
|
static char *transfer_text(const char *source,char *target)
|
||||||
{
|
{
|
||||||
char *orgn=source,*ot=target;
|
const char *orgn=source;
|
||||||
|
char *ot=target;
|
||||||
int num;
|
int num;
|
||||||
while (*source)
|
while (*source)
|
||||||
{
|
{
|
||||||
|
@ -357,7 +360,7 @@ static char *transfer_text(char *source,char *target)
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *conv_text(char *source)
|
static char *conv_text(const char *source)
|
||||||
{
|
{
|
||||||
if (string_buffer==NULL) string_buffer=getmem(STR_BUFF_SIZ);
|
if (string_buffer==NULL) string_buffer=getmem(STR_BUFF_SIZ);
|
||||||
return transfer_text(source,string_buffer);
|
return transfer_text(source,string_buffer);
|
||||||
|
@ -370,18 +373,23 @@ static char zjisti_typ()
|
||||||
|
|
||||||
static char *Get_string()
|
static char *Get_string()
|
||||||
{
|
{
|
||||||
|
const char *start = (const char *)ablock(H_DIALOGY_DAT);
|
||||||
char *c,i;
|
char *c,i;
|
||||||
if (*pc==P_STRING)
|
if (*pc==P_STRING)
|
||||||
{
|
{
|
||||||
|
int ofs = pc - start+1;
|
||||||
pc++;
|
pc++;
|
||||||
c=conv_text(pc);
|
const char *txt = stringtable_find(dialogy_strtable,ofs, pc);
|
||||||
|
c=conv_text(txt);
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
pc+=strlen(pc)+1;
|
pc+=strlen(pc)+1;
|
||||||
|
ofs = pc - start;
|
||||||
if ((i=zjisti_typ())==P_STRING)
|
if ((i=zjisti_typ())==P_STRING)
|
||||||
{
|
{
|
||||||
|
const char *txt = stringtable_find(dialogy_strtable,ofs, pc);
|
||||||
pc++;
|
pc++;
|
||||||
c=transfer_text(pc,c);
|
c=transfer_text(txt,c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while(i==P_STRING);
|
while(i==P_STRING);
|
||||||
|
@ -1222,12 +1230,22 @@ static void cast_spell(int spell)
|
||||||
add_spell(spell,cil,cil,1);
|
add_spell(spell,cil,cil,1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void free_dialog_stringtable() {
|
||||||
|
stringtable_free(dialogy_strtable);
|
||||||
|
}
|
||||||
|
|
||||||
void do_dialog()
|
void do_dialog()
|
||||||
{
|
{
|
||||||
int i,p1,p2,p3;
|
int i,p1,p2,p3;
|
||||||
char *c;
|
char *c;
|
||||||
|
|
||||||
|
if (!dialogy_strtable) {
|
||||||
|
dialogy_strtable = lang_load("dialogs.csv");
|
||||||
|
if (dialogy_strtable) {
|
||||||
|
atexit(free_dialog_stringtable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
i=Get_short();p3=0;
|
i=Get_short();p3=0;
|
||||||
|
|
|
@ -36,8 +36,8 @@ short zooming_points[ZOOM_PHASES][4]
|
||||||
{480,271,80,28},
|
{480,271,80,28},
|
||||||
{460,259,90,31}
|
{460,259,90,31}
|
||||||
};
|
};
|
||||||
int zooming_step=1;
|
int zooming_step=2;
|
||||||
int rot_phases=1;
|
int rot_phases=2;
|
||||||
int yreq;
|
int yreq;
|
||||||
int last_scale;
|
int last_scale;
|
||||||
char secnd_shade=1;
|
char secnd_shade=1;
|
||||||
|
|
|
@ -114,7 +114,7 @@ static __inline int rangrnd(int a, int b) {return rnd(b-a+1)+a;}
|
||||||
#define COL_RAMEC RGB555(31,31,26) //((31*32+31)*32+26)
|
#define COL_RAMEC RGB555(31,31,26) //((31*32+31)*32+26)
|
||||||
|
|
||||||
#undef RGB
|
#undef RGB
|
||||||
#define RGB(r,g,b) (((r)>>3)*2048+((g)>>3)*64+((b)>>3))
|
#define RGB(r,g,b) RGB888(r,g,b)
|
||||||
#define GET_R_COLOR(col) ((col & 0xF800)>>8)
|
#define GET_R_COLOR(col) ((col & 0xF800)>>8)
|
||||||
#define GET_G_COLOR(col) ((col & 0x07E0)>>3)
|
#define GET_G_COLOR(col) ((col & 0x07E0)>>3)
|
||||||
#define GET_B_COLOR(col) ((col & 0x001F)<<3)
|
#define GET_B_COLOR(col) ((col & 0x001F)<<3)
|
||||||
|
@ -342,6 +342,7 @@ typedef enum skeldal_folders_tag {
|
||||||
SR_DIALOGS,
|
SR_DIALOGS,
|
||||||
SR_SAVES,
|
SR_SAVES,
|
||||||
SR_WORK,
|
SR_WORK,
|
||||||
|
SR_LANG,
|
||||||
|
|
||||||
|
|
||||||
SR_COUNT} SKELDAL_FOLDERS_TAG;
|
SR_COUNT} SKELDAL_FOLDERS_TAG;
|
||||||
|
@ -597,7 +598,7 @@ extern char set_halucination;
|
||||||
extern int hal_sector; //cislo sektoru a smeru pri halucinaci
|
extern int hal_sector; //cislo sektoru a smeru pri halucinaci
|
||||||
extern int hal_dir;
|
extern int hal_dir;
|
||||||
extern char side_touched; //promena se nastavuje na 1 pri kazdem uspesnem dotyku steny
|
extern char side_touched; //promena se nastavuje na 1 pri kazdem uspesnem dotyku steny
|
||||||
extern char *texty_knihy; //jmeno souboru s textamy knihy
|
extern const char *texty_knihy; //jmeno souboru s textamy knihy
|
||||||
extern int cur_page; //cislo stranky v knize;
|
extern int cur_page; //cislo stranky v knize;
|
||||||
extern int32_t game_time; //hraci cas
|
extern int32_t game_time; //hraci cas
|
||||||
extern char autoattack;
|
extern char autoattack;
|
||||||
|
@ -1049,9 +1050,15 @@ typedef struct tshop
|
||||||
const TPRODUCT *list;
|
const TPRODUCT *list;
|
||||||
}TSHOP;
|
}TSHOP;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct tshop_product_state_tag {
|
||||||
|
uint16_t count;
|
||||||
|
uint16_t previous_price;
|
||||||
|
} TSHOP_PRODUCT_STATE;
|
||||||
|
|
||||||
typedef struct tshop_all_state {
|
typedef struct tshop_all_state {
|
||||||
const TPRODUCT *first_product;
|
const TPRODUCT *first_product;
|
||||||
int32_t *first_state;
|
TSHOP_PRODUCT_STATE *first_state;
|
||||||
size_t count_states;
|
size_t count_states;
|
||||||
} TSHOP_ALL_STATE;
|
} TSHOP_ALL_STATE;
|
||||||
|
|
||||||
|
@ -1674,7 +1681,7 @@ void add_window(int x,int y,int xs,int ys,int texture,int border,int txtx,int tx
|
||||||
int message(int butts,char def,char canc,char *keys,...);
|
int message(int butts,char def,char canc,char *keys,...);
|
||||||
void type_text(EVENT_MSG *msg,void **data); //event procedura (parms: X,Y,TEXT,MAX_SPACE,MAX_CHARS);
|
void type_text(EVENT_MSG *msg,void **data); //event procedura (parms: X,Y,TEXT,MAX_SPACE,MAX_CHARS);
|
||||||
void type_text_v2(va_list args);//char *text_buffer,int x,int y,int max_size,int max_chars,int font,int color,void (*exit_proc)(char));
|
void type_text_v2(va_list args);//char *text_buffer,int x,int y,int max_size,int max_chars,int font,int color,void (*exit_proc)(char));
|
||||||
void zalamovani(char *source,char *target,int maxxs,int *xs,int *ys);
|
void zalamovani(const char *source,char *target,int maxxs,int *xs,int *ys);
|
||||||
const void *col_load(const void *data, int32_t *size);
|
const void *col_load(const void *data, int32_t *size);
|
||||||
void open_story_file(void);
|
void open_story_file(void);
|
||||||
void write_story_text(char *text);
|
void write_story_text(char *text);
|
||||||
|
@ -1701,9 +1708,15 @@ TMPFILE_RD *enc_open(const char *filename); //dekoduje a otevira TXT soubor (ENC
|
||||||
void enc_close(TMPFILE_RD *fil);
|
void enc_close(TMPFILE_RD *fil);
|
||||||
int load_string_list_ex(char ***list,const char *filename);
|
int load_string_list_ex(char ***list,const char *filename);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int hprice;
|
||||||
|
const char *message;
|
||||||
|
char canceled;
|
||||||
|
} THAGGLERESULT;
|
||||||
|
|
||||||
int smlouvat_nakup(int cena,int ponuka,int posledni,int puvod,int pocet);
|
int smlouvat_nakup(int cena,int ponuka,int posledni,int puvod,int pocet);
|
||||||
int smlouvat_prodej(int cena,int ponuka,int posledni,int puvod,int pocet);
|
int smlouvat_prodej(int cena,int ponuka,int posledni,int puvod,int pocet);
|
||||||
int smlouvat(int cena,int puvod,int pocet,int money,char mode);
|
THAGGLERESULT smlouvat_dlg(int cena,int puvod,int pocet,int posledni, int money,char mode);
|
||||||
|
|
||||||
void disable_intro(void);
|
void disable_intro(void);
|
||||||
void show_jrc_logo(char *filename);
|
void show_jrc_logo(char *filename);
|
||||||
|
|
|
@ -248,7 +248,7 @@ static char test_kriterii(void)
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
hodn=temp_storage_find(text)>=0;
|
hodn=temp_storage_find(concat2(text,".map"))>=0;
|
||||||
/* char c[200];
|
/* char c[200];
|
||||||
sprintf(c,"%s.TMP",text);
|
sprintf(c,"%s.TMP",text);
|
||||||
hodn=!check_file_exists(c);*/
|
hodn=!check_file_exists(c);*/
|
||||||
|
@ -356,6 +356,7 @@ static void preskoc_prikaz(void)
|
||||||
switch (ODD)
|
switch (ODD)
|
||||||
{
|
{
|
||||||
case 0:cti_retezec(1,&text,0,0);ending=1;break;
|
case 0:cti_retezec(1,&text,0,0);ending=1;break;
|
||||||
|
case '\r':continue;
|
||||||
case '\n':if (ending && uroven==0) return;break;
|
case '\n':if (ending && uroven==0) return;break;
|
||||||
case EOF: if (uroven!=0)ex_error(OD_OUT);return;break;
|
case EOF: if (uroven!=0)ex_error(OD_OUT);return;break;
|
||||||
case '{': if (last==OD_CRIT || last==OD_NEWLINE) uroven++;break;
|
case '{': if (last==OD_CRIT || last==OD_NEWLINE) uroven++;break;
|
||||||
|
@ -422,7 +423,7 @@ static char flp_validate(word sector, void *ctx)
|
||||||
int *found_place = (int *)ctx;
|
int *found_place = (int *)ctx;
|
||||||
char c;
|
char c;
|
||||||
|
|
||||||
if (found_place) return 0;
|
if (*found_place) return 0;
|
||||||
if (mob_map[sector])
|
if (mob_map[sector])
|
||||||
{
|
{
|
||||||
m=mobs+mob_map[sector]-1;
|
m=mobs+mob_map[sector]-1;
|
||||||
|
@ -485,7 +486,7 @@ static char load_index_map(int index)
|
||||||
if (!GlobEvent(MAGLOB_LEAVEMAP,viewsector,viewdir)) return 0;
|
if (!GlobEvent(MAGLOB_LEAVEMAP,viewsector,viewdir)) return 0;
|
||||||
viewsector=lv;
|
viewsector=lv;
|
||||||
strncpy(x.name,index_tab[index].mapname,12);
|
strncpy(x.name,index_tab[index].mapname,12);
|
||||||
x.start_pos=lv;
|
x.start_pos=0;
|
||||||
x.dir=0;
|
x.dir=0;
|
||||||
macro_load_another_map(&x);
|
macro_load_another_map(&x);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -131,7 +131,7 @@ void add_window(int x,int y,int xs,int ys,int texture,int border,int txtx,int tx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void zalamovani(char *source,char *target,int maxxs,int *xs,int *ys)
|
void zalamovani(const char *source,char *target,int maxxs,int *xs,int *ys)
|
||||||
{
|
{
|
||||||
strcpy(target,source);
|
strcpy(target,source);
|
||||||
xs[0]=0;
|
xs[0]=0;
|
||||||
|
@ -1354,11 +1354,11 @@ TMPFILE_RD *enc_open(const char *filename)
|
||||||
if (f==NULL) return NULL;
|
if (f==NULL) return NULL;
|
||||||
encdata = load_file_to_string(f, &size);
|
encdata = load_file_to_string(f, &size);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
}
|
|
||||||
for (int i = 0; i < size; ++i) {
|
for (int i = 0; i < size; ++i) {
|
||||||
last = (last + encdata[i]) & 0xFF;
|
last = (last + encdata[i]) & 0xFF;
|
||||||
encdata[i] = last;
|
encdata[i] = last;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
temp_storage_store("__enc_temp", encdata, size);
|
temp_storage_store("__enc_temp", encdata, size);
|
||||||
free(encdata);
|
free(encdata);
|
||||||
return temp_storage_open("__enc_temp");
|
return temp_storage_open("__enc_temp");
|
||||||
|
@ -1478,14 +1478,12 @@ static void smlouvat_enter(EVENT_MSG *msg,OBJREC *o)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int smlouvat(int cena,int puvod,int pocet,int money,char mode)
|
THAGGLERESULT smlouvat_dlg(int cena,int puvod,int pocet,int posledni, int money,char mode)
|
||||||
{
|
{
|
||||||
int ponuka=0,posledni=0;
|
char buffer[20];
|
||||||
char text[255],*c,buffer[20];
|
int ponuka;
|
||||||
int y,yu,xu;
|
THAGGLERESULT res;
|
||||||
int temp1,temp2;
|
|
||||||
|
|
||||||
cena,puvod,pocet,money;text[0]=0;text[1]=0;
|
|
||||||
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,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]);
|
||||||
|
@ -1496,46 +1494,45 @@ int smlouvat(int cena,int puvod,int pocet,int money,char mode)
|
||||||
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);
|
||||||
do
|
|
||||||
{
|
{
|
||||||
redraw_window();
|
redraw_window();
|
||||||
schovej_mysku();set_font(H_FBOLD,RGB555(31,31,31));
|
schovej_mysku();set_font(H_FBOLD,RGB555(31,31,31));
|
||||||
c=text;yu=y=waktual->y+50;xu=waktual->x+10;
|
|
||||||
do {position(xu,y);outtext(c);y+=text_height(c)+1;c=strchr(c,0)+1;} while(*c);
|
|
||||||
ukaz_mysku();
|
ukaz_mysku();
|
||||||
showview(xu,yu,280,y-yu);
|
|
||||||
goto_control(10);
|
goto_control(10);
|
||||||
escape();
|
escape();
|
||||||
temp1=1;
|
res.message = 0;
|
||||||
if (o_aktual->id==20) cena=-1;
|
res.hprice = posledni;
|
||||||
else
|
res.canceled = 1;
|
||||||
|
if (o_aktual->id!=20)
|
||||||
{
|
{
|
||||||
|
res.canceled = 0;
|
||||||
get_value(0,10,buffer);
|
get_value(0,10,buffer);
|
||||||
if (buffer[0]==0) c=texty[240];
|
if (buffer[0]==0) res.message=texty[240];
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (sscanf(buffer,"%d",&ponuka)!=1) c=texty[237];
|
if (sscanf(buffer,"%d",&ponuka)!=1) res.message=texty[237];
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (ponuka>money && mode==1) c=texty[104];
|
if (ponuka>money && mode==1) {
|
||||||
|
message(1, 0, 0, texty[100], texty[104], texty[78]);
|
||||||
|
res.canceled = 1;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
int temp1;
|
||||||
if (mode) temp1=smlouvat_nakup(cena,ponuka,posledni,puvod,pocet);
|
if (mode) temp1=smlouvat_nakup(cena,ponuka,posledni,puvod,pocet);
|
||||||
else temp1=smlouvat_prodej(cena,ponuka,posledni,puvod,pocet+1);
|
else temp1=smlouvat_prodej(cena,ponuka,posledni,puvod,pocet+1);
|
||||||
posledni=ponuka;
|
res.hprice=ponuka;
|
||||||
if (rnd(100)<50) c=texty[230+temp1];else c=texty[250+temp1];
|
if (temp1) {
|
||||||
|
if (rnd(100)<50) res.message=texty[230+temp1];else res.message=texty[250+temp1];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
shadow_enabled=0;
|
|
||||||
}
|
}
|
||||||
if (c) zalamovani(c,text,280,&temp2,&temp2);
|
|
||||||
}
|
}
|
||||||
while (temp1!=0 && cena!=-1);
|
|
||||||
if (temp1==0) cena=ponuka;
|
|
||||||
close_current();
|
close_current();
|
||||||
shadow_enabled=1;
|
return res;
|
||||||
return cena;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------- JRC LOGO ----------------------------------
|
//----------------- JRC LOGO ----------------------------------
|
||||||
|
|
136
game/inv.c
136
game/inv.c
|
@ -18,7 +18,9 @@
|
||||||
#include <libs/pcx.h>
|
#include <libs/pcx.h>
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
|
|
||||||
|
#include "lang.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
@ -224,6 +226,36 @@ void load_items()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (lang_get_folder()) {
|
||||||
|
TSTRINGTABLE *str_table = lang_load("items.csv");
|
||||||
|
if (str_table) {
|
||||||
|
for (int i = 0; i < item_count; ++i) {
|
||||||
|
const char *trn = stringtable_find(str_table, i, NULL);
|
||||||
|
if (trn) {
|
||||||
|
char *trnw = local_strdup(trn);
|
||||||
|
char *sep = strchr(trnw, '\n');
|
||||||
|
if (sep != NULL) {
|
||||||
|
*sep = 0;
|
||||||
|
char *nx = sep+1;
|
||||||
|
--sep;
|
||||||
|
while (sep > trnw && isspace(*sep)) {
|
||||||
|
*sep = 0;
|
||||||
|
--sep;
|
||||||
|
}
|
||||||
|
sep = strchr(nx,0);
|
||||||
|
--sep;
|
||||||
|
while (sep > nx && isspace(*sep)) {
|
||||||
|
*sep = 0;
|
||||||
|
--sep;
|
||||||
|
}
|
||||||
|
strncpy(glob_items[i].popis, nx, sizeof(glob_items[i].popis)-1);
|
||||||
|
}
|
||||||
|
strncpy(glob_items[i].jmeno, trnw, sizeof(glob_items[i].jmeno)-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stringtable_free(str_table);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_items()
|
void init_items()
|
||||||
|
@ -2480,8 +2512,8 @@ static void rebuild_shops(const void *shop_ptr)
|
||||||
TPRODUCT *prod_iter = (TPRODUCT *)(shop_iter+max_shops);
|
TPRODUCT *prod_iter = (TPRODUCT *)(shop_iter+max_shops);
|
||||||
shop_all_state.first_product = prod_iter;
|
shop_all_state.first_product = prod_iter;
|
||||||
shop_all_state.count_states = products;
|
shop_all_state.count_states = products;
|
||||||
shop_all_state.first_state = (int32_t *)(prod_iter+products);
|
shop_all_state.first_state = (TSHOP_PRODUCT_STATE *)(prod_iter+products);
|
||||||
int32_t *state_iter = shop_all_state.first_state;
|
TSHOP_PRODUCT_STATE *state_iter = shop_all_state.first_state;
|
||||||
|
|
||||||
for(i=0;i<max_shops;i++) {
|
for(i=0;i<max_shops;i++) {
|
||||||
shop_list[i] = shop_iter;
|
shop_list[i] = shop_iter;
|
||||||
|
@ -2489,7 +2521,8 @@ static void rebuild_shops(const void *shop_ptr)
|
||||||
shop_iter->list = prod_iter;
|
shop_iter->list = prod_iter;
|
||||||
for (int j = 0; j < shop_iter->products; ++j) {
|
for (int j = 0; j < shop_iter->products; ++j) {
|
||||||
c = load_TPRODUCT(c, prod_iter);
|
c = load_TPRODUCT(c, prod_iter);
|
||||||
*state_iter += prod_iter->pocet;
|
state_iter->count = prod_iter->pocet;
|
||||||
|
state_iter->previous_price = 0;
|
||||||
++prod_iter;
|
++prod_iter;
|
||||||
++state_iter;
|
++state_iter;
|
||||||
}
|
}
|
||||||
|
@ -2515,10 +2548,16 @@ void load_shops(void)
|
||||||
ablock_free(sh);
|
ablock_free(sh);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t *get_product_count(const TPRODUCT *p) {
|
static uint16_t *get_product_count(const TPRODUCT *p) {
|
||||||
int32_t index = p - shop_all_state.first_product;
|
int32_t index = p - shop_all_state.first_product;
|
||||||
assert(index >= 0 && index < (int32_t)shop_all_state.count_states);
|
assert(index >= 0 && index < (int32_t)shop_all_state.count_states);
|
||||||
return shop_all_state.first_state + index;
|
return &shop_all_state.first_state[index].count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t *get_last_haggle_price(const TPRODUCT *p) {
|
||||||
|
int32_t index = p - shop_all_state.first_product;
|
||||||
|
assert(index >= 0 && index < (int32_t)shop_all_state.count_states);
|
||||||
|
return &shop_all_state.first_state[index].previous_price;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rebuild_keepers_items()
|
static void rebuild_keepers_items()
|
||||||
|
@ -2634,6 +2673,26 @@ static void display_keepers_items()
|
||||||
outtext(cur_shop->keeper);
|
outtext(cur_shop->keeper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *shop_keeper_bubble=NULL;
|
||||||
|
|
||||||
|
static void show_buble(int x, int y, int xs, const char *text) {
|
||||||
|
set_font(H_FTINY, NOSHADOW(0));
|
||||||
|
int newxs;
|
||||||
|
int newys;
|
||||||
|
char *buffer = (char *)alloca(strlen(text)+3);
|
||||||
|
zalamovani(text, buffer, xs-10, &newxs, &newys);
|
||||||
|
int lxs = newxs+10;
|
||||||
|
int lys = newys+10;
|
||||||
|
y-=newys+10;
|
||||||
|
x+=(xs-lxs)/2;
|
||||||
|
draw_rounded_rectangle(x,y,lxs, lys, 8,RGB888(0,0,0),RGB888(255,255,255));
|
||||||
|
while (*buffer) {
|
||||||
|
position(x+5,y+5);outtext(buffer);
|
||||||
|
y+= text_height(buffer);
|
||||||
|
buffer = strchr(buffer,0)+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void redraw_shop()
|
static void redraw_shop()
|
||||||
{
|
{
|
||||||
update_mysky();
|
update_mysky();
|
||||||
|
@ -2648,6 +2707,11 @@ static void redraw_shop()
|
||||||
info_box_below=NULL;
|
info_box_below=NULL;
|
||||||
if (shop_keeper_picture) put_picture(5,SCREEN_OFFLINE,shop_keeper_picture);
|
if (shop_keeper_picture) put_picture(5,SCREEN_OFFLINE,shop_keeper_picture);
|
||||||
ms_last_event.event_type=0x1;send_message(E_MOUSE,&ms_last_event);
|
ms_last_event.event_type=0x1;send_message(E_MOUSE,&ms_last_event);
|
||||||
|
if (shop_keeper_bubble) {
|
||||||
|
show_buble(5,SCREEN_OFFLINE+((word *)shop_keeper_picture)[1],
|
||||||
|
((word *)shop_keeper_picture)[0], shop_keeper_bubble);
|
||||||
|
}
|
||||||
|
shop_keeper_bubble=NULL;
|
||||||
ukaz_mysku();
|
ukaz_mysku();
|
||||||
showview(0,0,0,0);
|
showview(0,0,0,0);
|
||||||
}
|
}
|
||||||
|
@ -2770,10 +2834,20 @@ char shop_keeper_click(int id, int xa, int ya, int xr, int yr) {
|
||||||
}
|
}
|
||||||
if (p == 1) {
|
if (p == 1) {
|
||||||
redraw_shop();
|
redraw_shop();
|
||||||
price = smlouvat(price, pp->cena, *get_product_count(pp), money, 0);
|
THAGGLERESULT hr = smlouvat_dlg(price, pp->cena,
|
||||||
|
*get_product_count(pp), *get_last_haggle_price(pp), money, 0);
|
||||||
|
if (hr.canceled) {
|
||||||
|
price = -1;
|
||||||
|
} else if (hr.message) {
|
||||||
|
price = -1;
|
||||||
|
shop_keeper_bubble = hr.message;
|
||||||
|
*get_last_haggle_price(pp) = hr.hprice;
|
||||||
|
} else {
|
||||||
|
price = hr.hprice;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (price >= 0) {
|
if (price >= 0) {
|
||||||
|
*get_last_haggle_price(pp) = 0;
|
||||||
play_sample_at_channel(H_SND_OBCHOD, 1, 100);
|
play_sample_at_channel(H_SND_OBCHOD, 1, 100);
|
||||||
buy_item(z);
|
buy_item(z);
|
||||||
free(picked_item);
|
free(picked_item);
|
||||||
|
@ -2826,23 +2900,27 @@ char shop_bag_click(int id,int xa,int ya,int xr,int yr)
|
||||||
mouse_set_cursor(H_MS_DEFAULT);
|
mouse_set_cursor(H_MS_DEFAULT);
|
||||||
if (!price) return 0;
|
if (!price) return 0;
|
||||||
if (price > money) {
|
if (price > money) {
|
||||||
p = message(2, 0, 0, "", texty[104], texty[230], texty[78]);
|
p = message(2, 0, 0, "", texty[104], texty[230], texty[78])+1;
|
||||||
if (!p) {
|
|
||||||
redraw_shop();
|
|
||||||
price = smlouvat(price, pp->cena, *get_product_count(pp), money, 1);
|
|
||||||
} else {
|
|
||||||
price = -1;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
sprintf(s, texty[101], price);
|
sprintf(s, texty[101], price);
|
||||||
p = message(3, 0, 1, texty[118], s, texty[77], texty[230], texty[78]);
|
p = message(3, 0, 1, texty[118], s, texty[77], texty[230], texty[78]);
|
||||||
|
}
|
||||||
if (p == 1) {
|
if (p == 1) {
|
||||||
redraw_shop();
|
redraw_shop();
|
||||||
price = smlouvat(price, pp->cena, *get_product_count(pp), money, 1);
|
THAGGLERESULT hr = smlouvat_dlg(price, pp->cena,
|
||||||
|
*get_product_count(pp), *get_last_haggle_price(pp), money, 1);
|
||||||
|
if (hr.canceled) {
|
||||||
|
price = -1;
|
||||||
|
}else if (hr.message) {
|
||||||
|
price = -1;
|
||||||
|
shop_keeper_bubble = hr.message;
|
||||||
|
*get_last_haggle_price(pp) = hr.hprice;
|
||||||
|
} else {
|
||||||
|
price = hr.hprice;
|
||||||
|
}
|
||||||
} else if (p == 2) {
|
} else if (p == 2) {
|
||||||
price = -1;
|
price = -1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (price>=0)
|
if (price>=0)
|
||||||
{
|
{
|
||||||
play_sample_at_channel(H_SND_OBCHOD,1,100);
|
play_sample_at_channel(H_SND_OBCHOD,1,100);
|
||||||
|
@ -2869,12 +2947,23 @@ char shop_block_click(int id, int xa, int ya,int xr,int yr)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void shop_keyboard_proc(EVENT_MSG *msg, void **_) {
|
||||||
|
if (msg->msg == E_KEYBOARD) {
|
||||||
|
int c = quit_request_as_escape(va_arg(msg->data,int));
|
||||||
|
switch(c>>8) {
|
||||||
|
case 1: _exit_shop(0,0,0,0,0);break;
|
||||||
|
default:break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int old_inv_view_mode;
|
static int old_inv_view_mode;
|
||||||
|
|
||||||
void unwire_shop()
|
void unwire_shop()
|
||||||
{
|
{
|
||||||
send_message(E_DONE,E_MOUSE,shop_mouse_event);
|
send_message(E_DONE,E_MOUSE,shop_mouse_event);
|
||||||
|
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;
|
||||||
|
@ -2896,6 +2985,7 @@ void wire_shop()
|
||||||
last_shop=cur_shop;
|
last_shop=cur_shop;
|
||||||
}
|
}
|
||||||
send_message(E_ADD,E_MOUSE,shop_mouse_event);
|
send_message(E_ADD,E_MOUSE,shop_mouse_event);
|
||||||
|
send_message(E_ADD,E_KEYBOARD, shop_keyboard_proc);
|
||||||
unwire_proc=unwire_shop;
|
unwire_proc=unwire_shop;
|
||||||
change_click_map(clk_shop,CLK_SHOP);
|
change_click_map(clk_shop,CLK_SHOP);
|
||||||
if (shop_sector==viewsector) redraw_shop();else _exit_shop(0,0,0,0,0);
|
if (shop_sector==viewsector) redraw_shop();else _exit_shop(0,0,0,0,0);
|
||||||
|
@ -3008,10 +3098,14 @@ static void reroll_shop(TSHOP *p)
|
||||||
pr=p->list;
|
pr=p->list;
|
||||||
for(i=0;i<p->list_size;i++,pr++)
|
for(i=0;i<p->list_size;i++,pr++)
|
||||||
{
|
{
|
||||||
if (pr->trade_flags & SHP_AUTOADD && *get_product_count(pr)<pr->max_pocet) (*get_product_count(pr))++;
|
uint16_t *count = get_product_count(pr);
|
||||||
|
if (pr->trade_flags & SHP_AUTOADD) (*count)++;
|
||||||
|
if ((pr->trade_flags & SHP_SELL) == 0) *count = 0;
|
||||||
|
if (*count > pr->max_pocet) *count = pr->max_pocet;
|
||||||
if (pr->trade_flags & SHP_SPECIAL)
|
if (pr->trade_flags & SHP_SPECIAL)
|
||||||
{
|
{
|
||||||
poc_spec++;if (*get_product_count(pr)>0) *get_product_count(pr)=0;
|
poc_spec++;
|
||||||
|
*count = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pr=p->list;
|
pr=p->list;
|
||||||
|
@ -3022,8 +3116,12 @@ static void reroll_shop(TSHOP *p)
|
||||||
for(j=0;i<r;j++) if (pr[j].trade_flags & SHP_SPECIAL) i++;
|
for(j=0;i<r;j++) if (pr[j].trade_flags & SHP_SPECIAL) i++;
|
||||||
j--;
|
j--;
|
||||||
const TPRODUCT *sel = pr+j;
|
const TPRODUCT *sel = pr+j;
|
||||||
int maxp = MAX(sel->max_pocet,1);
|
int maxp = sel->max_pocet;
|
||||||
|
if (maxp) {
|
||||||
*get_product_count(pr+j)=rnd(maxp)+1;
|
*get_product_count(pr+j)=rnd(maxp)+1;
|
||||||
|
} else {
|
||||||
|
*get_product_count(pr+j) = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -498,6 +498,7 @@ static void seek_section(TMPFILE_RD *txt,int sect_number)
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
while (c!='[' && c!=EOF) c=temp_storage_getc(txt);
|
while (c!='[' && c!=EOF) c=temp_storage_getc(txt);
|
||||||
|
if (c == EOF) break;
|
||||||
if (c=='[')
|
if (c=='[')
|
||||||
{
|
{
|
||||||
i=-2;
|
i=-2;
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include "engine1.h"
|
#include "engine1.h"
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
|
#include "lang.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
@ -187,6 +188,7 @@ static void animace_kouzla(MGIF_HEADER_T *_,int act,const void *data, int ssize)
|
||||||
|
|
||||||
|
|
||||||
const void *load_spells_legacy_format(const void *p, int32_t *s) {
|
const void *load_spells_legacy_format(const void *p, int32_t *s) {
|
||||||
|
TSTRINGTABLE *strtable = lang_load("spells.csv");
|
||||||
void *np = getmem(*s);
|
void *np = getmem(*s);
|
||||||
memcpy(np,p,*s);
|
memcpy(np,p,*s);
|
||||||
TKOUZLO *k = (np);
|
TKOUZLO *k = (np);
|
||||||
|
@ -208,8 +210,13 @@ const void *load_spells_legacy_format(const void *p, int32_t *s) {
|
||||||
size_t eofs = offsetof(TKOUZLO, spellname)-1;
|
size_t eofs = offsetof(TKOUZLO, spellname)-1;
|
||||||
memmove(b+bofs+1, b+bofs, eofs-bofs);\
|
memmove(b+bofs+1, b+bofs, eofs-bofs);\
|
||||||
k->traceon = traceon;
|
k->traceon = traceon;
|
||||||
|
const char *new_name = stringtable_find(strtable, i, NULL);
|
||||||
|
if (new_name) {
|
||||||
|
strncpy(k->spellname,new_name,sizeof(k->spellname)-1);
|
||||||
|
}
|
||||||
++k;
|
++k;
|
||||||
}
|
}
|
||||||
|
stringtable_free(strtable);
|
||||||
return np;
|
return np;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
49
game/lang.c
Normal file
49
game/lang.c
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
#include <platform/platform.h>
|
||||||
|
#include <libs/event.h>
|
||||||
|
#include "globals.h"
|
||||||
|
#include "lang.h"
|
||||||
|
#include <libs/strlite.h>
|
||||||
|
|
||||||
|
|
||||||
|
static char *lang_folder = NULL;
|
||||||
|
|
||||||
|
static void free_lang_folder(void) {
|
||||||
|
free(lang_folder);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *lang_get_folder(void) {
|
||||||
|
return lang_folder;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lang_set_folder(const char *path) {
|
||||||
|
if (lang_folder == NULL) atexit(free_lang_folder);
|
||||||
|
lang_folder = strdup(path);
|
||||||
|
}
|
||||||
|
void lang_patch_stringtable(TSTR_LIST *lst, const char *object_name, const char *prefix) {
|
||||||
|
if (lang_folder == NULL) return;
|
||||||
|
const char *fname = set_file_extension(object_name, ".csv");
|
||||||
|
fname = concat2(prefix, fname);
|
||||||
|
const char *path = build_pathname(2, lang_folder, fname);
|
||||||
|
TSTRINGTABLE *st = stringtable_load(path);
|
||||||
|
if (!st) return;
|
||||||
|
for (int i = 0, cnt = str_count(*lst); i<cnt; ++i) {
|
||||||
|
const char *newstr = stringtable_find(st, i, NULL);
|
||||||
|
if (newstr) str_replace(lst, i, newstr);
|
||||||
|
}
|
||||||
|
stringtable_free(st);
|
||||||
|
|
||||||
|
}
|
||||||
|
TSTRINGTABLE *lang_load(const char *object_name) {
|
||||||
|
if (lang_folder == NULL) return NULL;
|
||||||
|
const char *fname = set_file_extension(object_name, ".csv");
|
||||||
|
const char *path = build_pathname(2, lang_folder, fname);
|
||||||
|
TSTRINGTABLE *st = stringtable_load(path);
|
||||||
|
return st;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *lang_replace_path_if_exists(const char *file) {
|
||||||
|
if (lang_folder == NULL) return NULL;
|
||||||
|
const char *path = build_pathname(2, lang_folder, file);
|
||||||
|
if (check_file_exists(path)) return path;
|
||||||
|
return NULL;
|
||||||
|
}
|
12
game/lang.h
Normal file
12
game/lang.h
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
#include <libs/strlite.h>
|
||||||
|
#include <libs/string_table.h>
|
||||||
|
|
||||||
|
void lang_set_folder(const char *path);
|
||||||
|
const char *lang_get_folder(void);
|
||||||
|
void lang_patch_stringtable(TSTR_LIST *lst, const char *object_name, const char *prefix);
|
||||||
|
const char *lang_replace_path_if_exists(const char *file);
|
||||||
|
TSTRINGTABLE *lang_load(const char *object_name);
|
||||||
|
|
20
game/menu.c
20
game/menu.c
|
@ -18,6 +18,7 @@
|
||||||
#include <libs/pcx.h>
|
#include <libs/pcx.h>
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
|
|
||||||
|
#include "lang.h"
|
||||||
|
|
||||||
#define MUSIC "TRACK06.MUS"
|
#define MUSIC "TRACK06.MUS"
|
||||||
|
|
||||||
|
@ -366,7 +367,13 @@ int enter_menu(char open)
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *get_next_title(signed char control,char *filename)
|
static const char *end_titles_path(const char *fname) {
|
||||||
|
if (stricmp(fname,"TITULKY.TXT") == 0) fname = "end_titles.txt";
|
||||||
|
else if (stricmp(fname,"ENDTEXT.TXT") == 0) fname = "epilog.txt";
|
||||||
|
return lang_replace_path_if_exists(fname);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *get_next_title(signed char control,const char *filename)
|
||||||
{
|
{
|
||||||
|
|
||||||
static TMPFILE_RD *titles=NULL;
|
static TMPFILE_RD *titles=NULL;
|
||||||
|
@ -377,7 +384,10 @@ char *get_next_title(signed char control,char *filename)
|
||||||
switch(control)
|
switch(control)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
|
path = end_titles_path(filename);
|
||||||
|
if (path == NULL) {
|
||||||
path = build_pathname(2, gpathtable[SR_MAP],filename);
|
path = build_pathname(2, gpathtable[SR_MAP],filename);
|
||||||
|
}
|
||||||
path = local_strdup(path);
|
path = local_strdup(path);
|
||||||
titles=enc_open(path);
|
titles=enc_open(path);
|
||||||
if (titles==NULL)
|
if (titles==NULL)
|
||||||
|
@ -395,8 +405,12 @@ char *get_next_title(signed char control,char *filename)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (char *)titles;
|
return (char *)titles;
|
||||||
case 0:if (titles!=NULL)temp_storage_gets(buffer,80,titles);
|
case 0:if (titles!=NULL && temp_storage_gets(buffer,80,titles)) {
|
||||||
c=strchr(buffer,'\n');if (c!=NULL) *c=0;
|
c=strchr(buffer,'\n');if (c!=NULL) *c=0;
|
||||||
|
c=strchr(buffer,'\r');if (c!=NULL) *c=0;
|
||||||
|
} else {
|
||||||
|
strcpy(buffer, "*KONEC");
|
||||||
|
}
|
||||||
return buffer;
|
return buffer;
|
||||||
case -1:if (titles!=NULL)enc_close(titles);
|
case -1:if (titles!=NULL)enc_close(titles);
|
||||||
break;
|
break;
|
||||||
|
@ -517,7 +531,7 @@ void titles(va_list args)
|
||||||
{
|
{
|
||||||
int32_t scr_linelen2 = GetScreenPitch();
|
int32_t scr_linelen2 = GetScreenPitch();
|
||||||
char send_back=va_arg(args,int);
|
char send_back=va_arg(args,int);
|
||||||
char *textname=va_arg(args,char *);
|
const char *textname=va_arg(args,const char *);
|
||||||
|
|
||||||
const void *picture;
|
const void *picture;
|
||||||
word *scr,*buff;
|
word *scr,*buff;
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include <libs/inicfg.h>
|
#include <libs/inicfg.h>
|
||||||
|
|
||||||
|
#include "lang.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
@ -197,7 +198,7 @@ int load_map(char *filename)
|
||||||
char snd_load=0;
|
char snd_load=0;
|
||||||
void *mob_template;
|
void *mob_template;
|
||||||
int32_t mob_size;
|
int32_t mob_size;
|
||||||
int suc = 0;
|
int failed = 0;
|
||||||
|
|
||||||
map_with_password=0;
|
map_with_password=0;
|
||||||
const char *mpath = build_pathname(2, gpathtable[SR_MAP], filename);
|
const char *mpath = build_pathname(2, gpathtable[SR_MAP], filename);
|
||||||
|
@ -344,8 +345,11 @@ int load_map(char *filename)
|
||||||
memset(minimap,0,sizeof(minimap));
|
memset(minimap,0,sizeof(minimap));
|
||||||
end_ptr=ofsts;
|
end_ptr=ofsts;
|
||||||
const char *tpath=set_file_extension(mpath,".txt");
|
const char *tpath=set_file_extension(mpath,".txt");
|
||||||
suc=load_level_texts(tpath);
|
failed=load_level_texts(tpath);
|
||||||
if (!suc && level_texts!=NULL) create_playlist(level_texts[0]);
|
if (!failed && level_texts!=NULL) {
|
||||||
|
lang_patch_stringtable(&level_texts, filename, "map_");
|
||||||
|
create_playlist(level_texts[0]);
|
||||||
|
}
|
||||||
init_tracks();
|
init_tracks();
|
||||||
change_music(get_next_music_from_playlist());
|
change_music(get_next_music_from_playlist());
|
||||||
for(r=0;r<mapsize*4;r++) flag_map[r]=(char)map_sides[r].flags;
|
for(r=0;r<mapsize*4;r++) flag_map[r]=(char)map_sides[r].flags;
|
||||||
|
@ -359,7 +363,7 @@ int load_map(char *filename)
|
||||||
current_map_hash = fnv1a_hash(filename);
|
current_map_hash = fnv1a_hash(filename);
|
||||||
const char * hash_str = map_hash_to_string(current_map_hash);
|
const char * hash_str = map_hash_to_string(current_map_hash);
|
||||||
temp_storage_store(hash_str, filename, strlen(filename));
|
temp_storage_store(hash_str, filename, strlen(filename));
|
||||||
return suc;
|
return failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_leaving_place(int sector)
|
void add_leaving_place(int sector)
|
||||||
|
@ -1272,11 +1276,11 @@ void group_all(void)
|
||||||
{
|
{
|
||||||
if (cur_group!=1)
|
if (cur_group!=1)
|
||||||
{
|
{
|
||||||
for(i=0,h=postavy;i<POCET_POSTAV;i++,h++) if (h->used && h->groupnum==1 && h->sektor!=viewsector && h->inmaphash == current_map_hash) break;
|
for(i=0,h=postavy;i<POCET_POSTAV;i++,h++) if (h->used && h->groupnum==1 && h->sektor!=viewsector) break;
|
||||||
if (i==POCET_POSTAV) cur_group=1;
|
if (i==POCET_POSTAV) cur_group=1;
|
||||||
}
|
}
|
||||||
for(i=0,h=postavy;i<POCET_POSTAV;i++,h++)
|
for(i=0,h=postavy;i<POCET_POSTAV;i++,h++)
|
||||||
if (h->used && h->lives && h->sektor==viewsector && h->inmaphash == current_map_hash) h->groupnum=cur_group;
|
if (h->used && h->lives && h->sektor==viewsector) h->groupnum=cur_group;
|
||||||
}
|
}
|
||||||
|
|
||||||
bott_draw(0);
|
bott_draw(0);
|
||||||
|
@ -1570,7 +1574,7 @@ void step_zoom(char smer)
|
||||||
int i;
|
int i;
|
||||||
THUMAN *h;
|
THUMAN *h;
|
||||||
group_all();can_go=1;
|
group_all();can_go=1;
|
||||||
for(i=0,h=postavy;i<POCET_POSTAV;i++,h++) if (h->groupnum!=cur_group && h->lives) break;
|
for(i=0,h=postavy;i<POCET_POSTAV;i++,h++) if (h->used && h->inmaphash == current_map_hash && h->groupnum!=cur_group && h->lives) break;
|
||||||
if (i!=POCET_POSTAV)
|
if (i!=POCET_POSTAV)
|
||||||
{
|
{
|
||||||
bott_disp_text(texty[66]);
|
bott_disp_text(texty[66]);
|
||||||
|
|
108
game/skeldal.c
108
game/skeldal.c
|
@ -14,12 +14,13 @@
|
||||||
#include <libs/basicobj.h>
|
#include <libs/basicobj.h>
|
||||||
#include <libs/mgfplay.h>
|
#include <libs/mgfplay.h>
|
||||||
#include <libs/inicfg.h>
|
#include <libs/inicfg.h>
|
||||||
#include <platform/getopt.h>
|
|
||||||
#include <platform/save_folder.h>
|
#include <platform/save_folder.h>
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "default_font.h"
|
#include "default_font.h"
|
||||||
//
|
//
|
||||||
#include "advconfig.h"
|
#include "advconfig.h"
|
||||||
|
#include "skeldal.h"
|
||||||
|
#include "lang.h"
|
||||||
|
|
||||||
#define CONFIG_NAME SKELDALINI
|
#define CONFIG_NAME SKELDALINI
|
||||||
|
|
||||||
|
@ -95,7 +96,7 @@ const void *pcx_15bit_autofade(const void *p, int32_t *s);
|
||||||
const void *pcx_15bit_backgrnd(const void *p, int32_t *s);
|
const void *pcx_15bit_backgrnd(const void *p, int32_t *s);
|
||||||
const void *pcx_8bit_decomp(const void *p, int32_t *s);
|
const void *pcx_8bit_decomp(const void *p, int32_t *s);
|
||||||
|
|
||||||
char *texty_knihy;
|
const char *texty_knihy;
|
||||||
static char *patch_file=NULL;
|
static char *patch_file=NULL;
|
||||||
int cur_page=0;
|
int cur_page=0;
|
||||||
|
|
||||||
|
@ -793,9 +794,13 @@ void cti_texty(void)
|
||||||
display_error(buff);
|
display_error(buff);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lang_patch_stringtable(&texty, "ui.csv", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void global_kbd(EVENT_MSG *msg,void **usr)
|
void global_kbd(EVENT_MSG *msg,void **usr)
|
||||||
{
|
{
|
||||||
char c;
|
char c;
|
||||||
|
@ -947,7 +952,16 @@ void init_skeldal(const INI_CONFIG *cfg)
|
||||||
|
|
||||||
init_DDL_manager();
|
init_DDL_manager();
|
||||||
|
|
||||||
|
if (lang_get_folder()) {
|
||||||
|
texty_knihy = build_pathname(2, lang_get_folder(), "book.txt");
|
||||||
|
if (!check_file_exists(texty_knihy)) {
|
||||||
texty_knihy=strdup(build_pathname(2,gpathtable[SR_MAP],"kniha.txt"));
|
texty_knihy=strdup(build_pathname(2,gpathtable[SR_MAP],"kniha.txt"));
|
||||||
|
} else {
|
||||||
|
texty_knihy=strdup(texty_knihy);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
texty_knihy=strdup(build_pathname(2,gpathtable[SR_MAP],"kniha.txt"));
|
||||||
|
}
|
||||||
|
|
||||||
install_gui();
|
install_gui();
|
||||||
|
|
||||||
|
@ -1576,32 +1590,22 @@ const char *configure_pathtable(const INI_CONFIG *cfg) {
|
||||||
gpathtable[SR_VIDEO] = ini_get_string(paths, "video", "video");
|
gpathtable[SR_VIDEO] = ini_get_string(paths, "video", "video");
|
||||||
gpathtable[SR_SAVES] = ini_get_string(paths, "savegame", get_default_savegame_directory());
|
gpathtable[SR_SAVES] = ini_get_string(paths, "savegame", get_default_savegame_directory());
|
||||||
gpathtable[SR_DATA]= ini_get_string(paths, "data", "./");
|
gpathtable[SR_DATA]= ini_get_string(paths, "data", "./");
|
||||||
|
gpathtable[SR_LANG]= ini_get_string(paths, "lang", "./lang");
|
||||||
|
|
||||||
|
|
||||||
return groot;
|
return groot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void show_help(const char *arg0) {
|
static void (*display_error_cb)(const char *);
|
||||||
printf(
|
void display_error(const char *format, ...) {
|
||||||
"Brany Skeldalu (Gates of Skeldal) portable game player\n"
|
va_list lst;va_start(lst, format);
|
||||||
"Copyright (c) 2025 Ondrej Novak. All rights reserved.\n\n"
|
if (display_error_cb) {
|
||||||
"This work is licensed under the terms of the MIT license.\n"
|
char buff[1024];
|
||||||
"For a copy, see <https://opensource.org/licenses/MIT>.\n"
|
vsnprintf(buff,sizeof(buff), format, lst);
|
||||||
"\n"
|
} else {
|
||||||
"Usage:"
|
fprintf(stderr, format, lst);
|
||||||
);
|
|
||||||
printf("%s [-f <file>] [-a <file>] [-h]\n\n", arg0);
|
|
||||||
|
|
||||||
printf("-f <file> path to configuration file\n"
|
|
||||||
"-a <adv> path for adventure file (.adv)\n"
|
|
||||||
"-s <directory> generate string-tables (for localization)\n"
|
|
||||||
"-h this help\n");
|
|
||||||
exit(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void show_help_short() {
|
|
||||||
printf("Use -h for help\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void quit_cb_exit_wait(void *_) {
|
void quit_cb_exit_wait(void *_) {
|
||||||
|
@ -1609,54 +1613,62 @@ void quit_cb_exit_wait(void *_) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int skeldal_gen_string_table_entry_point(const SKELDAL_CONFIG *start_cfg, const char *save_path) {
|
||||||
int main(int argc,char *argv[])
|
|
||||||
{
|
|
||||||
def_mman_group_table(gpathtable);
|
def_mman_group_table(gpathtable);
|
||||||
zoom_speed(1);
|
|
||||||
turn_speed(1);
|
|
||||||
const char *config_name = CONFIG_NAME;
|
|
||||||
const char *adv_config_file = NULL;
|
|
||||||
const char *gen_stringtable_path = NULL;
|
|
||||||
for (int optchr = -1; (optchr = getopt(argc, argv, "hf:a:s:")) != -1; ) {
|
|
||||||
switch (optchr) {
|
|
||||||
case 'f': config_name = local_strdup(optarg);break;
|
|
||||||
case 'a': adv_config_file = local_strdup(optarg);break;
|
|
||||||
case 'h': show_help(argv[0]);break;
|
|
||||||
case 's': gen_stringtable_path = local_strdup(optarg);break;
|
|
||||||
default: show_help_short();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
INI_CONFIG *cfg = ini_open(config_name);
|
INI_CONFIG *cfg = ini_open(start_cfg->config_path);
|
||||||
if (cfg == NULL) {
|
if (cfg == NULL) {
|
||||||
fprintf(stderr, "Failed to open configuration file: %s\n", CONFIG_NAME);
|
start_cfg->show_error(concat2("Failed to open configuration file: ", start_cfg->config_path));
|
||||||
show_help_short();
|
start_cfg->short_help();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (adv_config_file) {
|
if (start_cfg->adventure_path) {
|
||||||
TSTR_LIST adv_config=read_config(adv_config_file);
|
TSTR_LIST adv_config=read_config(start_cfg->adventure_path);
|
||||||
adv_patch_config(cfg, adv_config);
|
adv_patch_config(cfg, adv_config);
|
||||||
release_list(adv_config);
|
release_list(adv_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *groot = configure_pathtable(cfg);
|
const char *groot = configure_pathtable(cfg);
|
||||||
if (!change_current_directory(groot)) {
|
if (!change_current_directory(groot)) {
|
||||||
fprintf(stderr, "Can't change directory to %s", groot);
|
start_cfg->show_error(concat2("Can't change directory to: ", groot));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (gen_stringtable_path) {
|
|
||||||
init_DDL_manager();
|
init_DDL_manager();
|
||||||
generate_string_tables(gen_stringtable_path);
|
generate_string_tables(save_path);
|
||||||
printf("Done\n");
|
printf("Done\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int skeldal_entry_point(const SKELDAL_CONFIG *start_cfg)
|
||||||
|
{
|
||||||
|
def_mman_group_table(gpathtable);
|
||||||
|
|
||||||
|
display_error_cb = start_cfg->show_error;
|
||||||
|
|
||||||
|
INI_CONFIG *cfg = ini_open(start_cfg->config_path);
|
||||||
|
if (cfg == NULL) {
|
||||||
|
start_cfg->show_error(concat2("Failed to open configuration file: ", start_cfg->config_path));
|
||||||
|
start_cfg->short_help();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start_cfg->adventure_path) {
|
||||||
|
TSTR_LIST adv_config=read_config(start_cfg->adventure_path);
|
||||||
|
adv_patch_config(cfg, adv_config);
|
||||||
|
release_list(adv_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *groot = configure_pathtable(cfg);
|
||||||
|
if (!change_current_directory(groot)) {
|
||||||
|
start_cfg->show_error(concat2("Can't change directory to: ", groot));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start_cfg->lang_path) {
|
||||||
|
lang_set_folder(build_pathname(2, gpathtable[SR_LANG], start_cfg->lang_path));
|
||||||
|
}
|
||||||
|
|
||||||
start_check();
|
start_check();
|
||||||
purge_temps(1);
|
purge_temps(1);
|
||||||
|
|
25
game/skeldal.h
Normal file
25
game/skeldal.h
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
void (*short_help)();
|
||||||
|
void (*show_error)(const char *text);
|
||||||
|
|
||||||
|
const char *adventure_path;
|
||||||
|
const char *config_path;
|
||||||
|
const char *lang_path;
|
||||||
|
|
||||||
|
|
||||||
|
} SKELDAL_CONFIG;
|
||||||
|
|
||||||
|
int skeldal_entry_point(const SKELDAL_CONFIG *cfg);
|
||||||
|
int skeldal_gen_string_table_entry_point(const SKELDAL_CONFIG *cfg, const char *save_path);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -493,6 +493,13 @@ void auto_group()
|
||||||
if (p->sektor==q->sektor && p->direction==q->direction && p->inmaphash == current_map_hash && q->used && q->lives)
|
if (p->sektor==q->sektor && p->direction==q->direction && p->inmaphash == current_map_hash && q->used && q->lives)
|
||||||
q->groupnum=p->groupnum;
|
q->groupnum=p->groupnum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for(i=0;p=&postavy[i],i<POCET_POSTAV;i++) {
|
||||||
|
if (p->sektor == viewsector && p->direction == viewdir) {
|
||||||
|
cur_group = p->groupnum;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
int vyber_zacinajiciho(int att_player)
|
int vyber_zacinajiciho(int att_player)
|
||||||
|
@ -527,9 +534,8 @@ int vyber_prvniho(int att)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
static int vyber_hrace(int att)
|
static int vyber_hrace(int att) {
|
||||||
{
|
int gr;
|
||||||
int gr,i;
|
|
||||||
THUMAN *h;
|
THUMAN *h;
|
||||||
|
|
||||||
if (att > POCET_POSTAV || att < 0)
|
if (att > POCET_POSTAV || att < 0)
|
||||||
|
@ -537,11 +543,28 @@ static int vyber_hrace(int att)
|
||||||
else
|
else
|
||||||
gr = postavy[att].groupnum;
|
gr = postavy[att].groupnum;
|
||||||
h = postavy;
|
h = postavy;
|
||||||
for(i=0,h=postavy;i<POCET_POSTAV && (!h->used || !h->lives || !h->actions || h->groupnum!=gr) ;i++,h++);
|
int candidate0 = -1;
|
||||||
if (i==6)
|
int candidate1 = -1;
|
||||||
if (att!=0xff) return att;else return group_sort[0];
|
int candidate2 = -1;
|
||||||
else
|
for (int i = POCET_POSTAV; i>0;) {
|
||||||
return i;
|
--i;
|
||||||
|
h = postavy+i;
|
||||||
|
if (h->used && h->inmaphash == current_map_hash) {
|
||||||
|
candidate0 = i;
|
||||||
|
if (h->groupnum == gr) {
|
||||||
|
candidate1 =i;
|
||||||
|
if (h->actions) {
|
||||||
|
candidate2 = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (candidate2>=0) return candidate2;
|
||||||
|
if (candidate1>=0) return candidate1;
|
||||||
|
if (candidate0>=0) return candidate0;
|
||||||
|
if (att != 0xFF) return att;
|
||||||
|
display_error("Can't select PC for battle");
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void zacatek_kola()
|
void zacatek_kola()
|
||||||
|
|
|
@ -19,7 +19,19 @@ typedef struct _temp_storage_file_rd {
|
||||||
int skp = 0;
|
int skp = 0;
|
||||||
} TMPFILE_RD;
|
} TMPFILE_RD;
|
||||||
|
|
||||||
using FileSystem = std::map<std::string, std::vector<uint8_t>, std::less<> >;
|
struct icompare {
|
||||||
|
using is_transparent = std::true_type;
|
||||||
|
bool operator()(const std::string_view &a, const std::string_view &b) const {
|
||||||
|
if (a.size() != b.size()) return a.size() < b.size();
|
||||||
|
for (std::size_t i = 0, cnt = a.size(); i < cnt; ++i) {
|
||||||
|
int cmp = toupper(a[i]) - toupper(b[i]);
|
||||||
|
if (cmp) return cmp < 0;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using FileSystem = std::map<std::string, std::vector<uint8_t>, icompare >;
|
||||||
static FileSystem temp_fsystem;
|
static FileSystem temp_fsystem;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ SET(files basicobj.c
|
||||||
strlists.c
|
strlists.c
|
||||||
cztable.c
|
cztable.c
|
||||||
music.cpp
|
music.cpp
|
||||||
|
string_table.cpp
|
||||||
swaper.c )
|
swaper.c )
|
||||||
|
|
||||||
add_library(skeldal_libs ${files})
|
add_library(skeldal_libs ${files})
|
||||||
|
|
120
libs/addtext.c
120
libs/addtext.c
|
@ -1,120 +0,0 @@
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "memman.c"
|
|
||||||
#include "strlite.c"
|
|
||||||
|
|
||||||
|
|
||||||
TSTR_LIST ls_origin=NULL;
|
|
||||||
TSTR_LIST ls_new=NULL;
|
|
||||||
|
|
||||||
static void load_error_msg(int err,char *filename)
|
|
||||||
{
|
|
||||||
switch (err)
|
|
||||||
{
|
|
||||||
case -1: puts ("Source or target file not found");break;
|
|
||||||
case -2: puts ("Unexcepted EOF");break;
|
|
||||||
case -3: puts ("Internal error in strlite.c");break;
|
|
||||||
default: printf("Error in string table at line %d.\n",err);
|
|
||||||
}
|
|
||||||
printf("File:%s\n",filename);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void load_lists(char *filename1,char *filename2)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err=load_string_list(&ls_new,filename1);
|
|
||||||
if (err) load_error_msg(err,filename1);
|
|
||||||
err=load_string_list(&ls_origin,filename2);
|
|
||||||
if (err) load_error_msg(err,filename2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
char *create_backup(char *filename)
|
|
||||||
{
|
|
||||||
char *c,*d;
|
|
||||||
|
|
||||||
c=getmem(strlen(filename)+5);strcpy(c,filename);
|
|
||||||
d=strrchr(c,'.');if (d==NULL) d=strchr(c,0);
|
|
||||||
strcpy(d,".bak");
|
|
||||||
remove(c);
|
|
||||||
rename(filename,c);
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
void spoj_stringtable()
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
int cnt=str_count(ls_new);
|
|
||||||
for(i=0;i<cnt;i++) if (ls_new[i]!=NULL && ls_origin[i]==NULL)
|
|
||||||
str_replace(&ls_origin,i,ls_new[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void save_num(FILE *fo,int num)
|
|
||||||
{
|
|
||||||
char *c=ls_origin[num];
|
|
||||||
|
|
||||||
if (c==NULL) return;
|
|
||||||
fprintf(fo,"%d ",num);
|
|
||||||
while (*c) if (*c=='\n') (putc('|',fo),c++);else putc(*c++,fo);
|
|
||||||
putc('\n',fo);
|
|
||||||
}
|
|
||||||
|
|
||||||
void save_stringtable(char *filename,char *backup_name)
|
|
||||||
{
|
|
||||||
FILE *fo,*fb;
|
|
||||||
int cnt=str_count(ls_origin);
|
|
||||||
int num,rd;
|
|
||||||
int oldnum=-1,i;
|
|
||||||
|
|
||||||
fb=fopen_icase(backup_name,"rt");
|
|
||||||
if (fb==NULL)
|
|
||||||
{
|
|
||||||
puts("Cannot open backup file for reading.");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
fo=fopen_icase(filename,"wt");
|
|
||||||
if (fo==NULL)
|
|
||||||
{
|
|
||||||
puts("Cannot open target file for writting.");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
num=0;
|
|
||||||
rd=fscanf(fb,"%d",&num);
|
|
||||||
while (num!=-1)
|
|
||||||
{
|
|
||||||
if (rd!=1)
|
|
||||||
do
|
|
||||||
{
|
|
||||||
rd=getc(fb);putc(rd,fo);
|
|
||||||
}
|
|
||||||
while(rd!='\n');
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for(i=oldnum+1;i<=num;i++) save_num(fo,i);
|
|
||||||
while((rd=getc(fb))!=EOF && rd!='\n');
|
|
||||||
}
|
|
||||||
oldnum=num;
|
|
||||||
rd=fscanf(fb,"%d",&num);
|
|
||||||
}
|
|
||||||
for(i=oldnum+1;i<cnt;i++) save_num(fo,i);
|
|
||||||
fprintf(fo,"%d",-1);
|
|
||||||
fclose(fo);
|
|
||||||
fclose(fb);
|
|
||||||
}
|
|
||||||
|
|
||||||
void main(int argc,char **argv)
|
|
||||||
{
|
|
||||||
char *back;
|
|
||||||
if (argc!=3)
|
|
||||||
{
|
|
||||||
puts("Usage: ADDTEXT source target");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
load_lists(argv[1],argv[2]);
|
|
||||||
back=create_backup(argv[2]);
|
|
||||||
spoj_stringtable();
|
|
||||||
save_stringtable(argv[2],back);
|
|
||||||
puts("New texts added...");
|
|
||||||
}
|
|
132
libs/advinst.c
132
libs/advinst.c
|
@ -1,132 +0,0 @@
|
||||||
#include <stdio.h>
|
|
||||||
#include <io.h>
|
|
||||||
#include <direct.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <conio.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <dos.h>
|
|
||||||
|
|
||||||
char copy_path[500];
|
|
||||||
char *adv_name;
|
|
||||||
|
|
||||||
char _change_disk(unsigned znak)
|
|
||||||
{
|
|
||||||
unsigned total;
|
|
||||||
znak-='@';
|
|
||||||
_dos_setdrive(znak,&total);
|
|
||||||
_dos_getdrive(&total);
|
|
||||||
return total==znak;
|
|
||||||
}
|
|
||||||
|
|
||||||
char disk_finder()
|
|
||||||
{
|
|
||||||
static struct find_t ft;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if (!access("SKELDAL.EXE",F_OK) && !access("ADV",F_OK)) return 1;
|
|
||||||
err=_dos_findfirst("*.*",_A_SUBDIR,&ft);
|
|
||||||
while (!err)
|
|
||||||
{
|
|
||||||
if (ft.attrib & _A_SUBDIR && strcmp(ft.name,".") && strcmp(ft.name,".."))
|
|
||||||
{
|
|
||||||
chdir(ft.name);
|
|
||||||
if (disk_finder()) return 1;
|
|
||||||
chdir("..");
|
|
||||||
}
|
|
||||||
err=_dos_findnext(&ft);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
char find_path(char *path)
|
|
||||||
{SEPARATOR
|
|
||||||
char *oldpath;
|
|
||||||
unsigned pismeno='C';
|
|
||||||
|
|
||||||
cputs("Hledam...\r");
|
|
||||||
oldpath=getcwd(NULL,PATH_MAX);
|
|
||||||
for(pismeno='C';pismeno<='Z';pismeno++)
|
|
||||||
{
|
|
||||||
_change_disk(pismeno);
|
|
||||||
chdir("..");
|
|
||||||
if (disk_finder()==1)
|
|
||||||
{
|
|
||||||
getcwd(path,PATH_MAX);
|
|
||||||
chdir(oldpath);_change_disk(oldpath[0]);
|
|
||||||
free(oldpath);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
chdir(oldpath);_change_disk(oldpath[0]);
|
|
||||||
free(oldpath);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void main(int argc,char **argv)
|
|
||||||
{
|
|
||||||
char temp[550];
|
|
||||||
char rep;
|
|
||||||
if (argc<2)
|
|
||||||
{
|
|
||||||
puts("Nespravne parametry!\n"
|
|
||||||
"\n"
|
|
||||||
"Pouziti ADVINST [jmeno]\n"
|
|
||||||
"\n"
|
|
||||||
"jmeno = Nazev dobrodruzstvi bez pripony");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
adv_name=argv[1];
|
|
||||||
sprintf(temp,"%s.adv",adv_name);
|
|
||||||
if (access(adv_name,F_OK) && access(temp,F_OK))
|
|
||||||
{
|
|
||||||
printf("Nemohu najit zadne dobrodruzstvi s timto jmenem (%s)!\n",adv_name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
|
||||||
printf("Vypiste celou cestu, kde lezi hra (napr: c:\\hry\\skeldal)\n"
|
|
||||||
"Pokud vlozte otaznik (?), instalator se pokusi hru na disku vyhledat\n"
|
|
||||||
"Pokud stisknete pouze <ENTER>, instalator se ukonci\n"
|
|
||||||
">");
|
|
||||||
gets(copy_path);
|
|
||||||
if (copy_path[0]=='?')
|
|
||||||
{
|
|
||||||
find_path(copy_path);
|
|
||||||
printf("\nInstalator nasel hru na ceste: %s\n\n",copy_path);
|
|
||||||
}
|
|
||||||
if (copy_path[0]==0) return;
|
|
||||||
sprintf(temp,"%s\\skeldal.exe",copy_path);
|
|
||||||
rep=access(temp,F_OK);
|
|
||||||
if (rep) puts("Vami vlozena cesta neni spravna!\n");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sprintf(temp,"%s\\adv\\%s",copy_path,adv_name);
|
|
||||||
if (access(temp,F_OK))if (mkdir(temp)!=0) printf("Nedokazal jsem vytvorit adresar %s\n\n\n",temp),rep=1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while(rep);
|
|
||||||
sprintf(temp,"copy %s.adv %s > nul",adv_name,copy_path);
|
|
||||||
puts(temp);
|
|
||||||
system(temp);
|
|
||||||
sprintf(temp,"copy %s\\*.* %s\\adv\\%s > nul",adv_name,copy_path,adv_name);
|
|
||||||
puts(temp);
|
|
||||||
system(temp);
|
|
||||||
sprintf(temp,"%s.bat",adv_name);
|
|
||||||
if (access(temp,F_OK)==0)
|
|
||||||
{
|
|
||||||
sprintf(temp,"%s.bat %s",adv_name,copy_path);
|
|
||||||
puts(temp);
|
|
||||||
system(temp);
|
|
||||||
}
|
|
||||||
chdir(copy_path);
|
|
||||||
puts("Instalace uspesna!");
|
|
||||||
printf("Nove dobrodruzstvi spustis prikazem SKELDAL %s.adv\n",adv_name);
|
|
||||||
puts("Chces si nyni nove dobrodruzstvi vyzkouset? ANO/NE (cokoliv/N)");
|
|
||||||
if (toupper(getche())=='N') return;
|
|
||||||
sprintf(temp,"SKELDAL %s.adv",adv_name);
|
|
||||||
system(temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -142,6 +142,7 @@ void put_image(const word *image,word *target,int start_line,int sizex,int sizey
|
||||||
void put_picture2picture(const word *source,word *target,int xp,int yp);
|
void put_picture2picture(const word *source,word *target,int xp,int yp);
|
||||||
//#pragma aux put_picture2picture parm [ESI][EDI][EAX][EDX] modify [ECX]
|
//#pragma aux put_picture2picture parm [ESI][EDI][EAX][EDX] modify [ECX]
|
||||||
|
|
||||||
|
void draw_rounded_rectangle(int x, int y, int xs, int ys, int radius,
|
||||||
|
int stroke_color, int fill_color);
|
||||||
|
|
||||||
#define swap_int(a,b) do {int c=a;a=b;b=c;} while (0);
|
#define swap_int(a,b) do {int c=a;a=b;b=c;} while (0);
|
||||||
|
|
157
libs/bgraph2.c
157
libs/bgraph2.c
|
@ -624,3 +624,160 @@ void rectangle(int x1,int y1,int x2,int y2,int color)
|
||||||
ver_line32(x2,y1,y2);
|
ver_line32(x2,y1,y2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void put_pixel(int x, int y, int c) {
|
||||||
|
word *addr = getadr32(x, y);
|
||||||
|
*addr = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------
|
||||||
|
draw_circle_quarter()
|
||||||
|
|
||||||
|
Draws one quarter of a circle of radius 'r' (using Bresenham’s algorithm)
|
||||||
|
centered at (cx, cy). The parameter 'quadrant' selects which quarter:
|
||||||
|
0 = top–left (draws points in the direction of decreasing x and y)
|
||||||
|
1 = top–right (increasing x, decreasing y)
|
||||||
|
2 = bottom–right (increasing x and y)
|
||||||
|
3 = bottom–left (decreasing x, increasing y)
|
||||||
|
The function calls put_pixel() to draw the pixels.
|
||||||
|
--------------------------------------------------------------------------*/
|
||||||
|
static void draw_circle_quarter(int cx, int cy, int r, int quadrant, int color) {
|
||||||
|
int x = 0, y = r;
|
||||||
|
int d = 3 - 2 * r;
|
||||||
|
while (x <= y) {
|
||||||
|
switch (quadrant) {
|
||||||
|
case 0: /* Top-left quarter */
|
||||||
|
put_pixel(cx - x, cy - y, color);
|
||||||
|
put_pixel(cx - y, cy - x, color);
|
||||||
|
break;
|
||||||
|
case 1: /* Top-right quarter */
|
||||||
|
put_pixel(cx + x, cy - y, color);
|
||||||
|
put_pixel(cx + y, cy - x, color);
|
||||||
|
break;
|
||||||
|
case 2: /* Bottom-right quarter */
|
||||||
|
put_pixel(cx + x, cy + y, color);
|
||||||
|
put_pixel(cx + y, cy + x, color);
|
||||||
|
break;
|
||||||
|
case 3: /* Bottom-left quarter */
|
||||||
|
put_pixel(cx - x, cy + y, color);
|
||||||
|
put_pixel(cx - y, cy + x, color);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (d < 0) {
|
||||||
|
d += 4 * x + 6;
|
||||||
|
} else {
|
||||||
|
d += 4 * (x - y) + 10;
|
||||||
|
y--;
|
||||||
|
}
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------
|
||||||
|
draw_rounded_rectangle()
|
||||||
|
|
||||||
|
Draws a filled, rounded rectangle with a stroke border. The parameters are:
|
||||||
|
- (x,y): Top–left coordinate of the bounding rectangle.
|
||||||
|
- (xs, ys): Width and height.
|
||||||
|
- radius: The radius of the corner arcs.
|
||||||
|
- stroke_color: The color of the border.
|
||||||
|
- fill_color: The color used for filling the interior.
|
||||||
|
--------------------------------------------------------------------------*/
|
||||||
|
void draw_rounded_rectangle(int x, int y, int xs, int ys, int radius,
|
||||||
|
int stroke_color, int fill_color) {
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
/* Clamp the radius if it is too large */
|
||||||
|
if (radius * 2 > xs)
|
||||||
|
radius = xs / 2;
|
||||||
|
if (radius * 2 > ys)
|
||||||
|
radius = ys / 2;
|
||||||
|
|
||||||
|
int rsq = radius * radius; /* We'll use this to avoid taking square roots */
|
||||||
|
|
||||||
|
/* --- Fill the rounded rectangle --- */
|
||||||
|
for (j = y; j < y + ys; j++) {
|
||||||
|
for (i = x; i < x + xs; i++) {
|
||||||
|
int draw_pixel = 1; /* flag: set to 0 if the pixel is outside the filled area */
|
||||||
|
|
||||||
|
if (radius > 0) {
|
||||||
|
/* Top-left corner */
|
||||||
|
if (i < x + radius && j < y + radius) {
|
||||||
|
int cx = x + radius;
|
||||||
|
int cy = y + radius;
|
||||||
|
int dx = i - cx;
|
||||||
|
int dy = j - cy;
|
||||||
|
if (dx * dx + dy * dy > rsq)
|
||||||
|
draw_pixel = 0;
|
||||||
|
}
|
||||||
|
/* Top-right corner */
|
||||||
|
else if (i >= x + xs - radius && j < y + radius) {
|
||||||
|
int cx = x + xs - radius - 1;
|
||||||
|
int cy = y + radius;
|
||||||
|
int dx = i - cx;
|
||||||
|
int dy = j - cy;
|
||||||
|
if (dx * dx + dy * dy > rsq)
|
||||||
|
draw_pixel = 0;
|
||||||
|
}
|
||||||
|
/* Bottom-left corner */
|
||||||
|
else if (i < x + radius && j >= y + ys - radius) {
|
||||||
|
int cx = x + radius;
|
||||||
|
int cy = y + ys - radius - 1;
|
||||||
|
int dx = i - cx;
|
||||||
|
int dy = j - cy;
|
||||||
|
if (dx * dx + dy * dy > rsq)
|
||||||
|
draw_pixel = 0;
|
||||||
|
}
|
||||||
|
/* Bottom-right corner */
|
||||||
|
else if (i >= x + xs - radius && j >= y + ys - radius) {
|
||||||
|
int cx = x + xs - radius - 1;
|
||||||
|
int cy = y + ys - radius - 1;
|
||||||
|
int dx = i - cx;
|
||||||
|
int dy = j - cy;
|
||||||
|
if (dx * dx + dy * dy > rsq)
|
||||||
|
draw_pixel = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (draw_pixel)
|
||||||
|
put_pixel(i, j, fill_color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Draw the border (stroke) --- */
|
||||||
|
if (radius > 0) {
|
||||||
|
/* Draw the top and bottom horizontal lines (excluding the rounded corners) */
|
||||||
|
for (i = x + radius; i < x + xs - radius; i++) {
|
||||||
|
put_pixel(i, y, stroke_color); /* Top edge */
|
||||||
|
put_pixel(i, y + ys - 1, stroke_color); /* Bottom edge */
|
||||||
|
}
|
||||||
|
/* Draw the left and right vertical lines (excluding the rounded corners) */
|
||||||
|
for (j = y + radius; j < y + ys - radius; j++) {
|
||||||
|
put_pixel(x, j, stroke_color); /* Left edge */
|
||||||
|
put_pixel(x + xs - 1, j, stroke_color); /* Right edge */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Draw the four corner arcs */
|
||||||
|
/* Top-left corner */
|
||||||
|
draw_circle_quarter(x + radius, y + radius, radius, 0, stroke_color);
|
||||||
|
/* Top-right corner */
|
||||||
|
draw_circle_quarter(x + xs - radius - 1, y + radius, radius, 1, stroke_color);
|
||||||
|
/* Bottom-right corner */
|
||||||
|
draw_circle_quarter(x + xs - radius - 1, y + ys - radius - 1, radius, 2, stroke_color);
|
||||||
|
/* Bottom-left corner */
|
||||||
|
draw_circle_quarter(x + radius, y + ys - radius - 1, radius, 3, stroke_color);
|
||||||
|
} else {
|
||||||
|
/* If radius == 0, draw a normal (non–rounded) rectangle border */
|
||||||
|
for (i = x; i < x + xs; i++) {
|
||||||
|
put_pixel(i, y, stroke_color);
|
||||||
|
put_pixel(i, y + ys - 1, stroke_color);
|
||||||
|
}
|
||||||
|
for (j = y; j < y + ys; j++) {
|
||||||
|
put_pixel(x, j, stroke_color);
|
||||||
|
put_pixel(x + xs - 1, j, stroke_color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
394
libs/csv.hpp
Normal file
394
libs/csv.hpp
Normal file
|
@ -0,0 +1,394 @@
|
||||||
|
#pragma once
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///Describes mapping of column to a string field in the target structure
|
||||||
|
/**
|
||||||
|
* @tparam T type of target structure
|
||||||
|
*
|
||||||
|
* Supported types: string, int16-64, unsigned int 16-64, float, double, boolean, char
|
||||||
|
*
|
||||||
|
* nullptr is used to skip the field
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
struct CSVFieldMapping {
|
||||||
|
|
||||||
|
using FieldRef = std::variant<std::string T::*,
|
||||||
|
std::uint64_t T::*,
|
||||||
|
std::int64_t T::*,
|
||||||
|
std::uint32_t T::*,
|
||||||
|
std::int32_t T::*,
|
||||||
|
std::uint16_t T::*,
|
||||||
|
std::int16_t T::*,
|
||||||
|
char T::*,
|
||||||
|
unsigned char T::*,
|
||||||
|
float T::*,
|
||||||
|
double T::*,
|
||||||
|
bool T::*,
|
||||||
|
std::nullptr_t>;
|
||||||
|
///name of field
|
||||||
|
std::string name;
|
||||||
|
///pointer to member field
|
||||||
|
FieldRef field;
|
||||||
|
};
|
||||||
|
|
||||||
|
///Contains final mapping columns to structure. The instance is created by the function mapColumns
|
||||||
|
template<typename T>
|
||||||
|
class CSVFieldIndexMapping : public std::vector<typename CSVFieldMapping<T>::FieldRef > {
|
||||||
|
public:
|
||||||
|
using std::vector<typename CSVFieldMapping<T>::FieldRef >::vector;
|
||||||
|
///contains true, if all fields has been mapped. Otherwise it is false
|
||||||
|
/** to find, which field is not mapped you need to find it manually
|
||||||
|
*/
|
||||||
|
bool allMapped = false;
|
||||||
|
|
||||||
|
template<typename X>
|
||||||
|
constexpr bool isMapped(X T::*ptr) const {
|
||||||
|
if (allMapped) return true;
|
||||||
|
return std::find(this->begin(),
|
||||||
|
this->end(), typename CSVFieldMapping<T>::FieldRef(ptr)) != this->end();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
///Simple CSV reader
|
||||||
|
/**
|
||||||
|
* Parses CSV from the source. Each read returns one field until whole CSV is parsed
|
||||||
|
*
|
||||||
|
* @tparam Source the type of object which provides source data. This can also be a function.
|
||||||
|
* because the type must implement following function call <int()>. The input characters
|
||||||
|
* should be read as unsigned (so characters above 0x80 are not mapped bellow the zero). The
|
||||||
|
* function must return EOF (-1) as end of file.
|
||||||
|
*/
|
||||||
|
template<typename Source>
|
||||||
|
class CSVReader {
|
||||||
|
public:
|
||||||
|
|
||||||
|
|
||||||
|
enum class CSVState: int {
|
||||||
|
///there is next field at the row
|
||||||
|
next = 0,
|
||||||
|
///this field is last field at the row
|
||||||
|
last = 1,
|
||||||
|
///no more field, eof reached
|
||||||
|
eof = std::char_traits<char>::eof()
|
||||||
|
};
|
||||||
|
|
||||||
|
///Inicialize the parser
|
||||||
|
/**
|
||||||
|
* @param src data source. This is function, which returns next character.
|
||||||
|
* Returned type should be int.
|
||||||
|
* If there are no more characters, it should return std::char_traits<char>::eof()
|
||||||
|
*/
|
||||||
|
CSVReader(Source &&src)
|
||||||
|
: _src(std::forward<Source>(src)) {}
|
||||||
|
|
||||||
|
///Read next field
|
||||||
|
/**
|
||||||
|
* @param buffer reference to a string, which will be filled with content of the next field.
|
||||||
|
* The string is always cleared at the beginning regardless on how the operation was completed
|
||||||
|
* @retval next - field read successfully and there is at least one further field
|
||||||
|
* on the same row
|
||||||
|
* @retval last - field read successfully and this was the last field on the row,
|
||||||
|
* next read() will read a field on a new row
|
||||||
|
* @retval eof - reached end of file, buffer is empty
|
||||||
|
*/
|
||||||
|
CSVState read(std::string &buffer);
|
||||||
|
|
||||||
|
|
||||||
|
///Contains eof value
|
||||||
|
static constexpr auto eof = std::char_traits<char>::eof();
|
||||||
|
|
||||||
|
|
||||||
|
///Reads line and creates mapping of columns to structure
|
||||||
|
/**
|
||||||
|
* Function is intended to be called for the first line, which contains columns' names
|
||||||
|
*
|
||||||
|
* @tparam T You probably need to explicitly specify type
|
||||||
|
* @param def definition
|
||||||
|
* @return mapping
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
* struct CSVCols {
|
||||||
|
* std::string symbol_data_type;
|
||||||
|
* std::string format;
|
||||||
|
* std::string interval;
|
||||||
|
* std::string directory;
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* auto mapping = reader.mapColumns<CSVCols>({
|
||||||
|
* {"symbol_data_type",&CSVCols::symbol_data_type},
|
||||||
|
* {"format", &CSVCols::format},
|
||||||
|
* {"interval", &CSVCols::interval},
|
||||||
|
* {"directory", &CSVCols::directory},
|
||||||
|
* });
|
||||||
|
* if (!mapping.allMapped) return false;
|
||||||
|
* @encode
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
CSVFieldIndexMapping<T> mapColumns(const std::initializer_list<CSVFieldMapping<T> > &def);
|
||||||
|
|
||||||
|
|
||||||
|
///Reads row and transfer data to target structure through the mapping object
|
||||||
|
/**
|
||||||
|
* @param mapping mapping object created by mapColumns
|
||||||
|
* @param target target structure which is filled from the line
|
||||||
|
* @retval true some data read
|
||||||
|
* @retval false end of table (no data read)
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
bool readRow(const CSVFieldIndexMapping<T> &mapping, T &target);
|
||||||
|
|
||||||
|
///Reset state - assume that source has been reset
|
||||||
|
void reset() {
|
||||||
|
_eof_reached = false;
|
||||||
|
_beg_line = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool skipLine() {
|
||||||
|
std::string buff;
|
||||||
|
while (read(buff) == CSVState::next);
|
||||||
|
return !_eof_reached;
|
||||||
|
}
|
||||||
|
|
||||||
|
///Change the character for quotes
|
||||||
|
/**
|
||||||
|
* @param quotes new character for quotes
|
||||||
|
*
|
||||||
|
* @note you need to change this value before the first line is read
|
||||||
|
* (including the function mapColumns())
|
||||||
|
*
|
||||||
|
* (default=")
|
||||||
|
*/
|
||||||
|
void setQuotes(char quotes) {_quotes = quotes;}
|
||||||
|
|
||||||
|
|
||||||
|
///Retrieves character for quotes
|
||||||
|
char getQuotes() const {return _quotes;}
|
||||||
|
|
||||||
|
///Change the character for field separator
|
||||||
|
/**
|
||||||
|
* @param sep new separator
|
||||||
|
*
|
||||||
|
* @note you need to change this value before the first line is read
|
||||||
|
* (including the function mapColumns())
|
||||||
|
*
|
||||||
|
* (default=,)
|
||||||
|
*/
|
||||||
|
void setSep(char sep) {_sep = sep;}
|
||||||
|
|
||||||
|
|
||||||
|
///set field separator
|
||||||
|
char getSep() const {return _sep;}
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Source _src;
|
||||||
|
char _sep = ',';
|
||||||
|
char _quotes = '"';
|
||||||
|
bool _eof_reached = false;
|
||||||
|
bool _beg_line = true;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
///This CTAD allows to construct CSVReader without template arguments from lambda
|
||||||
|
/**
|
||||||
|
* CSVReader csv([&]() -> int {return .... ;});
|
||||||
|
*/
|
||||||
|
template<typename Source>
|
||||||
|
CSVReader(Source) -> CSVReader<Source>;
|
||||||
|
|
||||||
|
///Instantiate parser supplying a lambda function as a source
|
||||||
|
template<typename Fn>
|
||||||
|
CSVReader<Fn> parseCSV(Fn &&fn) {
|
||||||
|
return CSVReader<Fn>(std::forward<Fn>(fn));
|
||||||
|
}
|
||||||
|
|
||||||
|
///Instantiate parse supplying an input stream as a source
|
||||||
|
/**
|
||||||
|
* @param input input stream. Note it must stay valid during parsing
|
||||||
|
* @return CSVReader instance
|
||||||
|
*/
|
||||||
|
inline auto parseCSVFromFile(std::istream &input) {
|
||||||
|
return parseCSV([&]{return input.get();});
|
||||||
|
}
|
||||||
|
|
||||||
|
///Instantiate the parser supplying a string as a source
|
||||||
|
/**
|
||||||
|
* @param str string source
|
||||||
|
* @return CSVReader reader
|
||||||
|
*/
|
||||||
|
inline auto parseCSVString(std::string &&str) {
|
||||||
|
return parseCSV([s = std::move(str), pos = std::size_t(0)]() mutable {
|
||||||
|
return pos>=s.size()?std::char_traits<char>::eof()
|
||||||
|
:static_cast<int>(static_cast<unsigned char>(s[pos++]));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
///Instantiate the parser supplying a string as a source
|
||||||
|
/**
|
||||||
|
* @param str string source - must be valid during parsing
|
||||||
|
* @return CSVReader reader
|
||||||
|
*/
|
||||||
|
inline auto parseCSVString(std::string_view str) {
|
||||||
|
return parseCSV([=, pos = std::size_t(0)]() mutable {
|
||||||
|
return pos>=str.size()?std::char_traits<char>::eof()
|
||||||
|
:static_cast<int>(static_cast<unsigned char>(str[pos++]));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Source>
|
||||||
|
inline typename CSVReader<Source>::CSVState CSVReader<Source>::read(std::string &buffer) {
|
||||||
|
buffer.clear();
|
||||||
|
if (_eof_reached) return CSVState::eof;
|
||||||
|
int c = _src();
|
||||||
|
if (_beg_line) {
|
||||||
|
while (c != eof && std::iscntrl(c)) c = _src();
|
||||||
|
}
|
||||||
|
if (c == eof) return CSVState::eof;
|
||||||
|
if (c == _quotes) {
|
||||||
|
bool loop;
|
||||||
|
do {
|
||||||
|
c= _src();
|
||||||
|
while (c != _quotes && c != eof) {
|
||||||
|
buffer.push_back(static_cast<char>(c));
|
||||||
|
c = _src();
|
||||||
|
}
|
||||||
|
loop = false;
|
||||||
|
if (c == _quotes) {
|
||||||
|
c = _src();
|
||||||
|
if (c == _quotes) {
|
||||||
|
loop = true;
|
||||||
|
buffer.push_back(_quotes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (loop);
|
||||||
|
while (c != eof && c != _sep && c != '\n' && c != '\r') {
|
||||||
|
c = _src(); //ignore incorrect csv content
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while (c != _sep && c != eof && c != '\n' && c != '\r') {
|
||||||
|
buffer.push_back(static_cast<char>(c));
|
||||||
|
c = _src();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (c == eof) _eof_reached = true;
|
||||||
|
_beg_line = c != _sep;
|
||||||
|
|
||||||
|
return _beg_line?CSVState::last:CSVState::next;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Source>
|
||||||
|
template<typename T>
|
||||||
|
inline CSVFieldIndexMapping<T> CSVReader<Source>::mapColumns(const std::initializer_list<CSVFieldMapping<T> > &def) {
|
||||||
|
CSVFieldIndexMapping<T> out;
|
||||||
|
std::string buff;
|
||||||
|
std::size_t cnt = def.size();
|
||||||
|
CSVState st = CSVState::next;
|
||||||
|
while (st != CSVState::last) {
|
||||||
|
st = this->read(buff);
|
||||||
|
if (st == CSVState::eof) break;
|
||||||
|
auto iter = std::find_if(def.begin(), def.end(), [&](const CSVFieldMapping<T> &x) {
|
||||||
|
return x.name == buff;
|
||||||
|
});
|
||||||
|
if (iter != def.end()) {
|
||||||
|
out.push_back(iter->field);
|
||||||
|
cnt--;
|
||||||
|
} else {
|
||||||
|
out.push_back(nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.allMapped = cnt == 0;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Source>
|
||||||
|
template<typename T>
|
||||||
|
inline bool CSVReader<Source>::readRow(const CSVFieldIndexMapping<T> &mapping,T &target) {
|
||||||
|
std::string buff;
|
||||||
|
std::size_t idx = 0;
|
||||||
|
CSVState st = CSVState::next;
|
||||||
|
while (st == CSVState::next) {
|
||||||
|
if (idx < mapping.size()) {
|
||||||
|
const auto &m = mapping[idx];
|
||||||
|
st = std::visit([&](const auto &ptr) -> CSVState{
|
||||||
|
using TPtr = std::decay_t<decltype(ptr)>;
|
||||||
|
if constexpr(!std::is_null_pointer_v<TPtr>) {
|
||||||
|
using TVal = std::decay_t<decltype(target.*ptr)>;
|
||||||
|
if constexpr(std::is_same_v<TVal, std::string>) {
|
||||||
|
return read(target.*ptr);
|
||||||
|
} else if constexpr(std::is_same_v<TVal, std::uint16_t> || std::is_same_v<TVal, std::uint64_t> || std::is_same_v<TVal, std::uint32_t>) {
|
||||||
|
CSVState st = read(buff);
|
||||||
|
auto v = std::strtoull(buff.c_str(),nullptr,10);
|
||||||
|
target.*ptr = static_cast<TVal>(v);
|
||||||
|
return st;
|
||||||
|
} else if constexpr(std::is_same_v<TVal, std::int16_t> || std::is_same_v<TVal, std::int64_t> || std::is_same_v<TVal, std::int32_t>) {
|
||||||
|
CSVState st = read(buff);
|
||||||
|
auto v = std::strtoll(buff.c_str(),nullptr,10);
|
||||||
|
target.*ptr = static_cast<TVal>(v);
|
||||||
|
return st;
|
||||||
|
} else if constexpr(std::is_same_v<TVal, float> || std::is_same_v<TVal, double>) {
|
||||||
|
CSVState st = read(buff);
|
||||||
|
auto v = std::strtod(buff.c_str(), nullptr);
|
||||||
|
target.*ptr = static_cast<TVal>(v);
|
||||||
|
return st;
|
||||||
|
} else if constexpr(std::is_same_v<TVal, char> || std::is_same_v<TVal, unsigned char>) {
|
||||||
|
CSVState st = read(buff);
|
||||||
|
if (buff.empty()) target.*ptr = 0;
|
||||||
|
else target.*ptr = static_cast<TVal>(buff[0]);
|
||||||
|
return st;
|
||||||
|
} else {
|
||||||
|
static_assert(std::is_same_v<TVal, bool>);
|
||||||
|
CSVState st = read(buff);
|
||||||
|
std::transform(buff.begin(), buff.end(), buff.begin(), [](char c) { return std::tolower(c); });
|
||||||
|
if (buff == "y" || buff == "t" || buff =="true" || buff == "yes" || buff == "on") {
|
||||||
|
target.*ptr = true;
|
||||||
|
} else if (buff == "n" || buff == "f" || buff =="false" || buff == "no" || buff == "off") {
|
||||||
|
target.*ptr = false;
|
||||||
|
} else {
|
||||||
|
auto v = std::strtod(buff.c_str(), nullptr);
|
||||||
|
target.*ptr = v != 0;
|
||||||
|
}
|
||||||
|
return st;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return read(buff);
|
||||||
|
}
|
||||||
|
}, m);
|
||||||
|
// st = read(target.*m);
|
||||||
|
if (st == CSVState::eof)
|
||||||
|
break;
|
||||||
|
++idx;
|
||||||
|
} else {
|
||||||
|
st = read(buff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (st == CSVState::eof && idx == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//fill-up missing fields
|
||||||
|
while (idx < mapping.size()) {
|
||||||
|
const auto &m = mapping[idx];
|
||||||
|
std::visit([&](const auto &ptr) {
|
||||||
|
using TPtr = std::decay_t<decltype(ptr)>;
|
||||||
|
if constexpr(!std::is_null_pointer_v<TPtr>) {
|
||||||
|
target.*ptr = {};
|
||||||
|
}
|
||||||
|
},m);
|
||||||
|
++idx;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
51
libs/string_table.cpp
Normal file
51
libs/string_table.cpp
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
#include "string_table.h"
|
||||||
|
#include "csv.hpp"
|
||||||
|
#include "cztable.h"
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <fstream>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct stringtable_struct_tag {
|
||||||
|
|
||||||
|
std::unordered_map<int, std::string> _strings;
|
||||||
|
|
||||||
|
}TSTRINGTABLE;
|
||||||
|
|
||||||
|
struct CSVRecord {
|
||||||
|
int index;
|
||||||
|
std::string string;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TSTRINGTABLE *stringtable_load(const char *filename) {
|
||||||
|
std::ifstream input(filename);
|
||||||
|
if (!input) return NULL;
|
||||||
|
CSVReader reader([&input]{return input.get();});
|
||||||
|
auto mapping = reader.mapColumns<CSVRecord>({
|
||||||
|
{"id", &CSVRecord::index},
|
||||||
|
{"string", &CSVRecord::string},
|
||||||
|
});
|
||||||
|
if (!mapping.allMapped) return NULL;
|
||||||
|
CSVRecord rec;
|
||||||
|
std::unique_ptr<TSTRINGTABLE> tbl = std::make_unique<TSTRINGTABLE>();
|
||||||
|
while (reader.readRow(mapping, rec)) {
|
||||||
|
windows2kamenik(rec.string.data(), rec.string.size(), rec.string.data());
|
||||||
|
tbl->_strings[rec.index] = rec.string;
|
||||||
|
}
|
||||||
|
return tbl.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *stringtable_find(const TSTRINGTABLE *st, int id, const char *default_value) {
|
||||||
|
if (st) {
|
||||||
|
auto iter = st->_strings.find(id);
|
||||||
|
if (iter != st->_strings.end()) {
|
||||||
|
return iter->second.c_str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return default_value;
|
||||||
|
}
|
||||||
|
void stringtable_free(TSTRINGTABLE *st) {
|
||||||
|
delete st;
|
||||||
|
}
|
||||||
|
|
18
libs/string_table.h
Normal file
18
libs/string_table.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct stringtable_struct_tag TSTRINGTABLE;
|
||||||
|
|
||||||
|
TSTRINGTABLE *stringtable_load(const char *filename);
|
||||||
|
|
||||||
|
const char *stringtable_find(const TSTRINGTABLE *st, int id, const char *default_value);
|
||||||
|
void stringtable_free(TSTRINGTABLE *st);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -1,10 +1,9 @@
|
||||||
SET(files error.cpp
|
SET(files error.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
# Základní knihovna mylib
|
|
||||||
add_library(skeldal_platform STATIC)
|
add_library(skeldal_platform STATIC)
|
||||||
|
add_executable(skeldal)
|
||||||
|
|
||||||
# Přidejte soubory společné pro všechny platformy
|
|
||||||
target_sources(skeldal_platform PRIVATE
|
target_sources(skeldal_platform PRIVATE
|
||||||
legacy_coroutines.cpp
|
legacy_coroutines.cpp
|
||||||
platform.cpp
|
platform.cpp
|
||||||
|
@ -17,7 +16,6 @@ target_sources(skeldal_platform PRIVATE
|
||||||
getopt.c
|
getopt.c
|
||||||
)
|
)
|
||||||
|
|
||||||
# Podmínky pro platformu Windows
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
target_sources(skeldal_platform PRIVATE
|
target_sources(skeldal_platform PRIVATE
|
||||||
windows/save_folder.cpp
|
windows/save_folder.cpp
|
||||||
|
@ -25,20 +23,25 @@ if(WIN32)
|
||||||
target_compile_definitions(skeldal_platform PRIVATE PLATFORM_WINDOWS)
|
target_compile_definitions(skeldal_platform PRIVATE PLATFORM_WINDOWS)
|
||||||
message(STATUS "Building for Windows")
|
message(STATUS "Building for Windows")
|
||||||
|
|
||||||
# Podmínky pro platformu Linux
|
|
||||||
elseif(UNIX AND NOT APPLE)
|
elseif(UNIX AND NOT APPLE)
|
||||||
target_sources(skeldal_platform PRIVATE
|
target_sources(skeldal_platform PRIVATE
|
||||||
linux/save_folder.cpp
|
linux/save_folder.cpp
|
||||||
linux/map_file.cpp
|
linux/map_file.cpp
|
||||||
)
|
)
|
||||||
|
target_sources(skeldal PRIVATE
|
||||||
|
linux/app_start.cpp
|
||||||
|
)
|
||||||
target_compile_definitions(skeldal_platform PRIVATE PLATFORM_LINUX)
|
target_compile_definitions(skeldal_platform PRIVATE PLATFORM_LINUX)
|
||||||
message(STATUS "Building for Linux")
|
message(STATUS "Building for Linux")
|
||||||
|
|
||||||
# Podmínky pro platformu macOS
|
|
||||||
elseif(APPLE)
|
elseif(APPLE)
|
||||||
target_sources(skeldal_platform PRIVATE
|
target_sources(skeldal_platform PRIVATE
|
||||||
mac_os/save_folder.cpp
|
mac_os/save_folder.cpp
|
||||||
)
|
)
|
||||||
|
target_sources(skeldal PRIVATE
|
||||||
|
linux/app_start.cpp
|
||||||
|
)
|
||||||
target_compile_definitions(mylib PRIVATE PLATFORM_MACOS)
|
target_compile_definitions(mylib PRIVATE PLATFORM_MACOS)
|
||||||
message(STATUS "Building for macOS")
|
message(STATUS "Building for macOS")
|
||||||
else()
|
else()
|
||||||
|
@ -47,3 +50,11 @@ endif()
|
||||||
set_property(TARGET skeldal_platform PROPERTY CXX_STANDARD 20)
|
set_property(TARGET skeldal_platform PROPERTY CXX_STANDARD 20)
|
||||||
|
|
||||||
add_subdirectory(sdl)
|
add_subdirectory(sdl)
|
||||||
|
|
||||||
|
target_link_libraries(skeldal
|
||||||
|
skeldal_main
|
||||||
|
skeldal_libs
|
||||||
|
skeldal_platform
|
||||||
|
skeldal_sdl
|
||||||
|
skeldal_libs
|
||||||
|
${SDL2_LIBRARIES} pthread)
|
||||||
|
|
|
@ -8,10 +8,6 @@
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
|
||||||
|
|
||||||
void display_error(const char *text) {
|
|
||||||
std::cerr << "ERROR:" << text << std::endl;
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static std::uint32_t gtick = get_game_tick_count();
|
static std::uint32_t gtick = get_game_tick_count();
|
||||||
|
|
|
@ -6,7 +6,6 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
void display_error(const char *text);
|
|
||||||
void send_log_impl(const char *format, ...);
|
void send_log_impl(const char *format, ...);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
#ifndef GETOPT_H
|
#ifndef GETOPT_H
|
||||||
|
|
||||||
#define GETOPT_H
|
#define GETOPT_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
extern int opterr; /* if error message should be printed */
|
extern int opterr; /* if error message should be printed */
|
||||||
extern int optind; /* index into parent argv vector */
|
extern int optind; /* index into parent argv vector */
|
||||||
extern int optopt; /* character checked for validity */
|
extern int optopt; /* character checked for validity */
|
||||||
|
@ -10,4 +15,9 @@ extern char *optarg; /* argument associated with option */
|
||||||
|
|
||||||
int getopt(int nargc, char * const nargv[], const char *ostr);
|
int getopt(int nargc, char * const nargv[], const char *ostr);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -40,8 +40,8 @@ struct MsgQueue {
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::queue<MsgQueue> msg_queue;
|
static std::queue<MsgQueue> msg_queue;
|
||||||
|
static int recursion_count = 0;
|
||||||
|
|
||||||
static void flush_message_queue();
|
|
||||||
|
|
||||||
static void task_after_wakeup(TaskInfo *info) {
|
static void task_after_wakeup(TaskInfo *info) {
|
||||||
info->wake_up_msg = -1;
|
info->wake_up_msg = -1;
|
||||||
|
@ -67,7 +67,6 @@ static void switch_to_task(TaskInfo *task) {
|
||||||
task->resume_flag.notify_all();
|
task->resume_flag.notify_all();
|
||||||
resume_master_flag.wait(false);
|
resume_master_flag.wait(false);
|
||||||
resume_master_flag = false;
|
resume_master_flag = false;
|
||||||
flush_message_queue();
|
|
||||||
} else {
|
} else {
|
||||||
if (task->exited) return ;
|
if (task->exited) return ;
|
||||||
TaskInfo *me = current_task_inst;
|
TaskInfo *me = current_task_inst;
|
||||||
|
@ -81,6 +80,7 @@ static void switch_to_task(TaskInfo *task) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clean_task_table() {
|
static void clean_task_table() {
|
||||||
|
if (recursion_count) return;
|
||||||
for (auto iter = task_list.begin(); iter != task_list.end();) {
|
for (auto iter = task_list.begin(); iter != task_list.end();) {
|
||||||
if (iter->second->exited) {
|
if (iter->second->exited) {
|
||||||
iter = task_list.erase(iter);
|
iter = task_list.erase(iter);
|
||||||
|
@ -100,25 +100,23 @@ static void clean_up_current_task() {
|
||||||
resume_master_flag.notify_all();
|
resume_master_flag.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void flush_message_queue() {
|
static void broadcast_message(EVENT_MSG *msg) {
|
||||||
while (!msg_queue.empty()) {
|
++recursion_count;
|
||||||
auto m = msg_queue.front();
|
|
||||||
msg_queue.pop();
|
|
||||||
for (auto &[id, task]: task_list) {
|
for (auto &[id, task]: task_list) {
|
||||||
if (task->wake_up_msg == m.msg->msg && task.get() != m.sender) {
|
if (task->wake_up_msg == msg->msg && task.get() != current_task_inst) {
|
||||||
EVENT_MSG cpy;
|
EVENT_MSG cpy;
|
||||||
cpy.msg = m.msg->msg;
|
cpy.msg = msg->msg;
|
||||||
va_copy(cpy.data, m.msg->data);
|
va_copy(cpy.data, msg->data);
|
||||||
cur_message = &cpy;
|
cur_message = &cpy;
|
||||||
switch_to_task(task.get());
|
switch_to_task(task.get());
|
||||||
va_end(cpy.data);
|
va_end(cpy.data);
|
||||||
cur_message = NULL;
|
cur_message = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
--recursion_count;
|
||||||
clean_task_table();
|
clean_task_table();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int add_task(int stack,TaskerFunctionName fcname,...) {
|
int add_task(int stack,TaskerFunctionName fcname,...) {
|
||||||
int id = get_new_task_id();
|
int id = get_new_task_id();
|
||||||
|
@ -150,21 +148,21 @@ char is_running(int id_num) {
|
||||||
return !iter->second->exited;
|
return !iter->second->exited;
|
||||||
}
|
}
|
||||||
void unsuspend_task(EVENT_MSG *msg) {
|
void unsuspend_task(EVENT_MSG *msg) {
|
||||||
if (current_task_inst) return;
|
|
||||||
msg_queue.push({msg, current_task_inst});
|
msg_queue.push({msg, current_task_inst});
|
||||||
flush_message_queue();
|
broadcast_message(msg);
|
||||||
|
|
||||||
}
|
}
|
||||||
void task_sleep(void) {
|
void task_sleep(void) {
|
||||||
if (current_task_inst) {
|
if (current_task_inst) {
|
||||||
switch_to_task(NULL);
|
switch_to_task(NULL);
|
||||||
} else {
|
} else {
|
||||||
auto now = std::chrono::system_clock::now();
|
auto now = std::chrono::system_clock::now();
|
||||||
|
recursion_count++;
|
||||||
for (auto &[id, task]: task_list) {
|
for (auto &[id, task]: task_list) {
|
||||||
if (task->_wake_up_after < now && task->wake_up_msg == -1) {
|
if (task->_wake_up_after < now && task->wake_up_msg == -1) {
|
||||||
switch_to_task(task.get());
|
switch_to_task(task.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
recursion_count--;
|
||||||
clean_task_table();
|
clean_task_table();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
73
platform/linux/app_start.cpp
Normal file
73
platform/linux/app_start.cpp
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
#include "../../game/skeldal.h"
|
||||||
|
#include "../getopt.h"
|
||||||
|
#include "../platform.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
void show_help(const char *arg0) {
|
||||||
|
printf(
|
||||||
|
"Brany Skeldalu (Gates of Skeldal) portable game player\n"
|
||||||
|
"Copyright (c) 2025 Ondrej Novak. All rights reserved.\n\n"
|
||||||
|
"This work is licensed under the terms of the MIT license.\n"
|
||||||
|
"For a copy, see <https://opensource.org/licenses/MIT>.\n"
|
||||||
|
"\n"
|
||||||
|
"Usage:"
|
||||||
|
);
|
||||||
|
printf("%s [-f <file>] [-a <file>] [-l <lang>] [-s <dir>] [-h]\n\n", arg0);
|
||||||
|
|
||||||
|
printf("-f <file> path to configuration file\n"
|
||||||
|
"-a <adv> path for adventure file (.adv)\n"
|
||||||
|
"-l <lang> set language (cz|en)"
|
||||||
|
"-s <directory> generate string-tables (for localization) and exit\n"
|
||||||
|
"-h this help\n");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void show_help_short() {
|
||||||
|
printf("Use -h for help\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
std::string config_name = SKELDALINI;
|
||||||
|
std::string adv_config_file;
|
||||||
|
std::string gen_stringtable_path;
|
||||||
|
std::string lang;
|
||||||
|
for (int optchr = -1; (optchr = getopt(argc, argv, "hf:a:s:l:")) != -1; ) {
|
||||||
|
switch (optchr) {
|
||||||
|
case 'f': config_name = optarg;break;
|
||||||
|
case 'a': adv_config_file = optarg;break;
|
||||||
|
case 'h': show_help(argv[0]);break;
|
||||||
|
case 'l': lang = optarg;break;
|
||||||
|
case 's': gen_stringtable_path = optarg;break;
|
||||||
|
default: show_help_short();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SKELDAL_CONFIG cfg;
|
||||||
|
cfg.short_help = show_help_short;
|
||||||
|
cfg.show_error = [](const char *txt) {
|
||||||
|
std::cerr << "ERROR: " << txt << std::endl;
|
||||||
|
};
|
||||||
|
cfg.adventure_path = adv_config_file.empty()?NULL:adv_config_file.c_str();
|
||||||
|
cfg.config_path = config_name.c_str();
|
||||||
|
cfg.lang_path = lang.c_str();
|
||||||
|
try {
|
||||||
|
|
||||||
|
if (!gen_stringtable_path.empty()) {
|
||||||
|
skeldal_gen_string_table_entry_point(&cfg, gen_stringtable_path.c_str());
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return skeldal_entry_point(&cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
std::cerr << "ERROR: " << e.what() << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ static std::string get_default_savegame_dir() {
|
||||||
if (home) {
|
if (home) {
|
||||||
return std::filesystem::path(home) / ".local/share/" SAVEGAME_FOLDERNAME;
|
return std::filesystem::path(home) / ".local/share/" SAVEGAME_FOLDERNAME;
|
||||||
} else {
|
} else {
|
||||||
display_error("$HOME has no value (user with no home)");
|
throw std::runtime_error("$HOME has no value (user with no home)");
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,7 @@ void SetWheelMapping(char up, char down);
|
||||||
char get_control_key_state(void);
|
char get_control_key_state(void);
|
||||||
char get_shift_key_state(void);
|
char get_shift_key_state(void);
|
||||||
char get_capslock_state(void);
|
char get_capslock_state(void);
|
||||||
void display_error(const char *text);
|
void display_error(const char *text,...);
|
||||||
///returns -1 if doesn't exists
|
///returns -1 if doesn't exists
|
||||||
char check_file_exists(const char *pathname);
|
char check_file_exists(const char *pathname);
|
||||||
FILE *fopen_icase(const char *pathname, const char *mode);
|
FILE *fopen_icase(const char *pathname, const char *mode);
|
||||||
|
|
|
@ -259,10 +259,11 @@ void SDLContext::event_loop(std::stop_token stp) {
|
||||||
if (e.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
|
if (e.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
|
||||||
_crt_effect.reset();
|
_crt_effect.reset();
|
||||||
}
|
}
|
||||||
} else if (e.type == SDL_KEYDOWN) {
|
} else if (e.type == SDL_KEYDOWN || e.type == SDL_KEYUP) {
|
||||||
_key_capslock = e.key.keysym.mod & KMOD_CAPS;
|
_key_capslock = e.key.keysym.mod & KMOD_CAPS;
|
||||||
_key_shift =e.key.keysym.mod & KMOD_SHIFT;
|
_key_shift =e.key.keysym.mod & KMOD_SHIFT;
|
||||||
_key_control =e.key.keysym.mod & KMOD_CTRL;
|
_key_control =e.key.keysym.mod & KMOD_CTRL;
|
||||||
|
if (e.type == SDL_KEYDOWN) {
|
||||||
if (e.key.keysym.sym == SDLK_RETURN && (e.key.keysym.mod & KMOD_ALT)) {
|
if (e.key.keysym.sym == SDLK_RETURN && (e.key.keysym.mod & KMOD_ALT)) {
|
||||||
_fullscreen_mode = !_fullscreen_mode;
|
_fullscreen_mode = !_fullscreen_mode;
|
||||||
SDL_SetWindowFullscreen(_window.get(), _fullscreen_mode ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
|
SDL_SetWindowFullscreen(_window.get(), _fullscreen_mode ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
|
||||||
|
@ -274,6 +275,7 @@ void SDLContext::event_loop(std::stop_token stp) {
|
||||||
_keyboard_queue.push(code);
|
_keyboard_queue.push(code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if (e.type == SDL_MOUSEMOTION) {
|
} else if (e.type == SDL_MOUSEMOTION) {
|
||||||
SDL_Point mspt(e.motion.x, e.motion.y);
|
SDL_Point mspt(e.motion.x, e.motion.y);
|
||||||
SDL_Rect winrc = get_window_aspect_rect();
|
SDL_Rect winrc = get_window_aspect_rect();
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
# maps = relative path to maps
|
# maps = relative path to maps
|
||||||
# video = relative path to video
|
# video = relative path to video
|
||||||
# data = relative path to skeldal.ddl
|
# data = relative path to skeldal.ddl
|
||||||
|
# language = path language folders
|
||||||
# savegame = path to savegame, if not defined, retrieved from platform settings
|
# savegame = path to savegame, if not defined, retrieved from platform settings
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,6 +13,7 @@
|
||||||
# maps=./maps/
|
# maps=./maps/
|
||||||
# video=./video/
|
# video=./video/
|
||||||
# data=./
|
# data=./
|
||||||
|
# language=./lang
|
||||||
# savegame = determine default
|
# savegame = determine default
|
||||||
|
|
||||||
#### video settings
|
#### video settings
|
||||||
|
@ -61,6 +63,4 @@
|
||||||
# (note, internal fonts supports only characters from KEYBCS2/CP895 code page)
|
# (note, internal fonts supports only characters from KEYBCS2/CP895 code page)
|
||||||
# (https://en.wikipedia.org/wiki/Kamenick%C3%BD_encoding)
|
# (https://en.wikipedia.org/wiki/Kamenick%C3%BD_encoding)
|
||||||
#
|
#
|
||||||
[localization]
|
|
||||||
#keyboard_layout=cz_querty
|
|
||||||
#string_table=
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue