a lot of changes and support languages

This commit is contained in:
Ondřej Novák 2025-02-07 20:26:54 +01:00
parent 185a6e5382
commit f55f92a88b
38 changed files with 1221 additions and 467 deletions

View file

@ -36,13 +36,8 @@ console.c
gen_stringtable.c
advconfig.c
temp_storage.cpp
lang.c
${CMAKE_BINARY_DIR}/default_font.cpp
)
add_executable(skeldal ${files})
target_link_libraries(skeldal
skeldal_libs
skeldal_platform
skeldal_sdl
skeldal_libs
${SDL2_LIBRARIES} pthread)
add_library(skeldal_main ${files})

View file

@ -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;
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;
if (q[i].flags & SD_INVIS) curcolor=AUTOMAP_FORE;
if (curcolor!=AUTOMAP_FORE)

View file

@ -828,6 +828,7 @@ static int draw_basic_sector(int celx, int cely, int sector) {
int tmask = true_seeing?SD_TRUESEE:0;
w = &map_sides[sector * 4];
q = &w[dirs[1]];
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 );
if (q->flags & SD_RIGHT_ARC && q->oblouk & 0x0f)
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));
if (q->flags & SD_SEC_VIS && q->sec) {
if (q->flags & (SD_SEC_VIS|tmask) && q->sec) {
if (q->side_tag & SD_SHIFTUP) {
if (cely != 0) {
show_cel2(celx, cely - 1,
@ -866,13 +867,13 @@ static int draw_basic_sector(int celx, int cely, int sector) {
if (left_shiftup)
show_cel(celx, cely, ablock(num_ofsets[LEFT_NUM] + 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,
ablock(
num_ofsets[LEFT_NUM] + q->prim
+ (q->prim_anim >> 4)), 0, 0,
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 (celx != 0) {
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)
show_cel(celx, cely, ablock(num_ofsets[RIGHT_NUM] + right_shiftup),
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,
ablock(
num_ofsets[RIGHT_NUM] + q->prim
+ (q->prim_anim >> 4)), 0, 0,
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 (celx != 0)
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);
if (q->flags & SD_RIGHT_ARC && q->oblouk)
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));
if (celx<=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));
}
if (celx>=0)
{
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));
}
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)
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

View file

@ -19,6 +19,7 @@
#include <libs/pcx.h>
#include "globals.h"
#include <stdarg.h>
#include "lang.h"
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 ask_who_proc(int id,int xa,int ya,int xr,int yr);
static TSTRINGTABLE *dialogy_strtable = NULL;
#define CLK_DIALOG 3
static T_CLK_MAP clk_dialog[CLK_DIALOG]=
@ -288,9 +290,10 @@ static void goto_paragraph(int prgf)
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;
while (*source)
{
@ -357,7 +360,7 @@ static char *transfer_text(char *source,char *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);
return transfer_text(source,string_buffer);
@ -370,18 +373,23 @@ static char zjisti_typ()
static char *Get_string()
{
const char *start = (const char *)ablock(H_DIALOGY_DAT);
char *c,i;
if (*pc==P_STRING)
{
int ofs = pc - start+1;
pc++;
c=conv_text(pc);
const char *txt = stringtable_find(dialogy_strtable,ofs, pc);
c=conv_text(txt);
do
{
pc+=strlen(pc)+1;
ofs = pc - start;
if ((i=zjisti_typ())==P_STRING)
{
const char *txt = stringtable_find(dialogy_strtable,ofs, pc);
pc++;
c=transfer_text(pc,c);
c=transfer_text(txt,c);
}
}
while(i==P_STRING);
@ -1222,12 +1230,22 @@ static void cast_spell(int spell)
add_spell(spell,cil,cil,1);
}
static void free_dialog_stringtable() {
stringtable_free(dialogy_strtable);
}
void do_dialog()
{
int i,p1,p2,p3;
char *c;
if (!dialogy_strtable) {
dialogy_strtable = lang_load("dialogs.csv");
if (dialogy_strtable) {
atexit(free_dialog_stringtable);
}
}
do
{
i=Get_short();p3=0;

View file

@ -36,8 +36,8 @@ short zooming_points[ZOOM_PHASES][4]
{480,271,80,28},
{460,259,90,31}
};
int zooming_step=1;
int rot_phases=1;
int zooming_step=2;
int rot_phases=2;
int yreq;
int last_scale;
char secnd_shade=1;

View file

@ -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)
#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_G_COLOR(col) ((col & 0x07E0)>>3)
#define GET_B_COLOR(col) ((col & 0x001F)<<3)
@ -342,6 +342,7 @@ typedef enum skeldal_folders_tag {
SR_DIALOGS,
SR_SAVES,
SR_WORK,
SR_LANG,
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_dir;
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 int32_t game_time; //hraci cas
extern char autoattack;
@ -1049,9 +1050,15 @@ typedef struct tshop
const TPRODUCT *list;
}TSHOP;
typedef struct tshop_product_state_tag {
uint16_t count;
uint16_t previous_price;
} TSHOP_PRODUCT_STATE;
typedef struct tshop_all_state {
const TPRODUCT *first_product;
int32_t *first_state;
TSHOP_PRODUCT_STATE *first_state;
size_t count_states;
} 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,...);
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 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);
void open_story_file(void);
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);
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_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 show_jrc_logo(char *filename);

View file

@ -248,7 +248,7 @@ static char test_kriterii(void)
break;
default:
{
hodn=temp_storage_find(text)>=0;
hodn=temp_storage_find(concat2(text,".map"))>=0;
/* char c[200];
sprintf(c,"%s.TMP",text);
hodn=!check_file_exists(c);*/
@ -356,6 +356,7 @@ static void preskoc_prikaz(void)
switch (ODD)
{
case 0:cti_retezec(1,&text,0,0);ending=1;break;
case '\r':continue;
case '\n':if (ending && uroven==0) return;break;
case EOF: if (uroven!=0)ex_error(OD_OUT);return;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;
char c;
if (found_place) return 0;
if (*found_place) return 0;
if (mob_map[sector])
{
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;
viewsector=lv;
strncpy(x.name,index_tab[index].mapname,12);
x.start_pos=lv;
x.start_pos=0;
x.dir=0;
macro_load_another_map(&x);
return 0;

View file

@ -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);
xs[0]=0;
@ -1354,10 +1354,10 @@ TMPFILE_RD *enc_open(const char *filename)
if (f==NULL) return NULL;
encdata = load_file_to_string(f, &size);
fclose(f);
}
for (int i = 0; i < size; ++i) {
last = (last + encdata[i]) & 0xFF;
encdata[i] = last;
for (int i = 0; i < size; ++i) {
last = (last + encdata[i]) & 0xFF;
encdata[i] = last;
}
}
temp_storage_store("__enc_temp", encdata, size);
free(encdata);
@ -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 text[255],*c,buffer[20];
int y,yu,xu;
int temp1,temp2;
char buffer[20];
int ponuka;
THAGGLERESULT res;
cena,puvod,pocet,money;text[0]=0;text[1]=0;
set_font(H_FBOLD,RGB555(31,31,31));
add_window(170,130,300,100,H_WINTXTR,3,20,20);
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);
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);
do
{
redraw_window();
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();
showview(xu,yu,280,y-yu);
goto_control(10);
escape();
temp1=1;
if (o_aktual->id==20) cena=-1;
else
res.message = 0;
res.hprice = posledni;
res.canceled = 1;
if (o_aktual->id!=20)
{
res.canceled = 0;
get_value(0,10,buffer);
if (buffer[0]==0) c=texty[240];
if (buffer[0]==0) res.message=texty[240];
else
{
if (sscanf(buffer,"%d",&ponuka)!=1) c=texty[237];
if (sscanf(buffer,"%d",&ponuka)!=1) res.message=texty[237];
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
{
if (mode) temp1=smlouvat_nakup(cena,ponuka,posledni,puvod,pocet);
else temp1=smlouvat_prodej(cena,ponuka,posledni,puvod,pocet+1);
posledni=ponuka;
if (rnd(100)<50) c=texty[230+temp1];else c=texty[250+temp1];
int temp1;
if (mode) temp1=smlouvat_nakup(cena,ponuka,posledni,puvod,pocet);
else temp1=smlouvat_prodej(cena,ponuka,posledni,puvod,pocet+1);
res.hprice=ponuka;
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();
shadow_enabled=1;
return cena;
return res;
}
//----------------- JRC LOGO ----------------------------------

View file

@ -18,7 +18,9 @@
#include <libs/pcx.h>
#include "globals.h"
#include "lang.h"
#include <assert.h>
#include <ctype.h>
#include <stddef.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()
@ -2480,8 +2512,8 @@ static void rebuild_shops(const void *shop_ptr)
TPRODUCT *prod_iter = (TPRODUCT *)(shop_iter+max_shops);
shop_all_state.first_product = prod_iter;
shop_all_state.count_states = products;
shop_all_state.first_state = (int32_t *)(prod_iter+products);
int32_t *state_iter = shop_all_state.first_state;
shop_all_state.first_state = (TSHOP_PRODUCT_STATE *)(prod_iter+products);
TSHOP_PRODUCT_STATE *state_iter = shop_all_state.first_state;
for(i=0;i<max_shops;i++) {
shop_list[i] = shop_iter;
@ -2489,7 +2521,8 @@ static void rebuild_shops(const void *shop_ptr)
shop_iter->list = prod_iter;
for (int j = 0; j < shop_iter->products; ++j) {
c = load_TPRODUCT(c, prod_iter);
*state_iter += prod_iter->pocet;
state_iter->count = prod_iter->pocet;
state_iter->previous_price = 0;
++prod_iter;
++state_iter;
}
@ -2515,10 +2548,16 @@ void load_shops(void)
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;
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()
@ -2634,6 +2673,26 @@ static void display_keepers_items()
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()
{
update_mysky();
@ -2648,6 +2707,11 @@ static void redraw_shop()
info_box_below=NULL;
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);
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();
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) {
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) {
*get_last_haggle_price(pp) = 0;
play_sample_at_channel(H_SND_OBCHOD, 1, 100);
buy_item(z);
free(picked_item);
@ -2826,22 +2900,26 @@ char shop_bag_click(int id,int xa,int ya,int xr,int yr)
mouse_set_cursor(H_MS_DEFAULT);
if (!price) return 0;
if (price > money) {
p = message(2, 0, 0, "", texty[104], texty[230], texty[78]);
if (!p) {
redraw_shop();
price = smlouvat(price, pp->cena, *get_product_count(pp), money, 1);
} else {
price = -1;
}
p = message(2, 0, 0, "", texty[104], texty[230], texty[78])+1;
} else {
sprintf(s, texty[101], price);
p = message(3, 0, 1, texty[118], s, texty[77], texty[230], texty[78]);
if (p == 1) {
redraw_shop();
price = smlouvat(price, pp->cena, *get_product_count(pp), money, 1);
} else if (p == 2) {
}
if (p == 1) {
redraw_shop();
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) {
price = -1;
}
if (price>=0)
{
@ -2869,12 +2947,23 @@ char shop_block_click(int id, int xa, int ya,int xr,int yr)
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;
void unwire_shop()
{
send_message(E_DONE,E_MOUSE,shop_mouse_event);
send_message(E_DONE,E_KEYBOARD, shop_keyboard_proc);
norefresh=0;
wire_proc=wire_shop;
inv_view_mode=old_inv_view_mode;
@ -2896,6 +2985,7 @@ void wire_shop()
last_shop=cur_shop;
}
send_message(E_ADD,E_MOUSE,shop_mouse_event);
send_message(E_ADD,E_KEYBOARD, shop_keyboard_proc);
unwire_proc=unwire_shop;
change_click_map(clk_shop,CLK_SHOP);
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;
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)
{
poc_spec++;if (*get_product_count(pr)>0) *get_product_count(pr)=0;
poc_spec++;
*count = 0;
}
}
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++;
j--;
const TPRODUCT *sel = pr+j;
int maxp = MAX(sel->max_pocet,1);
*get_product_count(pr+j)=rnd(maxp)+1;
int maxp = sel->max_pocet;
if (maxp) {
*get_product_count(pr+j)=rnd(maxp)+1;
} else {
*get_product_count(pr+j) = 0;
}
}
}

View file

@ -498,6 +498,7 @@ static void seek_section(TMPFILE_RD *txt,int sect_number)
do
{
while (c!='[' && c!=EOF) c=temp_storage_getc(txt);
if (c == EOF) break;
if (c=='[')
{
i=-2;

View file

@ -12,6 +12,7 @@
#include <stdarg.h>
#include "engine1.h"
#include "globals.h"
#include "lang.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) {
TSTRINGTABLE *strtable = lang_load("spells.csv");
void *np = getmem(*s);
memcpy(np,p,*s);
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;
memmove(b+bofs+1, b+bofs, eofs-bofs);\
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;
}
stringtable_free(strtable);
return np;
}

49
game/lang.c Normal file
View 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
View 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);

View file

@ -18,6 +18,7 @@
#include <libs/pcx.h>
#include "globals.h"
#include "lang.h"
#define MUSIC "TRACK06.MUS"
@ -366,7 +367,13 @@ int enter_menu(char open)
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;
@ -377,7 +384,10 @@ char *get_next_title(signed char control,char *filename)
switch(control)
{
case 1:
path = build_pathname(2, gpathtable[SR_MAP],filename);
path = end_titles_path(filename);
if (path == NULL) {
path = build_pathname(2, gpathtable[SR_MAP],filename);
}
path = local_strdup(path);
titles=enc_open(path);
if (titles==NULL)
@ -395,8 +405,12 @@ char *get_next_title(signed char control,char *filename)
}
}
return (char *)titles;
case 0:if (titles!=NULL)temp_storage_gets(buffer,80,titles);
c=strchr(buffer,'\n');if (c!=NULL) *c=0;
case 0:if (titles!=NULL && temp_storage_gets(buffer,80,titles)) {
c=strchr(buffer,'\n');if (c!=NULL) *c=0;
c=strchr(buffer,'\r');if (c!=NULL) *c=0;
} else {
strcpy(buffer, "*KONEC");
}
return buffer;
case -1:if (titles!=NULL)enc_close(titles);
break;
@ -517,7 +531,7 @@ void titles(va_list args)
{
int32_t scr_linelen2 = GetScreenPitch();
char send_back=va_arg(args,int);
char *textname=va_arg(args,char *);
const char *textname=va_arg(args,const char *);
const void *picture;
word *scr,*buff;

View file

@ -18,6 +18,7 @@
#include "globals.h"
#include <libs/inicfg.h>
#include "lang.h"
#include <ctype.h>
#include <string.h>
@ -197,7 +198,7 @@ int load_map(char *filename)
char snd_load=0;
void *mob_template;
int32_t mob_size;
int suc = 0;
int failed = 0;
map_with_password=0;
const char *mpath = build_pathname(2, gpathtable[SR_MAP], filename);
@ -344,8 +345,11 @@ int load_map(char *filename)
memset(minimap,0,sizeof(minimap));
end_ptr=ofsts;
const char *tpath=set_file_extension(mpath,".txt");
suc=load_level_texts(tpath);
if (!suc && level_texts!=NULL) create_playlist(level_texts[0]);
failed=load_level_texts(tpath);
if (!failed && level_texts!=NULL) {
lang_patch_stringtable(&level_texts, filename, "map_");
create_playlist(level_texts[0]);
}
init_tracks();
change_music(get_next_music_from_playlist());
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);
const char * hash_str = map_hash_to_string(current_map_hash);
temp_storage_store(hash_str, filename, strlen(filename));
return suc;
return failed;
}
void add_leaving_place(int sector)
@ -1272,11 +1276,11 @@ void group_all(void)
{
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;
}
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);
@ -1570,7 +1574,7 @@ void step_zoom(char smer)
int i;
THUMAN *h;
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)
{
bott_disp_text(texty[66]);

View file

@ -14,12 +14,13 @@
#include <libs/basicobj.h>
#include <libs/mgfplay.h>
#include <libs/inicfg.h>
#include <platform/getopt.h>
#include <platform/save_folder.h>
#include "globals.h"
#include "default_font.h"
//
#include "advconfig.h"
#include "skeldal.h"
#include "lang.h"
#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_8bit_decomp(const void *p, int32_t *s);
char *texty_knihy;
const char *texty_knihy;
static char *patch_file=NULL;
int cur_page=0;
@ -793,9 +794,13 @@ void cti_texty(void)
display_error(buff);
exit(1);
}
lang_patch_stringtable(&texty, "ui.csv", "");
}
void global_kbd(EVENT_MSG *msg,void **usr)
{
char c;
@ -947,7 +952,16 @@ void init_skeldal(const INI_CONFIG *cfg)
init_DDL_manager();
texty_knihy=strdup(build_pathname(2,gpathtable[SR_MAP],"kniha.txt"));
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"));
} else {
texty_knihy=strdup(texty_knihy);
}
} else {
texty_knihy=strdup(build_pathname(2,gpathtable[SR_MAP],"kniha.txt"));
}
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_SAVES] = ini_get_string(paths, "savegame", get_default_savegame_directory());
gpathtable[SR_DATA]= ini_get_string(paths, "data", "./");
gpathtable[SR_LANG]= ini_get_string(paths, "lang", "./lang");
return groot;
}
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>] [-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");
static void (*display_error_cb)(const char *);
void display_error(const char *format, ...) {
va_list lst;va_start(lst, format);
if (display_error_cb) {
char buff[1024];
vsnprintf(buff,sizeof(buff), format, lst);
} else {
fprintf(stderr, format, lst);
}
}
void quit_cb_exit_wait(void *_) {
@ -1609,55 +1613,63 @@ void quit_cb_exit_wait(void *_) {
}
int skeldal_gen_string_table_entry_point(const SKELDAL_CONFIG *start_cfg, const char *save_path) {
def_mman_group_table(gpathtable);
int main(int argc,char *argv[])
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;
}
init_DDL_manager();
generate_string_tables(save_path);
printf("Done\n");
return 0;
}
int skeldal_entry_point(const SKELDAL_CONFIG *start_cfg)
{
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);
display_error_cb = start_cfg->show_error;
INI_CONFIG *cfg = ini_open(start_cfg->config_path);
if (cfg == NULL) {
fprintf(stderr, "Failed to open configuration file: %s\n", CONFIG_NAME);
show_help_short();
start_cfg->show_error(concat2("Failed to open configuration file: ", start_cfg->config_path));
start_cfg->short_help();
return 1;
}
if (adv_config_file) {
TSTR_LIST adv_config=read_config(adv_config_file);
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)) {
fprintf(stderr, "Can't change directory to %s", groot);
start_cfg->show_error(concat2("Can't change directory to: ", groot));
return 1;
}
if (gen_stringtable_path) {
init_DDL_manager();
generate_string_tables(gen_stringtable_path);
printf("Done\n");
return 0;
if (start_cfg->lang_path) {
lang_set_folder(build_pathname(2, gpathtable[SR_LANG], start_cfg->lang_path));
}
start_check();
purge_temps(1);
clrscr();

25
game/skeldal.h Normal file
View 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

View file

@ -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)
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)
@ -527,22 +534,38 @@ int vyber_prvniho(int att)
return i;
}
*/
static int vyber_hrace(int att)
{
int gr,i;
THUMAN *h;
static int vyber_hrace(int att) {
int gr;
THUMAN *h;
if (att>POCET_POSTAV || att<0)
gr=cur_group,att=0xff;
else
gr=postavy[att].groupnum;
h=postavy;
for(i=0,h=postavy;i<POCET_POSTAV && (!h->used || !h->lives || !h->actions || h->groupnum!=gr) ;i++,h++);
if (i==6)
if (att!=0xff) return att;else return group_sort[0];
else
return i;
}
if (att > POCET_POSTAV || att < 0)
gr = cur_group, att = 0xff;
else
gr = postavy[att].groupnum;
h = postavy;
int candidate0 = -1;
int candidate1 = -1;
int candidate2 = -1;
for (int i = POCET_POSTAV; i>0;) {
--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()
{

View file

@ -19,7 +19,19 @@ typedef struct _temp_storage_file_rd {
int skp = 0;
} 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;