diff --git a/Makefile.mingw32ce b/Makefile.mingw32ce index f42ad82..95e5d61 100644 --- a/Makefile.mingw32ce +++ b/Makefile.mingw32ce @@ -1,4 +1,4 @@ -VERSION := 1.2.3 +VERSION := 1.3.0 PREFIX=./ DESTDIR= diff --git a/PKGBUILD.in b/PKGBUILD.in index 9c36619..777e6ec 100644 --- a/PKGBUILD.in +++ b/PKGBUILD.in @@ -1,6 +1,6 @@ # Contributor: Peter Kosyh pkgname=instead -pkgver=1.2.3 +pkgver=1.3.0 pkgrel=1 pkgdesc="instead quest interpreter" arch=('i686' 'x86_64') diff --git a/Rules.make.macosx b/Rules.make.macosx index fba3987..422f16c 100644 --- a/Rules.make.macosx +++ b/Rules.make.macosx @@ -1,4 +1,4 @@ -VERSION := 1.2.3 +VERSION := 1.3.0 DESTDIR= BIN= diff --git a/Rules.make.standalone b/Rules.make.standalone index c152cb7..0b22e68 100644 --- a/Rules.make.standalone +++ b/Rules.make.standalone @@ -1,4 +1,4 @@ -VERSION := 1.2.3 +VERSION := 1.3.0 DESTDIR= BIN= diff --git a/Rules.make.system b/Rules.make.system index e8086b9..0f0eb8e 100644 --- a/Rules.make.system +++ b/Rules.make.system @@ -1,4 +1,4 @@ -VERSION := 1.2.3 +VERSION := 1.3.0 PREFIX=/usr/local DESTDIR= diff --git a/Rules.mingw b/Rules.mingw index dd9c218..f42ca19 100644 --- a/Rules.mingw +++ b/Rules.mingw @@ -1,4 +1,4 @@ -VERSION := 1.2.3 +VERSION := 1.3.0 PREFIX=./ DESTDIR= diff --git a/Rules.windows b/Rules.windows index aa9c2d7..6683794 100644 --- a/Rules.windows +++ b/Rules.windows @@ -1,4 +1,4 @@ -VERSION := 1.2.3 +VERSION := 1.3.0 PREFIX= DESTDIR= diff --git a/debian/changelog b/debian/changelog index 7e41838..2c4fad0 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,22 @@ +instead (1.3.0) unstable; urgency=low + + * bug fix (resample sounds while HZ change); + * bug fix (empty bg); + * bug fix (cursor center scaling); + * changing themes from game; + * strike ougth text; + * *.fnt.height theme parameter; + * scroller positions in theme; + * escaping ^ and delim; + * box: and blank:; + * pad: ; + * speed up; + * picture flow; + * prefs:purge now removes vars; + * dialog:empty added; + + -- Peter Kosyh Tue, 12 Oct 2010 22:42:00 +0300 + instead (1.2.3) unstable; urgency=low * android build; diff --git a/desktop/instead.desktop.in b/desktop/instead.desktop.in index 641523f..a9a6ebb 100644 --- a/desktop/instead.desktop.in +++ b/desktop/instead.desktop.in @@ -1,6 +1,6 @@ [Desktop Entry] Encoding=UTF-8 -Version=1.2.3 +Version=1.3.0 Type=Application Name=INSTEAD Name[ru]=INSTEAD diff --git a/doc/index.html b/doc/index.html index 5402681..ebc1991 100644 --- a/doc/index.html +++ b/doc/index.html @@ -13,7 +13,7 @@ body { font-family: Verdana, Arial, Helvetica, sans-serif; INSTEAD -- interpreter of simple text adventures for Unix and Windows -

INSTEAD 1.2.3

+

INSTEAD 1.3.0

INSTEAD -- interpreter of simple text adventures for Unix and Windows.
INSTEAD was designed to interpret the games that are the mix of visual novels, text quests and classical 90'ss quests.

diff --git a/doc/instead.6 b/doc/instead.6 index 028ebf2..908fb73 100644 --- a/doc/instead.6 +++ b/doc/instead.6 @@ -1,4 +1,4 @@ -.TH INSTEAD 6 "Version 1.2.3" Instead GAMES +.TH INSTEAD 6 "Version 1.3.0" Instead GAMES .SH NAME diff --git a/doc/writing_games-en.txt b/doc/writing_games-en.txt index fb84b84..3b94b65 100644 --- a/doc/writing_games-en.txt +++ b/doc/writing_games-en.txt @@ -1,6 +1,6 @@ ===== 0. General information ===== -Game code for STEAD is written in lua (5.1), therefore it is useful to know the language, though not necessary. The engine code in lua is about ~2000 lines long. And it is the best documentation. +Game code for STEAD is written in lua (5.1), therefore it is useful to know the language, though not necessary. The engine code in lua is about ~3000 lines long. And it is the best documentation. The main game window contains information about static and dynamic parts of the scene, active events and the scene picture with possible passages to other scenes (in the graphic interpreter). @@ -30,9 +30,9 @@ At the beginning of “main.lua” file a header may be defined. It consists of -- $Name: The most interesting game!$ -From version 1.2.0 after headers you must define required STEAD API version. It is "1.2.2" currently. +From version 1.2.0 after headers you must define required STEAD API version. It is "1.3.0" currently. -instead_version "1.2.2" +instead_version "1.3.0" Game initialization should be defined as init function. For example: @@ -854,7 +854,6 @@ Or: p 'Guard entered the room.' return true -- The event will be printed before objects description. - ===== 17. Graphics and music ===== Graphic interpreter analyzes the scene “pic” attribute and treats it as a path to the picture. For example: @@ -880,6 +879,21 @@ knife = obj { } +From version 1.3.0 text flow is supported. Using functions imgl/imgr, picture can be inserted at left/right. border. Those pictures can not be links. + +For padding, you can use 'pad:'. For example: + +imgl 'pad:16,picture.png' -- padding 16px; +imgl 'pad:0 16 16 4,picture.png' -- padding: top 0, right 16, bottom 16, left 4 +imgl 'pad:0 16,picture.png' -- padding: top 0, right 16, bottom 0, left 16 + + +You can use pseudo-images for blank areas and boxes: + +dsc = img 'blank:32x32'..[[Line with blank image.]]; +dsc = img 'box:32x32,red,128'..[[Line with red semi-transparent square.]]; + + In current version you can use disp attribute: knife = obj { @@ -921,7 +935,6 @@ To stop music use stop_music() function (from version 1.0.0). Use is_music() to check if music is playing. (from version 1.0.0) ===== 18. Advices ===== - ==== Modules ==== Starting from version 1.2.0 you can use modules via “require” function call. At the moment the following modules are available: @@ -935,6 +948,7 @@ Starting from version 1.2.0 you can use modules via “require” function call. * snapshots — snapshots; * format — formats the output; * object — improved objects; + * theme — theme manipulations; Modules can be used like this: @@ -1031,13 +1045,15 @@ format.quotes = false -- changes quotes on << >>; format.filter = nil -- user formatting function; You may use modules para/dash/quotes to enable specific feature. - ==== Formatting ==== You can do simple text formatting with functions: -txtc() - center align; -txtr() - right align; -txtl() - left align; + * txtc() - center align; + * txtr() - right align; + * txtl() - left align; + * txttop() - top of line; + * txtbottom() - bottom of line; + * txtmiddle() - middle (by default); For example: @@ -1049,10 +1065,10 @@ main = room { You can define text style with functions: -txtb() - bold; -txtem() - emboss; -txtu() - underline; - + * txtb() - bold; + * txtem() - emboss; + * txtu() - underline; + * txtst() - strikesthrougth; For example: main = room { @@ -1432,7 +1448,6 @@ The object created will be saved every time the game is saved. ''new()'' returns o_name = deref(new('myconstructor()')); delete(o_name); - ==== Complex output from event handlers ==== Sometimes the we need to form event handler output from several parts depending on some conditions. In this case ''p()'' and ''pn()'' functions can be useful. These functions add text to the internal buffer of the handler. The content of this buffer is returned from the handler. @@ -1450,7 +1465,7 @@ There is a function ''pr()'' in versions 1.1.6 and later, that does not add anyt To clear the buffer you can use ''pclr()''. To return the status of the action along with the text, use ''pget()'' or just return. use = function(s, w) - if w == 'apple' then + if w == apple then p 'I peeled the apple'; apple._peeled = true return @@ -1478,7 +1493,6 @@ For ingame simple debugger insert this: require "dbg" just after version line in main.lua. Then use F7 to call debugger. - ===== 19. Themes for sdl-instead ===== Graphic interpreter supports theme mechanism. A theme is a directory with the “theme.ini” file inside. @@ -1531,8 +1545,12 @@ win.fnt.name = path to the font file (string) win.fnt.size = font size for the main window (number) +win.fnt.height = line height as float number (1.0 by default) + win.gfx.up, win.gfx.down = paths to the pictures of up/down scrollers for the main window (string) +win.up.x, win.up.y, win.down.x, win.down.y = coordinates of scrollers (position or -1) + win.col.fg = font color for the main window (color) win.col.link = link color for the main window (color) @@ -1553,8 +1571,12 @@ inv.fnt.name = path to the inventory font file (string) inv.fnt.size = inventory font size (number) +inv.fnt.height = line height as float number (1.0 by default) + inv.gfx.up, inv.gfx.down = paths to the pictures of inventory up/down scrollers (string) +inv.up.x, inv.up.y, inv.down.x, inv.down.y = coordinates of scrollers (position or -1) + menu.col.bg = menu background (color) menu.col.fg = menu text color (color) @@ -1573,6 +1595,8 @@ menu.fnt.name = paths to menu font file (string) menu.fnt.size = menu font size (number) +menu.fnt.height = line height as float number (1.0 by default) + menu.gfx.button = path to the menu icon (string) menu.button.x, menu.button.y = menu button coordinates (number) @@ -1594,4 +1618,4 @@ The interpreter searches for themes in the “themes” directory. Unix version TODO Full list of objects and methods. -Translation: vopros@pochta.ru +Translation: vopros@pochta.ru \ No newline at end of file diff --git a/doc/writing_games.txt b/doc/writing_games.txt index 995f187..afa7443 100644 --- a/doc/writing_games.txt +++ b/doc/writing_games.txt @@ -1,6 +1,6 @@ -===== 0. Общие сведения ===== - -Код игр для STEAD пишется на lua (5.1), поэтому, знание этого языка полезно, хотя и не необходимо. Код движка на lua занимает около ~2000 строк и лучшей документацией является изучение его кода. +====== Базовая документация ====== +===== Общие сведения ===== +Код игр для STEAD пишется на lua (5.1), поэтому, знание этого языка полезно, хотя и не необходимо. Код движка на lua занимает около ~3000 строк и лучшей документацией является изучение его кода. Главное окно игры содержит информацию о статической и динамической части сцены, активные события и картинку сцены с возможными переходами в другие сцены (в графическом интерпретаторе). @@ -30,12 +30,12 @@ -- $Name: Самая интересная игра!$ -Начиная с версии 1.2.0 сразу после заголовков вам необходимо указать версию STEAD API, которая требуется игре. На данный момент последняя версия 1.2.2. +Сразу после заголовков вам необходимо указать версию STEAD API, которая требуется игре. На данный момент последняя версия 1.3.0. -instead_version "1.2.2" +instead_version "1.3.0" -Если version отсутствует, то STEAD API будет работать в режиме совместимости (устаревшее API). +Если version отсутствует, то STEAD API будет работать в режиме совместимости (устаревшее API). Инициализацию игры следует описывать в функции init: @@ -47,9 +47,8 @@ end Графический интерпретатор ищет доступные игры в каталоге games. Unix версия интерпретатора кроме этого каталога просматривает также игры в каталоге ~/.instead/games. -Windows версия (>=0.8.7): Documents and Settings/USER/Local Settings/Application Data/instead/games. - -Начиная с версии 1.2.0, для Windows версии и standalone Unix версии игры ищутся в каталоге ./appdata/games, если он существует. +Windows версия: Documents and Settings/USER/Local Settings/Application Data/instead/games. +В Windows и standalone Unix версии игры ищутся в каталоге ./appdata/games, если он существует. ===== 1. Сцена ===== @@ -853,7 +852,6 @@ return 'В комнату вошел охранник.', true При этом текст события будет выведен до описания объектов. - ===== 17. Графика и музыка ===== Графический интерпретатор анализирует атрибут сцены pic, и воспринимает его как путь к картинке, например: @@ -878,6 +876,21 @@ knife = obj { } +А начиная с 1.3.0 поддерживается обтекание картинок текстом. Если картинка вставляется с помощью функции imgl/imgr, она будет расположена у левого/правого края. Такие картинки не могут быть ссылками. + +Для задания отступов вокруг изображения используйте pad, например: + +imgl 'pad:16,picture.png' -- отступы по 16 от каждого края +imgl 'pad:0 16 16 4,picture.png' -- отступы: вверху 0, справа 16, внизу 16, слева 4 +imgl 'pad:0 16,picture.png' -- отступы: вверху 0, справа 16, внизу 0, слева 16 + + +Вы можете использовать псевдо-файлы для изображений прямоугольников и пустых областей: + +dsc = img 'blank:32x32'..[[Строка с пустым изображением.]]; +dsc = img 'box:32x32,red,128'..[[Строка красным полупрозрачным квадратом.]]; + + В современной версии INSTEAD вы можете использовать атрибут disp: knife = obj { @@ -932,6 +945,7 @@ is_music() позволяет узнать, проигрывается ли му * snapshots — модуль поддержки снапшотов; * format — модуль оформления вывода; * object — модуль улучшенных объектов; + * theme — управление темой; Использование модуля выглядит так: @@ -972,6 +986,8 @@ require "dbg" При этом, объект может быть объектом или именем объекта. +**Примечание**: начиная с версии 1.2.2 используется следующий формат ссылок: {объект|строка}. + В этом модуле определены также такие объекты как xact и xdsc. xact -- объект - простейшая реакция. Например: @@ -1027,13 +1043,15 @@ format.filter = nil -- пользовательская функция заме Вы можете пользоваться модулями para, dash, quotes для включения отдельных настроек. - ==== Форматирование ==== Вы можете делать простое форматирование текста с помощью функций: * txtc() - разместить по центру; * txtr() - разместить справа; * txtl() - разместить слева; + * txttop() - сверху строки; + * txtbottom() - снизу строки; + * txtmiddle() - середина строки (по умолчанию); Например: @@ -1048,6 +1066,7 @@ main = room { * txtb() - жирный; * txtem() - курсив; * txtu() - подчеркнутый; + * txtst() - перечеркнутый; Например: @@ -1437,7 +1456,7 @@ end Для очистки буфера, используйте pclr(). Если вам нужно вернуть статус действия, используйте pget(), или просто используйте return. use = function(s, w) - if w == 'apple' then + if w == apple then p 'Гм... Я почистил яблоко.'; apple._peeled = true return @@ -1465,7 +1484,6 @@ iface:shell(); require "dbg" Отладчик вызывается по F7. - ===== 19. Темы для sdl-instead ===== Графический интерпретатор поддерживает механизм тем. Тема представляет из себя каталог, с файлом theme.ini внутри. @@ -1518,8 +1536,12 @@ win.fnt.name = путь к файлу-шрифту (строка) win.fnt.size = размер шрифта главного окна (размер) +win.fnt.height = междустрочный интервал как число с плавающей запятой (1.0 по умолчанию) + win.gfx.up, win.gfx.down = пути к файлам-изображениям скорллеров вверх/вниз для главного окна (строка) +win.up.x, win.up.y, win.down.x, win.down.y = координаты скроллеров (координата или -1) + win.col.fg = цвет текста главного окна (цвет) win.col.link = цвет ссылок главного окна (цвет) @@ -1540,8 +1562,12 @@ inv.fnt.name = путь к файлу-шрифту инвентаря (стро inv.fnt.size = размер шрифта инвентаря (размер) +inv.fnt.height = междустрочный интервал как число с плавающей запятой (1.0 по умолчанию) + inv.gfx.up, inv.gfx.down = пути к файлам-изображениям скорллеров вверх/вниз для инвентаря (строка) +inv.up.x, inv.up.y, inv.down.x, inv.down.y = координаты скроллеров (координата или -1) + menu.col.bg = фон меню (цвет) menu.col.fg = цвет текста меню (цвет) @@ -1560,6 +1586,8 @@ menu.fnt.name = путь к файлу-шрифту меню (строка) menu.fnt.size = размер шрифта меню (размер) +menu.fnt.height = междустрочный интервал как число с плавающей запятой (1.0 по умолчанию) + menu.gfx.button = путь к файлу изображению значка меню (строка) menu.button.x, menu.button.y = координаты кнопки меню (числа) diff --git a/instead.spec b/instead.spec index 34a7d58..8cc5958 100644 --- a/instead.spec +++ b/instead.spec @@ -1,6 +1,6 @@ Summary: simply text adventures/visual novels engine and game Name: instead -Version: 1.2.3 +Version: 1.3.0 Release: 1%{?dist} License: GPLv2 URL: http://instead.googlecode.com diff --git a/readme.txt b/readme.txt index f69deaf..fd2e463 100644 --- a/readme.txt +++ b/readme.txt @@ -1,4 +1,4 @@ -INSTEAD 1.2.3 +INSTEAD 1.3.0 ============= WARNING! For successfull building you must install these development packages (names may vary in your distribution): diff --git a/src/sdl-instead/cache.c b/src/sdl-instead/cache.c index 4fb6e87..48a4af5 100644 --- a/src/sdl-instead/cache.c +++ b/src/sdl-instead/cache.c @@ -192,6 +192,7 @@ static void __cache_shrink(__cache_t *c) } else break; } +// fprintf(stderr,"%d/%d\n", c->size, c->used); } int cache_add(cache_t cache, const char *name, void *p) diff --git a/src/sdl-instead/game.c b/src/sdl-instead/game.c index cae667e..7884fb3 100644 --- a/src/sdl-instead/game.c +++ b/src/sdl-instead/game.c @@ -10,6 +10,7 @@ char game_cwd[PATH_MAX]; char *curgame_dir = NULL; int game_own_theme = 0; +int game_theme_changed = 0; static int game_pic_w = 0; static int game_pic_h = 0; @@ -78,14 +79,34 @@ static struct game *game_lookup(const char *name) return NULL; } +int game_reset(void) +{ + game_release_theme(); + free_last(); + if (game_select(curgame_dir)) + goto out; + if (game_apply_theme()) + goto out; + return 0; +out: + game_done(0); + if (game_init(NULL)) { + game_error(""); + return -1; + } + return -1; +} + int game_select(const char *name) { struct game *g; FREE(last_cmd); game_stop_mus(500); g = game_lookup(name); - if ((!name || !*name) && !g) - return 0; + if ((!name || !*name) && !g) { + game_use_theme(); + return game_theme_init(); + } if (setdir(game_cwd)) return -1; if (g) { @@ -100,12 +121,24 @@ int game_select(const char *name) curgame_dir = oldgame; return -1; } + + game_use_theme(); + if (instead_load(dirpath(MAIN_FILE))) { curgame_dir = oldgame; return -1; } + instead_function("game:ini", NULL); instead_clear(); + + if (game_theme_init()) { + curgame_dir = oldgame; + return -1; + } return 0; + } else { + game_use_theme(); + game_theme_init(); } return 0; } @@ -462,29 +495,13 @@ static int inv_enabled(void) return (game_theme.inv_mode != INV_MODE_DISABLED); } + int game_apply_theme(void) { layout_t lay; textbox_t box; - int w = opt_mode[0]; - int h = opt_mode[1]; - if ((w == -1) - && (gfx_get_max_mode(&w, &h) || (game_theme.w <= w && game_theme.h <= h))) { - w = opt_mode[0]; - h = opt_mode[1]; - } - if (game_theme_init(w, h)) - return -1; - memset(objs, 0, sizeof(struct el) * el_max); - - if (gfx_set_mode(game_theme.w, game_theme.h, opt_fs)) { - opt_mode[0] = opt_mode[1] = -1; opt_fs = 0; /* safe options */ - return -1; - } - if (game_theme_optimize()) - return -1; gfx_bg(game_theme.bgcol); game_clear(0, 0, game_theme.w, game_theme.h); gfx_flip(); @@ -498,11 +515,11 @@ int game_apply_theme(void) txt_layout_link_color(lay, game_theme.lcol); // txt_layout_link_style(lay, 4); txt_layout_active_color(lay, game_theme.acol); - + txt_layout_font_height(lay, game_theme.font_height); + txt_box_set(box, lay); el_set(el_scene, elt_box, game_theme.win_x, 0, box); - if (inv_enabled()) { lay = txt_layout(game_theme.inv_font, INV_ALIGN(game_theme.inv_mode), game_theme.inv_w, game_theme.inv_h); @@ -511,6 +528,7 @@ int game_apply_theme(void) txt_layout_color(lay, game_theme.icol); txt_layout_link_color(lay, game_theme.ilcol); txt_layout_active_color(lay, game_theme.iacol); + txt_layout_font_height(lay, game_theme.inv_font_height); box = txt_box(game_theme.inv_w, game_theme.inv_h); if (!box) @@ -527,7 +545,8 @@ int game_apply_theme(void) txt_layout_color(lay, game_theme.fgcol); txt_layout_link_color(lay, game_theme.lcol); txt_layout_active_color(lay, game_theme.acol); - + txt_layout_font_height(lay, game_theme.font_height); + el_set(el_title, elt_layout, game_theme.win_x, game_theme.win_y, lay); lay = txt_layout(game_theme.font, ALIGN_CENTER, game_theme.win_w, 0); @@ -537,7 +556,8 @@ int game_apply_theme(void) txt_layout_color(lay, game_theme.fgcol); txt_layout_link_color(lay, game_theme.lcol); txt_layout_active_color(lay, game_theme.acol); - + txt_layout_font_height(lay, game_theme.font_height); + el_set(el_ways, elt_layout, game_theme.win_x, 0, lay); el_set(el_sdown, elt_image, 0, 0, game_theme.a_down); @@ -604,6 +624,8 @@ int game_change_vol(int d, int val) return 0; } +static void sounds_reload(void); + int game_change_hz(int hz) { if (!hz) @@ -614,6 +636,7 @@ int game_change_hz(int hz) snd_volume_mus(cur_vol); snd_free_wav(game_theme.click); game_theme.click = snd_load_wav(game_theme.click_name); + sounds_reload(); game_music_player(); opt_hz = snd_hz(); return 0; @@ -684,6 +707,32 @@ int counter_fn(int interval, void *p) return interval; } +int game_use_theme(void) +{ + int rc = 0; + game_theme_changed = 0; + game_own_theme = 0; + + game_theme.changed = CHANGED_ALL; + + if (game_default_theme()) { + fprintf(stderr, "Can't load default theme.\n"); + return -1; + } + + if (curgame_dir && !access(dirpath(THEME_FILE), R_OK)) { + game_own_theme = 1; + } + if (game_own_theme && opt_owntheme) { + theme_relative = 1; + rc = theme_load(dirpath(THEME_FILE)); + theme_relative = 0; + } else if (curtheme_dir && strcmp(DEFAULT_THEME, curtheme_dir)) { + rc = game_theme_load(curtheme_dir); + } + return rc; +} + int game_init(const char *name) { getdir(game_cwd, sizeof(game_cwd)); @@ -698,43 +747,35 @@ int game_init(const char *name) snd_init(opt_hz); game_change_vol(0, opt_vol); - if (game_default_theme()) { - fprintf(stderr, "Can't load default theme.\n"); + if (game_select(name)) + return -1; + + if (gfx_set_mode(game_theme.w, game_theme.h, opt_fs)) { + opt_mode[0] = opt_mode[1] = -1; opt_fs = 0; /* safe options */ return -1; } - if (game_select(name)) + if (game_theme_optimize()) return -1; - - if (curgame_dir && !access(dirpath(THEME_FILE), R_OK)) { - game_own_theme = 1; - } - - if (game_own_theme && opt_owntheme) { - if (theme_load(dirpath(THEME_FILE))) - return -1; - } else if (curtheme_dir && strcmp(DEFAULT_THEME, curtheme_dir)) { - game_theme_load(curtheme_dir); - } if (game_apply_theme()) { game_theme_select(DEFAULT_THEME); return -1; } timer_han = gfx_add_timer(HZ, counter_fn, NULL); - if (!curgame_dir) { game_menu(menu_games); } else { if (!game_load(-1)) /* tmp save */ - return 0; + goto out; if (opt_autosave && !game_load(0)) /* autosave */ - return 0; + goto out; game_cmd("look"); custom_theme_warn(); if (opt_autosave) game_save(0); } +out: return 0; } @@ -760,10 +801,35 @@ void free_last(void) sounds_free(); } -void game_done(int err) +void game_release_theme(void) { int i; + mouse_reset(1); + game_cursor(CURSOR_OFF); + if (el_img(el_spic)) + gfx_free_image(el_img(el_spic)); + for (i = 0; i < el_max; i++) { + struct el *o; + o = el(i); + if (o->type == elt_layout && o->p.p) { + txt_layout_free(o->p.lay); + } else if (o->type == elt_box && o->p.p) { + txt_layout_free(txt_box_layout(o->p.box)); + txt_box_free(o->p.box); + } + o->p.p = NULL; + o->drawn = 0; + } + if (menu) + gfx_free_image(menu); + if (menubg) + gfx_free_image(menubg); + menu = menubg = NULL; +} + +void game_done(int err) +{ gfx_del_timer(timer_han); timer_han = NULL; @@ -774,33 +840,8 @@ void game_done(int err) if (menu_shown) menu_toggle(); - mouse_reset(1); - game_cursor(CURSOR_OFF); - if (el_img(el_spic)) - gfx_free_image(el_img(el_spic)); - - for (i = 0; i < el_max; i++) { - struct el *o; - o = el(i); -// if (o->type == elt_image && o->p.p) { -// if (!o->clone) -// gfx_free_image(o->p.img); -// } else - if (o->type == elt_layout && o->p.p) { - txt_layout_free(o->p.lay); - } else if (o->type == elt_box && o->p.p) { - txt_layout_free(txt_box_layout(o->p.box)); - txt_box_free(o->p.box); - } - o->p.p = NULL; - o->drawn = 0; - } + game_release_theme(); free_last(); - if (menu) - gfx_free_image(menu); - if (menubg) - gfx_free_image(menubg); - menu = menubg = NULL; game_theme_free(); input_clear(); snd_done(); @@ -907,29 +948,45 @@ void box_update_scrollbar(int n) int off; int w, h, hh; - el_size(n, &w, &h); - - x1 = el(n)->x + w + game_theme.pad; - y1 = el(n)->y; - - x2 = x1; - y2 = y1 + h - gfx_img_h(game_theme.a_down); - - l = txt_box_layout(el_box(n)); - txt_layout_real_size(l, NULL, &hh); - off = txt_box_off(el_box(n)); if (n == el_scene) { elup = el(el_sup); eldown = el(el_sdown); + x1 = game_theme.a_up_x; + y1 = game_theme.a_up_y; + x2 = game_theme.a_down_x; + y2 = game_theme.a_down_y; // elslide = el(el_sslide); } else if (n == el_inv) { elup = el(el_iup); eldown = el(el_idown); + x1 = game_theme.inv_a_up_x; + y1 = game_theme.inv_a_up_y; + x2 = game_theme.inv_a_down_x; + y2 = game_theme.inv_a_down_y; // elslide = el(el_islide); } if (!elup || !eldown) return; + if (x1 == -1 || y1 == -1 || x2 == -1 || y2 == -1) + el_size(n, &w, &h); + + if (x1 == -1) + x1 = el(n)->x + w + game_theme.pad; + + if (y1 == -1) + y1 = el(n)->y; + + if (x2 == -1) + x2 = x1; + + if (y2 == -1) + y2 = y1 + h - gfx_img_h(game_theme.a_down); + + l = txt_box_layout(el_box(n)); + txt_layout_real_size(l, NULL, &hh); + off = txt_box_off(el_box(n)); + if (el_clear(elup->id)) { if (elup->x != x1 || elup->y != y1) el_update(elup->id); @@ -1026,7 +1083,7 @@ int game_menu_box_wh(const char *txt, int *w, int *h) int b = game_theme.border_w; int pad = game_theme.pad; - lay = txt_layout(game_theme.menu_font, ALIGN_CENTER, game_theme.win_w - 2 * (b + pad), 0); + lay = txt_layout(game_theme.menu_font, ALIGN_CENTER, game_theme.w - 2 * (b + pad), 0); txt_layout_set(lay, (char*)txt); txt_layout_real_size(lay, w, h); txt_layout_free(lay); @@ -1084,6 +1141,8 @@ void game_menu_box_width(int show, const char *txt, int width) txt_layout_color(lay, game_theme.menu_fg); txt_layout_link_color(lay, game_theme.menu_link); txt_layout_active_color(lay, game_theme.menu_alink); + txt_layout_font_height(lay, game_theme.menu_font_height); + txt_layout_set(lay, (char*)txt); txt_layout_real_size(lay, &w, &h); if (width) @@ -1096,8 +1155,8 @@ void game_menu_box_width(int show, const char *txt, int width) gfx_img_fill(menu, 0, 0, w + (b + pad)*2, h + (b + pad)*2, game_theme.border_col); gfx_img_fill(menu, b, b, w + pad*2, h + pad*2, game_theme.menu_bg); gfx_set_alpha(menu, game_theme.menu_alpha); - x = (game_theme.win_w - w)/2 + game_theme.win_x; //(game_theme.w - w)/2; - y = (game_theme.win_h - h)/2 + game_theme.win_y; //(game_theme.h - h)/2; + x = (game_theme.w - w)/2; + y = (game_theme.h - h)/2; mx = x - b - pad; my = y - b - pad; mw = w + (b + pad) * 2; @@ -1177,24 +1236,6 @@ static int check_fading(void) return rc?st:0; } -void scene_scrollbar(void) -{ - layout_t l; - int h, off; - int hh; - el_clear(el_sdown); - el_clear(el_sup); - el_size(el_scene, NULL, &hh); - el(el_sup)->y = el(el_scene)->y; - l = txt_box_layout(el_box(el_scene)); - txt_layout_size(l, NULL, &h); - off = txt_box_off(el_box(el_scene)); - if (h - off >= hh) - el_draw(el_sdown); - if (off) - el_draw(el_sup); -} - static void game_autosave(void) { int b,r; @@ -1315,6 +1356,15 @@ static void sounds_free(void) } } +static void sounds_reload(void) +{ + int i; + for (i = 0; i < MAX_WAVS; i++) { + snd_free_wav(wavs[i].wav); + wavs[i].wav = snd_load_wav(wavs[i].fname); + } +} + void game_sound_player(void) { wav_t w; @@ -1391,15 +1441,19 @@ static void scroll_to_diff(const char *cmdstr, int cur_off) int off = 0; int pos = 0; int h = 0; + int hh = 0; pos = find_diff_pos(cmdstr, last_cmd); if (pos == -1) off = cur_off; else - off = txt_layout_pos2off(txt_box_layout(el_box(el_scene)), pos); + off = txt_layout_pos2off(txt_box_layout(el_box(el_scene)), pos, &hh); el_size(el_scene, NULL, &h); - if (cur_off <= off && (cur_off + h) > off) + if (cur_off <= off && (cur_off + h) > off + hh) { off = cur_off; - txt_box_scroll(el_box(el_scene), off); + hh = 0; + } else if (off < cur_off || off + hh <= cur_off + h) + hh = 0; + txt_box_scroll(el_box(el_scene), off + hh); } int game_highlight(int x, int y, int on); @@ -1446,6 +1500,9 @@ int game_cmd(char *cmd) fading = check_fading(); + if (game_theme_changed == 2 && opt_owntheme && !fading) + fading = 1; /* one frame at least */ + if (fading) { /* take old screen */ game_cursor(CURSOR_CLEAR); img_t offscreen = gfx_new(game_theme.w, game_theme.h); @@ -1453,14 +1510,22 @@ int game_cmd(char *cmd) gfx_draw(oldscreen, 0, 0); } + if (game_theme_changed == 2 && opt_owntheme) { + game_theme_update(); + game_theme_changed = 1; + new_place = 1; + if (pict) + new_pict = 1; + } + if (new_place) el_clear(el_title); if (title && *title) { - snprintf(buf, sizeof(buf), "%s", title); + snprintf(buf, sizeof(buf), "%s", title); txt_layout_set(el_layout(el_title), buf); txt_layout_size(el_layout(el_title), NULL, &title_h); - title_h += game_theme.font_size / 2; // todo? + title_h += game_theme.font_size * game_theme.font_height / 2; // todo? } else txt_layout_set(el_layout(el_title), NULL); @@ -1538,8 +1603,9 @@ int game_cmd(char *cmd) p = malloc(strlen(cmdstr) + ((waystr)?strlen(waystr):0) + 16); if (p) { *p = 0; - if (waystr) { - strcpy(p, waystr); + if ((waystr && *waystr) || el_img(el_spic)) { /* is this hack needed? */ + if (waystr) + strcpy(p, waystr); strcat(p, "\n"); /* small hack */ } strcat(p, cmdstr); @@ -1563,6 +1629,7 @@ int game_cmd(char *cmd) last_cmd = cmdstr; el(el_ways)->y = el(el_title)->y + title_h + pict_h; + if (waystr) free(waystr); @@ -1602,7 +1669,6 @@ inv: el_clear(el_inv); el_draw(el_inv); } -// scene_scrollbar(); if (fading) { img_t offscreen; @@ -2598,9 +2664,8 @@ int game_loop(void) game_save(9); } else if (!is_key(&ev, "f9") && curgame_dir && !menu_shown) { if (!access(game_save_path(0, 9), R_OK)) { - mouse_reset(1); - game_select(curgame_dir); - game_load(9); + if (!game_reset()) + game_load(9); } } else if (!is_key(&ev, "f5") && curgame_dir && !menu_shown) { mouse_reset(1); diff --git a/src/sdl-instead/game.h b/src/sdl-instead/game.h index 3c67f23..74414ab 100644 --- a/src/sdl-instead/game.h +++ b/src/sdl-instead/game.h @@ -9,6 +9,7 @@ #define HZ 100 extern int game_running; +extern int game_theme_changed; extern int nosound_sw; extern int alsa_sw; @@ -29,10 +30,15 @@ extern char *game_tmp_path(void); extern int game_theme_select(const char *name); extern int game_init(const char *game); + extern int game_loop(void); extern void game_done(int err); extern int game_load_theme(const char *path); +extern int game_apply_theme(void); +extern int game_use_theme(void); +extern void game_release_theme(void); +extern int game_reset(void); extern void game_music_player(void); extern void game_stop_mus(int ms); diff --git a/src/sdl-instead/graphics.c b/src/sdl-instead/graphics.c index 1a0bf33..a7b04a3 100644 --- a/src/sdl-instead/graphics.c +++ b/src/sdl-instead/graphics.c @@ -582,7 +582,11 @@ img_t gfx_alpha_img(img_t src, int alpha) Uint32 col; int size; - SDL_Surface *img = SDL_DisplayFormatAlpha((SDL_Surface*)src); + SDL_Surface *img; + if (screen) + img = SDL_DisplayFormatAlpha((SDL_Surface*)src); + else + img = gfx_new(Surf(src)->w, Surf(src)->h); if (!img) return NULL; ptr = (Uint32*)img->pixels; @@ -613,30 +617,123 @@ img_t gfx_combine(img_t src, img_t dst) return new; } -/* blank:WxH */ -static img_t _gfx_load_special_image(char *filename) +static img_t img_pad(char *fname) { + int l,r,t,b, rc; img_t img, img2; - int wh[2] = { 0, 0 }; - if (strncmp(filename, "blank:", 6)) + SDL_Rect to; + char *p = fname; + p += strcspn(p, ","); + if (*p != ',') return NULL; - filename += 6; - if (parse_mode(filename, wh)) + p ++; + rc = sscanf(fname, "%d %d %d %d,", &t, &r, &b, &l); + if (rc == 1) { + r = b = l = t; + } else if (rc == 2) { + b = t; l = r; + } else if (rc == 3) { + l = r; + } else if (rc == 4) { + ; + } else return NULL; - if (wh[0] <= 0 || wh[1] <= 0) - return NULL; - img = gfx_new(wh[0], wh[1]); + img = gfx_load_image(p); if (!img) return NULL; - img2 = gfx_alpha_img(img, 0); + img2 = gfx_new(gfx_img_w(img) + l + r, gfx_img_h(img) + t + b); + if (!img2) { + gfx_free_image(img); + return NULL; + } else { + img_t img = gfx_alpha_img(img2, 0); + if (img) { + gfx_free_image(img2); + img2 = img; + } + } + to.x = l; + to.y = t; + SDL_gfxBlitRGBA(img, NULL, img2, &to); gfx_free_image(img); return img2; } +/* blank:WxH */ +static img_t _gfx_load_special_image(char *f) +{ + int alpha = 0; + int blank = 0; + char *filename; + img_t img, img2; + char *pc = NULL, *pt = NULL; + int wh[2] = { 0, 0 }; + if (!f) + return NULL; + + + if (!(f = filename = strdup(f))) + return NULL; + + if (!strncmp(filename, "blank:", 6)) { + filename += 6; + blank = 1; + } else if (!strncmp(filename, "box:", 4)) { + filename += 4; + alpha = 255; + } else if (!strncmp(filename, "pad:", 4)) { + filename += 4; + img2 = img_pad(filename); + goto out; + } else + goto err; + + if (strchr(filename, ';')) + goto err; /* combined */ + + if (blank) + goto skip; + pc = filename + strcspn(filename, ","); + if (*pc == ',') { + *pc = 0; + pc ++; + pt = pc + strcspn(pc, ","); + if (*pt == ',') { + *pt = 0; + pt ++; + } else + pt = NULL; + } else + pc = NULL; +skip: + if (parse_mode(filename, wh)) + goto err; + if (wh[0] <= 0 || wh[1] <= 0) + goto err; + img = gfx_new(wh[0], wh[1]); + if (!img) + goto err; + if (pc) { + color_t col = { .r = 255, .g = 255, .b = 255 }; + gfx_parse_color(pc, &col); + gfx_img_fill(img, 0, 0, wh[0], wh[1], col); + } + if (pt) + alpha = atoi(pt); + img2 = gfx_alpha_img(img, alpha); + gfx_free_image(img); +out: + free(f); + return img2; +err: + free(f); + return NULL; +} static img_t _gfx_load_image(char *filename) { SDL_Surface *img; int nr = 0; + filename = strip(filename); img = _gfx_load_special_image(filename); if (img) return img; @@ -1198,6 +1295,7 @@ struct word { int w; int unbrake; int valign; + int img_align; char *word; img_t img; struct word *next; /* in line */ @@ -1231,6 +1329,7 @@ struct word *word_new(const char *str) w->xref = NULL; w->style = 0; w->img = NULL; + w->img_align = 0; w->unbrake = 0; w->prerend = NULL; w->hlprerend = NULL; @@ -1238,6 +1337,7 @@ struct word *word_new(const char *str) } struct line { + int x; int y; int h; int w; @@ -1250,6 +1350,7 @@ struct line { struct layout *layout; }; +static int vertical_align(struct word *w, int *hh); int word_geom(word_t v, int *x, int *y, int *w, int *h) { @@ -1261,14 +1362,10 @@ int word_geom(word_t v, int *x, int *y, int *w, int *h) return -1; img = word->img; line = word->line; - xx = word->x; - yy = line->y; + xx = word->x + line->x; ww = word->w; - hh = line->h; - if (img) { /* todo */ - hh = gfx_img_h(img); - yy += (line->h - hh) / 2; - } + yy = line->y; + yy += vertical_align(v, &hh); if (x) *x = xx; if (y) @@ -1289,6 +1386,7 @@ struct line *line_new(void) l->words = NULL; l->next = NULL; l->prev = NULL; + l->x = 0; l->w = 0; l->y = 0; l->h = 0; @@ -1310,7 +1408,7 @@ void line_justify(struct line *line, int width) w = line->words; while (w) { lw += w->w; - if (!w->unbrake) + if (!w->unbrake && !w->img_align) lnum ++; w = w->next; } @@ -1320,14 +1418,15 @@ void line_justify(struct line *line, int width) sp = (width - lw) / (lnum - 1); spm = (width - lw) % (lnum - 1); while (w) { - w->x = x; - if (w->next && w->next->unbrake) - x += w->w; - else { - x += w->w + sp + ((spm)?1:0); - - if (spm) - spm --; + if (!w->img_align) { + w->x = x; + if (w->next && w->next->unbrake) + x += w->w; + else { + x += w->w + sp + ((spm)?1:0); + if (spm) + spm --; + } } w = w->next; } @@ -1342,7 +1441,9 @@ void line_right(struct line *line, int width) sp = width - line->w; w = line->words; while (w) { - w->x += sp; + if (!w->img_align) { + w->x += sp; + } w = w->next; } } @@ -1355,7 +1456,9 @@ void line_center(struct line *line, int width) sp = (width - line->w)/2; w = line->words; while (w) { - w->x += sp; + if (!w->img_align) { + w->x += sp; + } w = w->next; } } @@ -1440,9 +1543,36 @@ void image_free(struct image *image) struct textbox; #define ALIGN_NEST 16 +struct margin; + +struct margin { + struct margin *next; + int w; + int h; + int y; + int align; + struct word *word; +}; + +struct margin *margin_new(void) +{ + struct margin *m = malloc(sizeof(struct margin)); + if (!m) + return NULL; + m->w = m->h = m->align = 0; + m->next = NULL; + return m; +} + +void margin_free(struct margin *m) +{ + if (m) + free(m); +} struct layout { fnt_t fn; + float fn_height; color_t col; color_t lcol; color_t acol; @@ -1450,6 +1580,7 @@ struct layout { struct xref *xrefs; struct line *lines; struct textbox *box; + struct margin *margin; int w; int h; int align; @@ -1466,11 +1597,6 @@ struct layout { cache_t hlprerend_cache; }; -struct word_list { - struct word_list *next; - struct word *word; -}; - struct xref { struct xref *next; struct xref *prev; @@ -1563,6 +1689,43 @@ void layout_add_line(struct layout *layout, struct line *line) return; } +void layout_add_margin(struct layout *layout, struct margin *margin) +{ + struct margin *m = layout->margin; + if (!m) { + layout->margin = margin; + return; + } + while (m->next) + m = m->next; + m->next = margin; + return; +} + +int layout_find_margin(struct layout *layout, int y, int *w) +{ + struct margin *m = layout->margin; + int xpos = 0; + int rpos = layout->w; + if (!m) { + if (w) + *w = layout->w; + return 0; + } + while (m) { + if (y >= m->y && y < m->y + m->h) { + if (m->align == ALIGN_LEFT) + xpos = (xpos < m->w)?m->w:xpos; + else + rpos = (rpos > layout->w - m->w)?layout->w - m->w:rpos; + } + m = m->next; + } + if (w) + *w = rpos - xpos; + return xpos; +} + struct image *_layout_lookup_image(struct layout *layout, const char *name) { struct image *g = layout->images; @@ -1641,11 +1804,13 @@ struct layout *layout_new(fnt_t fn, int w, int h) l->w = w; l->h = h; l->fn = fn; + l->fn_height = 1.0f; l->align = ALIGN_JUSTIFY; l->valign = 0; l->style = 0; l->lstyle = 0; l->xrefs = NULL; + l->margin = NULL; l->col = gfx_col(0, 0, 0); l->lcol = gfx_col(0, 0, 255); l->acol = gfx_col(255, 0, 0); @@ -1693,6 +1858,7 @@ void _txt_layout_free(layout_t lay) struct line *l; struct image *g; struct xref *x; + struct margin *m; if (!layout) return; l = layout->lines; @@ -1707,6 +1873,12 @@ void _txt_layout_free(layout_t lay) x = x->next; xref_free(ox); } + m = layout->margin; + while (m) { + struct margin *om = m; + m = m->next; + margin_free(om); + } g = layout->images; while (g) { struct image *og = g; @@ -1719,6 +1891,8 @@ void _txt_layout_free(layout_t lay) layout->images = NULL; layout->xrefs = NULL; layout->lines = NULL; + layout->margin = NULL; + memset(layout->scnt, 0, sizeof(layout->scnt)); memset(layout->saved_align, 0, sizeof(layout->saved_align)); memset(layout->saved_valign, 0, sizeof(layout->saved_valign)); @@ -2080,6 +2254,15 @@ void txt_layout_color(layout_t lay, color_t fg) return; layout->col = fg; } + +void txt_layout_font_height(layout_t lay, float height) +{ + struct layout *layout = (struct layout*)lay; + if (!lay) + return; + layout->fn_height = height; +} + void txt_layout_link_color(layout_t lay, color_t link) { struct layout *layout = (struct layout*)lay; @@ -2204,6 +2387,10 @@ static int vertical_align(struct word *w, int *hh) h = fnt_height(layout->fn); if (hh) *hh = h; + + if (w->img && w->img_align) + return 0; + if (w->valign == ALIGN_TOP) return 0; else if (w->valign == ALIGN_BOTTOM) @@ -2211,6 +2398,39 @@ static int vertical_align(struct word *w, int *hh) return (line->h - h) / 2; } +static void word_image_render(struct word *word, int x, int y, clear_fn clear, update_fn update) +{ + struct line *line = word->line; + struct layout *layout = line->layout; + int yy; + + if (clear && !word->xref) + return; + yy = vertical_align(word, NULL); + + if (clear) { + if (word->img) { + if (word->img_align) + clear(x + word->x, y + line->y + yy, gfx_img_w(word->img), gfx_img_h(word->img)); + else + clear(x + line->x + word->x, y + line->y + yy, gfx_img_w(word->img), gfx_img_h(word->img)); + } else + clear(x + line->x + word->x, y + line->y/* + yy*/, word->w, line->h); + } + if (word->img) { + if (word->img_align) + gfx_draw(word->img, x + word->x, y + line->y + yy); + else + gfx_draw(word->img, x + line->x + word->x, y + line->y + yy); + if (update) + update(x + word->x, y + line->y + yy, gfx_img_w(word->img), gfx_img_h(word->img)); + } else { + word_render(layout, word, x + line->x + word->x, y + yy + line->y); + if (update) + update(x + line->x + word->x, y + line->y + yy, word->w, line->h); + } +} + void xref_update(xref_t pxref, int x, int y, clear_fn clear, update_fn update) { int i; @@ -2227,36 +2447,19 @@ void xref_update(xref_t pxref, int x, int y, clear_fn clear, update_fn update) } for (i = 0; i < xref->num; i ++) { - int yy; - struct line *line; word = xref->words[i]; - line = word->line; - - yy = vertical_align(word, NULL); - - if (clear) { - if (word->img) - clear(x + word->x, y + line->y + yy, gfx_img_w(word->img), gfx_img_h(word->img)); - else - clear(x + word->x, y + line->y/* + yy*/, word->w, line->h); - } - if (word->img) { - gfx_draw(word->img, x + word->x, y + line->y + yy); - update(x + word->x, y + line->y + yy, gfx_img_w(word->img), gfx_img_h(word->img)); - continue; - } - word_render(layout, word, x + word->x, y + yy + line->y); - update(x + word->x, y + line->y + yy, word->w, line->h); + word_image_render(word, x, y, clear, update); } gfx_noclip(); } + void txt_layout_draw_ex(layout_t lay, struct line *line, int x, int y, int off, int height, clear_fn clear) { void *v; img_t img; struct layout *layout = (struct layout*)lay; -// struct line *line; + struct margin *margin; struct word *word; // line = layout->lines; // gfx_clip(x, y, layout->w, layout->h); @@ -2264,30 +2467,24 @@ void txt_layout_draw_ex(layout_t lay, struct line *line, int x, int y, int off, return; for (v = NULL; (img = txt_layout_images(lay, &v)); ) gfx_dispose_gif(img); + + for (margin = layout->margin; margin; margin = margin->next) { + if (margin->y + margin->h < off) + continue; + if (margin->y - off > height) + continue; + word_image_render(margin->word, x, y, clear, NULL); + } if (!line) line = layout->lines; for (; line; line= line->next) { - int yy; if ((line->y + line->h) < off) continue; if (line->y - off > height) break; for (word = line->words; word; word = word->next ) { - if (clear && !word->xref) - continue; - yy = vertical_align(word, NULL); - if (clear) { - if (word->img) - clear(x + word->x, y + line->y + yy, gfx_img_w(word->img), gfx_img_h(word->img)); - else - clear(x + word->x, y + line->y/* + yy*/, word->w, line->h); - } - if (word->img) { - yy = (line->h - gfx_img_h(word->img)) / 2; - gfx_draw(word->img, x + word->x, y + line->y + yy); - continue; - } - word_render(layout, word, x + word->x, y + yy + line->y); + if (!word->img_align) + word_image_render(word, x, y, clear, NULL); } } cache_shrink(layout->prerend_cache); @@ -2578,14 +2775,14 @@ xref_t txt_box_xref(textbox_t tbox, int x, int y) yy = vertical_align(word, &hh); if (y < line->y + yy || y > line->y + yy + hh) continue; - if (x < word->x) + if (x < line->x + word->x) continue; xref = word->xref; if (!xref) continue; - if (x < word->x + word->w) + if (x < line->x + word->x + word->w) break; - if (word->next && word->next->xref == xref && x < word->next->x + word->next->w) { + if (word->next && word->next->xref == xref && x < line->x + word->next->x + word->next->w) { yy = vertical_align(word->next, &hh); if (y < line->y + yy || y > line->y + yy + hh) continue; @@ -2659,17 +2856,28 @@ void txt_layout_update_links(layout_t layout, int x, int y, clear_fn clear) // gfx_noclip(); } -img_t get_img(struct layout *layout, char *p) +img_t get_img(struct layout *layout, char *p, int *al) { int len; + int align; img_t img; struct image *image; + *al = 0; len = word_img(p, NULL); if (!len) return NULL; p += 3; p[len - 1] = 0; - + align = strcspn(p, "|"); + if (!p[align]) + align = 0; + else { + p[align] = 0; + if (!strcmp(p + align + 1, "left")) + *al = ALIGN_LEFT; + else if (!strcmp(p + align + 1, "right")) + *al = ALIGN_RIGHT; + } img = layout_lookup_image(layout, p); if (img) goto out; @@ -2691,6 +2899,8 @@ img_t get_img(struct layout *layout, char *p) cache_add(layout->img_cache, p, img); } out: + if (align) + p[align] = '|'; p[len - 1] = '>'; return img; } @@ -2869,7 +3079,7 @@ int get_unbrakable_len(struct layout *layout, const char *ptr) return w; } -int txt_layout_pos2off(layout_t lay, int pos) +int txt_layout_pos2off(layout_t lay, int pos, int *hh) { int off = 0; struct line *line; @@ -2877,7 +3087,9 @@ int txt_layout_pos2off(layout_t lay, int pos) if (!layout) return 0; for (line = layout->lines; line && (line->pos <= pos); line = line->next) { - off = line->y; + off = line->y; // + line->h; + if (hh) + *hh = line->h; } return off; } @@ -2886,6 +3098,10 @@ void _txt_layout_add(layout_t lay, char *txt) { int sp = 0; int saved_style; + int width; + int img_align; + struct margin *m; + struct line *line, *lastline = NULL; struct layout *layout = (struct layout*)lay; char *p, *eptr; @@ -2915,6 +3131,8 @@ void _txt_layout_add(layout_t lay, char *txt) line = lastline; } + line->x = layout_find_margin(layout, line->y, &width); + while (ptr && *ptr) { struct word *word; int sp2, addlen; @@ -2942,20 +3160,26 @@ void _txt_layout_add(layout_t lay, char *txt) if (!p) break; addlen = get_unbrakable_len(layout, eptr); - img = get_img(layout, p); + img = get_img(layout, p, &img_align); if (img) { w = gfx_img_w(img); h = gfx_img_h(img); + if (img_align && width - w <= 0) + img_align = 0; } else { p = get_word_token(p); TTF_SizeUTF8((TTF_Font *)(layout->fn), p, &w, &h); + h *= layout->fn_height; } nl = !*p; - if (!line->h) /* first word ? */ + if (!line->h && !img_align && !line->num) /* first word ? */ line->h = h; - if ((line->num && (line->w + ((sp && line->w)?spw:0) + w + addlen) > layout->w) || nl) { + if (img_align && !line->w) + line->h = 0; + + if ((line->num && (line->w + ((sp && line->w)?spw:0) + w + addlen) > width) || nl) { struct line *ol = line; h = 0; /* reset h for new line */ if ((layout->h) && (line->y + line->h) >= layout->h) @@ -2963,8 +3187,8 @@ void _txt_layout_add(layout_t lay, char *txt) if (line != lastline) { layout_add_line(layout, line); } - line_align(line, layout->w, line->align, nl); - + line_align(line, width, line->align, nl); + line = line_new(); if (!line) { free(p); @@ -2973,6 +3197,9 @@ void _txt_layout_add(layout_t lay, char *txt) line->align = layout->align; line->h = 0;//h; line->y = ol->y + ol->h; +// line->x = 0; + line->x = layout_find_margin(layout, line->y, &width); +// fprintf(stderr,"%d %d\n", line->x, width); if (nl) { ptr = eptr + 1; } @@ -2982,7 +3209,8 @@ void _txt_layout_add(layout_t lay, char *txt) continue; } - if (h > line->h) + + if (h > line->h && !img_align) line->h = h; word = word_new(p); @@ -3003,6 +3231,35 @@ void _txt_layout_add(layout_t lay, char *txt) word->x = line->w; word->img = img; + word->img_align = img_align; + + if (img_align && (m = margin_new())) { + int x2, w2; + + x2 = layout_find_margin(layout, line->y, &w2); + + if (img_align == ALIGN_LEFT) { + line->x += w; + m->w = x2 + w; + } + else + m->w = layout->w - x2 - w2 + w; + + width -= w; + + m->h = h; + m->y = line->y; + m->align = img_align; + m->word = word; + word->w = 0; + if (img_align == ALIGN_LEFT) + word->x = x2; + else + word->x = x2 + w2 - w; + h = 0; + w = 0; + layout_add_margin(layout, m); + } // if (line->w) // w += spw; @@ -3025,7 +3282,7 @@ void _txt_layout_add(layout_t lay, char *txt) // if (line->num) { if (line != lastline) layout_add_line(layout, line); - line_align(line, layout->w, line->align, nl); + line_align(line, width, line->align, nl); // } else // line_free(line); if (xref) @@ -3100,7 +3357,7 @@ int xref_position(xref_t x, int *xc, int *yc) return -1; if (xc) - *xc = word->x + (word->w + w); + *xc = line->x + word->x + (word->w + w); if (yc) *yc = line->y + line->h / 2; return 0; @@ -3124,11 +3381,11 @@ xref_t txt_layout_xref(layout_t lay, int x, int y) yy = vertical_align(word, &hh); if (y < line->y + yy || y > line->y + yy + hh) continue; - if (x < word->x) + if (x < line->x + word->x) continue; - if (x <= word->x + word->w) + if (x <= line->x + word->x + word->w) return xref; - if (word->next && word->next->xref == xref && x < word->next->x + word->next->w) { + if (word->next && word->next->xref == xref && x < line->x + word->next->x + word->next->w) { yy = vertical_align(word->next, &hh); if (y < line->y + yy || y > line->y + yy + hh) continue; @@ -3198,6 +3455,7 @@ void txt_layout_real_size(layout_t lay, int *pw, int *ph) { int w = 0; int h = 0; + struct margin *margin; struct line *line; struct layout *layout = (struct layout*)lay; if (!layout) @@ -3210,6 +3468,12 @@ void txt_layout_real_size(layout_t lay, int *pw, int *ph) if (line->num && line->y + line->h > h) h = line->y + line->h; } + + for (margin = layout->margin; margin; margin = margin->next) { + if (margin->y + margin->h > h) + h = margin->y + margin->h; + } + if (pw) *pw = w; if (ph) diff --git a/src/sdl-instead/graphics.h b/src/sdl-instead/graphics.h index 0b0b002..2f426b6 100644 --- a/src/sdl-instead/graphics.h +++ b/src/sdl-instead/graphics.h @@ -103,6 +103,7 @@ extern void txt_layout_free(layout_t lay); extern xref_t txt_layout_xref(layout_t lay, int x, int y); extern void txt_layout_color(layout_t lay, color_t fg); extern fnt_t txt_layout_font(layout_t lay); +extern void txt_layout_font_height(layout_t lay, float height); extern void txt_layout_link_color(layout_t lay, color_t link); extern void txt_layout_active_color(layout_t lay, color_t link); @@ -135,7 +136,7 @@ typedef void (*clear_fn)(int x, int y, int w, int h); extern void txt_box_update_links(textbox_t tbox, int x, int y, clear_fn); extern void txt_layout_update_links(layout_t layout, int x, int y, clear_fn clear); extern void txt_layout_real_size(layout_t lay, int *w, int *h); -extern int txt_layout_pos2off(layout_t lay, int pos); +extern int txt_layout_pos2off(layout_t lay, int pos, int *hh); extern img_t txt_box_render(textbox_t tbox); diff --git a/src/sdl-instead/instead.c b/src/sdl-instead/instead.c index 8e21d1a..8c875ef 100644 --- a/src/sdl-instead/instead.c +++ b/src/sdl-instead/instead.c @@ -6,6 +6,9 @@ #include "internals.h" /* the Lua interpreter */ +static gtimer_t instead_timer = NULL; +static int instead_timer_nr = 0; + char *fromgame(const char *s); char *togame(const char *s); lua_State *L = NULL; @@ -24,6 +27,8 @@ static int report (lua_State *L, int status) free(p); lua_pop(L, 1); status = -1; + gfx_del_timer(instead_timer); /* to avoid error loops */ + instead_timer = NULL; } return status; } @@ -91,7 +96,6 @@ char *getstring(char *cmd) return s; } - int instead_eval(char *s) { if (!L) @@ -450,8 +454,6 @@ static int luaB_get_steadpath(lua_State *L) { return 1; } -static gtimer_t instead_timer = NULL; -static int instead_timer_nr = 0; extern void mouse_reset(int hl); /* too bad */ @@ -487,6 +489,7 @@ static int luaB_set_timer(lua_State *L) { const char *delay = luaL_optstring(L, 1, NULL); int d; gfx_del_timer(instead_timer); + instead_timer = NULL; if (!delay) d = 0; else @@ -498,6 +501,31 @@ static int luaB_set_timer(lua_State *L) { return 0; } +extern int theme_setvar(char *name, char *val); +extern char *theme_getvar(const char *name); + +static int luaB_theme_var(lua_State *L) { + const char *var = luaL_optstring(L, 1, NULL); + const char *val = luaL_optstring(L, 2, NULL); + if (var && !val) { /* get */ + char *p = theme_getvar(var); + if (p) { + lua_pushstring(L, p); + free(p); + return 1; + } + return 0; + } + if (!val || !var) + return 0; + game_own_theme = 1; + if (!opt_owntheme) + return 0; + if (!theme_setvar((char*)var, (char*)val)) + game_theme_changed = 2; + return 0; +} + static const luaL_Reg base_funcs[] = { {"doencfile", luaB_doencfile}, {"dofile", luaB_dofile}, @@ -507,6 +535,7 @@ static const luaL_Reg base_funcs[] = { {"get_gamepath", luaB_get_gamepath}, {"get_steadpath", luaB_get_steadpath}, {"set_timer", luaB_set_timer}, + {"theme_var", luaB_theme_var}, {NULL, NULL} }; @@ -582,6 +611,7 @@ int instead_init(void) void instead_done(void) { gfx_del_timer(instead_timer); + instead_timer = NULL; #ifdef _HAVE_ICONV if (fromcp) free(fromcp); diff --git a/src/sdl-instead/menu.c b/src/sdl-instead/menu.c index 045cf04..8e2b68e 100644 --- a/src/sdl-instead/menu.c +++ b/src/sdl-instead/menu.c @@ -492,10 +492,11 @@ int game_menu_act(const char *a) if (!curgame_dir) return 0; // free_last(); - game_select(curgame_dir); game_menu_box(0, NULL); - game_load(nr); - cur_menu = menu_main; + if (!game_reset()) { + game_load(nr); + cur_menu = menu_main; + } // game_menu_box(0, NULL); } else if (!strcmp(a, "/new")) { char *s; @@ -507,11 +508,11 @@ int game_menu_act(const char *a) s = game_save_path(0, 0); if (s && !access(s, R_OK) && opt_autosave) unlink (s); - game_select(curgame_dir); game_menu_box(0, NULL); -// instead_eval("game:ini()"); instead_clear(); - game_cmd("look"); - custom_theme_warn(); + if (!game_reset()) { + game_cmd("look"); + custom_theme_warn(); + } } else if (!strcmp(a,"/main")) { if (restart_needed) { game_restart(); diff --git a/src/sdl-instead/themes.c b/src/sdl-instead/themes.c index aa33631..ce2e06c 100644 --- a/src/sdl-instead/themes.c +++ b/src/sdl-instead/themes.c @@ -1,6 +1,9 @@ + #include "externals.h" #include "internals.h" +int theme_relative = 0; + char *curtheme_dir = NULL; static int parse_gfx_mode(const char *v, void *data) @@ -17,6 +20,29 @@ static int parse_gfx_mode(const char *v, void *data) return 0; } +static int out_gfx_mode(const void *v, char **out) +{ + char *o; + switch (*((int*)v)) { + case GFX_MODE_FIXED: + o = strdup("fixed"); + break; + case GFX_MODE_EMBEDDED: + o = strdup("embedded"); + break; + case GFX_MODE_FLOAT: + o = strdup("float"); + break; + default: + o = strdup(""); + break; + } + if (!o) + return -1; + *out = o; + return 0; +} + static int parse_inv_mode(const char *v, void *data) { int *i = (int *)data; @@ -39,12 +65,53 @@ static int parse_inv_mode(const char *v, void *data) return 0; } +static int out_inv_mode(const void *v, char **out) +{ + char *o; + int m = *((int*)v); + o = malloc(64); + if (!o) + return -1; + if (m == INV_MODE_DISABLED) { + sprintf(o, "disabled"); + *out = o; + return 0; + } + + if (m & INV_MODE_VERT) { + sprintf(o, "vertical"); + } else if (m & INV_MODE_HORIZ) { + sprintf(o, "vertical"); + } + if ((m & INV_ALIGN_SET(ALIGN_CENTER)) == INV_ALIGN_SET(ALIGN_CENTER)) { + strcat(o, "-center"); + } else if ((m & INV_ALIGN_SET(ALIGN_LEFT)) == INV_ALIGN_SET(ALIGN_LEFT)) { + strcat(o, "-left"); + } else if ((m & INV_ALIGN_SET(ALIGN_RIGHT)) == INV_ALIGN_SET(ALIGN_RIGHT)) { + strcat(o, "-right"); + } + *out = o; + return 0; +} + static int parse_color(const char *v, void *data) { color_t *c = (color_t *)data; return gfx_parse_color(v, c); } +static int out_color(const void *v, char **out) +{ + char *o; + color_t *c = (color_t *)v; + o = malloc(16); + if (!o) + return -1; + sprintf(o, "#%02x%02x%02x", c->r, c->g, c->b); + *out = o; + return 0; +} + static int parse_include(const char *v, void *data) { int rc; @@ -59,18 +126,17 @@ static int parse_include(const char *v, void *data) setdir(cwd); return rc; } - struct parser cmd_parser[] = { { "scr.w", parse_int, &game_theme.w }, { "scr.h", parse_int, &game_theme.h }, { "scr.col.bg", parse_color, &game_theme.bgcol }, - { "scr.gfx.bg", parse_full_path, &game_theme.bg_name }, - { "scr.gfx.cursor.normal", parse_full_path, &game_theme.cursor_name }, + { "scr.gfx.bg", parse_full_path, &game_theme.bg_name, CHANGED_BG }, + { "scr.gfx.cursor.normal", parse_full_path, &game_theme.cursor_name, CHANGED_CURSOR }, { "scr.gfx.cursor.x", parse_int, &game_theme.cur_x }, { "scr.gfx.cursor.y", parse_int, &game_theme.cur_y }, - { "scr.gfx.use", parse_full_path, &game_theme.use_name }, /* compat */ - { "scr.gfx.cursor.use", parse_full_path, &game_theme.use_name }, - { "scr.gfx.pad", parse_int, &game_theme.pad }, + { "scr.gfx.use", parse_full_path, &game_theme.use_name, CHANGED_USE }, /* compat */ + { "scr.gfx.cursor.use", parse_full_path, &game_theme.use_name, CHANGED_USE }, + { "scr.gfx.pad", parse_int, &game_theme.pad }, { "scr.gfx.x", parse_int, &game_theme.gfx_x }, { "scr.gfx.y", parse_int, &game_theme.gfx_y }, { "scr.gfx.w", parse_int, &game_theme.max_scene_w }, @@ -79,33 +145,43 @@ struct parser cmd_parser[] = { { "win.x", parse_int, &game_theme.win_x }, { "win.y", parse_int, &game_theme.win_y }, - { "win.w", parse_int, &game_theme.win_w }, - { "win.h", parse_int, &game_theme.win_h }, - { "win.fnt.name", parse_full_path, &game_theme.font_name }, - { "win.fnt.size", parse_int, &game_theme.font_size }, + { "win.w", parse_int, &game_theme.win_w }, + { "win.h", parse_int, &game_theme.win_h }, + { "win.fnt.name", parse_full_path, &game_theme.font_name, CHANGED_FONT }, + { "win.fnt.size", parse_int, &game_theme.font_size, CHANGED_FONT }, + { "win.fnt.height", parse_float, &game_theme.font_height }, /* compat mode directive */ { "win.gfx.h", parse_int, &game_theme.max_scene_h }, /* here it was */ - { "win.gfx.up", parse_full_path, &game_theme.a_up_name }, - { "win.gfx.down", parse_full_path, &game_theme.a_down_name }, + { "win.gfx.up", parse_full_path, &game_theme.a_up_name, CHANGED_UP }, + { "win.gfx.down", parse_full_path, &game_theme.a_down_name, CHANGED_DOWN }, + { "win.up.x", parse_int, &game_theme.a_up_x }, + { "win.up.y", parse_int, &game_theme.a_up_y }, + { "win.down.x", parse_int, &game_theme.a_down_x }, + { "win.down.y", parse_int, &game_theme.a_down_y }, { "win.col.fg", parse_color, &game_theme.fgcol }, { "win.col.link", parse_color, &game_theme.lcol }, { "win.col.alink", parse_color, &game_theme.acol }, { "inv.x", parse_int, &game_theme.inv_x }, { "inv.y", parse_int, &game_theme.inv_y }, - { "inv.w", parse_int, &game_theme.inv_w }, - { "inv.h", parse_int, &game_theme.inv_h }, + { "inv.w", parse_int, &game_theme.inv_w }, + { "inv.h", parse_int, &game_theme.inv_h }, { "inv.mode", parse_inv_mode, &game_theme.inv_mode }, - { "inv.horiz", parse_inv_mode, &game_theme.inv_mode }, + { "inv.horiz", parse_inv_mode, &game_theme.inv_mode }, - { "inv.col.fg", parse_color, &game_theme.icol }, + { "inv.col.fg", parse_color, &game_theme.icol }, { "inv.col.link", parse_color, &game_theme.ilcol }, { "inv.col.alink", parse_color, &game_theme.iacol }, - { "inv.fnt.name", parse_full_path, &game_theme.inv_font_name }, - { "inv.fnt.size", parse_int, &game_theme.inv_font_size }, - { "inv.gfx.up", parse_full_path, &game_theme.inv_a_up_name }, - { "inv.gfx.down", parse_full_path, &game_theme.inv_a_down_name }, + { "inv.fnt.name", parse_full_path, &game_theme.inv_font_name, CHANGED_IFONT }, + { "inv.fnt.size", parse_int, &game_theme.inv_font_size, CHANGED_IFONT }, + { "inv.fnt.height", parse_float, &game_theme.inv_font_height }, + { "inv.gfx.up", parse_full_path, &game_theme.inv_a_up_name, CHANGED_IUP }, + { "inv.gfx.down", parse_full_path, &game_theme.inv_a_down_name, CHANGED_IDOWN }, + { "inv.up.x", parse_int, &game_theme.inv_a_up_x }, + { "inv.up.y", parse_int, &game_theme.inv_a_up_y }, + { "inv.down.x", parse_int, &game_theme.inv_a_down_x }, + { "inv.down.y", parse_int, &game_theme.inv_a_down_y }, { "menu.col.bg", parse_color, &game_theme.menu_bg }, { "menu.col.fg", parse_color, &game_theme.menu_fg }, @@ -113,21 +189,67 @@ struct parser cmd_parser[] = { { "menu.col.alink", parse_color, &game_theme.menu_alink }, { "menu.col.alpha", parse_int, &game_theme.menu_alpha }, { "menu.col.border", parse_color, &game_theme.border_col }, - { "menu.bw", parse_int, &game_theme.border_w }, - { "menu.fnt.name", parse_full_path, &game_theme.menu_font_name }, - { "menu.fnt.size", parse_int, &game_theme.menu_font_size }, - { "menu.gfx.button", parse_full_path, &game_theme.menu_button_name }, + { "menu.bw", parse_int, &game_theme.border_w}, + { "menu.fnt.name", parse_full_path, &game_theme.menu_font_name, CHANGED_MFONT }, + { "menu.fnt.size", parse_int, &game_theme.menu_font_size, CHANGED_MFONT }, + { "menu.fnt.height", parse_float, &game_theme.menu_font_height }, + { "menu.gfx.button", parse_full_path, &game_theme.menu_button_name, CHANGED_BUTTON }, { "menu.button.x", parse_int, &game_theme.menu_button_x }, { "menu.button.y", parse_int, &game_theme.menu_button_y }, /* compat */ { "menu.buttonx", parse_int, &game_theme.menu_button_x }, { "menu.buttony", parse_int, &game_theme.menu_button_y }, - { "snd.click", parse_full_path, &game_theme.click_name }, + { "snd.click", parse_full_path, &game_theme.click_name, CHANGED_CLICK }, { "include", parse_include, NULL }, { NULL, }, }; +#define TF_POSX 1 +#define TF_POSY 2 +#define TF_NEG 4 + +typedef struct { + const char *name; + int *val; + int flags; +} theme_scalable_t; + +static theme_scalable_t theme_scalables[] = { + { "scr.w", &game_theme.w }, + { "scr.h", &game_theme.h }, + { "scr.gfx.cursor.x", &game_theme.cur_x }, + { "scr.gfx.cursor.y", &game_theme.cur_y }, + { "scr.gfx.pad", &game_theme.pad }, + { "scr.gfx.x", &game_theme.gfx_x, TF_POSX }, + { "scr.gfx.y", &game_theme.gfx_y, TF_POSY }, + { "scr.gfx.w", &game_theme.max_scene_w, TF_NEG }, + { "scr.gfx.h", &game_theme.max_scene_h, TF_NEG }, + { "win.x", &game_theme.win_x, TF_POSX }, + { "win.y", &game_theme.win_y, TF_POSY }, + { "win.w", &game_theme.win_w }, + { "win.h", &game_theme.win_h }, + { "win.fnt.size", &game_theme.font_size }, + { "inv.x", &game_theme.inv_x, TF_POSX }, + { "inv.y", &game_theme.inv_y, TF_POSY }, + { "inv.w", &game_theme.inv_w }, + { "inv.h", &game_theme.inv_h }, + { "inv.fnt.size", &game_theme.inv_font_size }, + { "menu.fnt.size", &game_theme.menu_font_size }, + { "menu.button.x", &game_theme.menu_button_x, TF_POSX }, + { "menu.button.y", &game_theme.menu_button_y, TF_POSY }, + { "win.up.x", &game_theme.a_up_x, TF_POSX | TF_NEG }, + { "win.up.y", &game_theme.a_up_y, TF_POSY | TF_NEG }, + { "win.down.x", &game_theme.a_down_x, TF_POSX | TF_NEG }, + { "win.down.y", &game_theme.a_down_y, TF_POSY | TF_NEG }, + { "inv.up.x", &game_theme.inv_a_up_x, TF_POSX | TF_NEG }, + { "inv.up.y", &game_theme.inv_a_up_y, TF_POSY | TF_NEG }, + { "inv.down.x", &game_theme.inv_a_down_x, TF_POSX | TF_NEG }, + { "inv.down.y", &game_theme.inv_a_down_y, TF_POSY | TF_NEG }, + { NULL, }, +}; +static int theme_scalables_unscaled[sizeof(theme_scalables)/sizeof(theme_scalable_t)]; + struct game_theme game_theme = { .scale = 1.0f, .w = 800, @@ -141,18 +263,29 @@ struct game_theme game_theme = { .cur_x = 0, .cur_y = 0, .font_name = NULL, + .font_height = 1.0f, .font = NULL, .a_up_name = NULL, .a_down_name = NULL, .a_up = NULL, .a_down = NULL, + .a_up_x = -1, + .a_up_y = -1, + .a_down_x = -1, + .a_down_y = -1, .inv_font_name = NULL, .inv_font = NULL, + .inv_font_height = 1.0f, .inv_a_up_name = NULL, .inv_a_down_name = NULL, + .inv_a_up_x = -1, + .inv_a_up_y = -1, + .inv_a_down_x = -1, + .inv_a_down_y = -1, .inv_a_up = NULL, .inv_a_down = NULL, .menu_font_name = NULL, + .menu_font_height = 1.0f, .menu_font = NULL, .menu_button_name = NULL, .menu_button = NULL, @@ -162,8 +295,9 @@ struct game_theme game_theme = { .click = NULL, .xoff = 0, .yoff = 0, + .changed = 0, }; - +struct game_theme game_theme; static void free_theme_strings(void) { @@ -179,7 +313,7 @@ static void free_theme_strings(void) FREE(t->inv_font_name); FREE(t->menu_font_name); FREE(t->menu_button_name); -/* FREE(t->click_name); must be reloaded, ugly :(*/ + FREE(t->click_name); } int game_theme_free(void) @@ -221,7 +355,6 @@ int game_theme_free(void) game_theme.bg = NULL; game_theme.click = NULL; game_theme.cur_x = game_theme.cur_y = 0; -// game_theme.slide = gfx_load_image("slide.png", 1); return 0; } @@ -238,9 +371,9 @@ int theme_img_scale(img_t *p) *p = pic; return 0; } - static int game_theme_scale(int w, int h) { + int i; float xs, ys, v; int xoff, yoff; struct game_theme *t = &game_theme; @@ -249,9 +382,10 @@ static int game_theme_scale(int w, int h) t->scale = 1.0f; t->xoff = 0; t->yoff = 0; - return 0; + w = t->w; + h = t->h; + goto out; } - xs = (float)w / (float)t->w; ys = (float)h / (float)t->h; @@ -259,60 +393,137 @@ static int game_theme_scale(int w, int h) xoff = (w - t->w*v)/2; yoff = (h - t->h*v)/2; - t->w = w; - t->h = h; if (xoff < 0) xoff = 0; if (yoff < 0) yoff = 0; - t->pad *= v; - t->win_x *= v; t->win_x += xoff; - t->win_y *= v; t->win_y += yoff; - t->win_w *= v; - t->win_h *= v; - t->font_size *= v; - t->gfx_x *= v; t->gfx_x += xoff; - t->gfx_y *= v; t->gfx_y += yoff; - - if (t->max_scene_w != -1) - t->max_scene_w *= v; - - if (t->max_scene_h != -1) - t->max_scene_h *= v; - - t->inv_x *= v; t->inv_x += xoff; - t->inv_y *= v; t->inv_y += yoff; - t->inv_w *= v; - t->inv_h *= v; - - t->inv_font_size *= v; - t->menu_font_size *= v; - t->menu_button_x *= v; t->menu_button_x += xoff; - t->menu_button_y *= v; t->menu_button_y += yoff; - t->cur_x *= v; - t->cur_y *= v; - t->scale = v; t->xoff = xoff; t->yoff = yoff; +out: + for (i = 0; theme_scalables[i].name; i++) { + int val = *(theme_scalables[i].val); + theme_scalables_unscaled[i] = val; + if (val == -1 && (theme_scalables[i].flags & TF_NEG)) + continue; + val *= t->scale; + if (theme_scalables[i].flags & TF_POSX) + val += t->xoff; + if (theme_scalables[i].flags & TF_POSY) + val += t->yoff; + *(theme_scalables[i].val) = val; + } + t->w = w; + t->h = h; return 0; } +extern int parse_relative_path; -static int theme_gfx_scale(void) +char *theme_getvar(char *name) { - struct game_theme *t = &game_theme; - if (theme_img_scale(&t->a_up) || - theme_img_scale(&t->a_down) || - theme_img_scale(&t->inv_a_up) || - theme_img_scale(&t->inv_a_down) || - theme_img_scale(&t->use) || - theme_img_scale(&t->cursor) || - theme_img_scale(&t->menu_button) || - theme_img_scale(&t->bg)) + int i; + for (i = 0; theme_scalables[i].name; i ++) { + int val; + char buf[64]; + if (strcmp(theme_scalables[i].name, name)) + continue; + val = theme_scalables_unscaled[i]; + sprintf(buf, "%d", val); + return strdup(buf); + } + /* so, it is a string or like this */ + for (i = 0; cmd_parser[i].cmd; i++) { + int *num; + char *s; + float *f; + char buf[64]; + if (strcmp(cmd_parser[i].cmd, name)) + continue; + if (cmd_parser[i].fn == parse_int) { + num = (int *)cmd_parser[i].p; + sprintf(buf, "%d", *num); + return strdup(buf); + } else if (cmd_parser[i].fn == parse_full_path) { + s = *((char **)cmd_parser[i].p); + if (!s) + return NULL; + return strdup(s); + } else if (cmd_parser[i].fn == parse_inv_mode) { + if (out_inv_mode(cmd_parser[i].p, &s)) + return NULL; + return s; + } else if (cmd_parser[i].fn == parse_gfx_mode) { + if (out_gfx_mode(cmd_parser[i].p, &s)) + return NULL; + return s; + } else if (cmd_parser[i].fn == parse_float) { + f = (float*)cmd_parser[i].p; + sprintf(buf, "%f", *f); + return strdup(buf); + } else if (cmd_parser[i].fn == parse_color) { + if (out_color(cmd_parser[i].p, &s)) + return NULL; + return s; + } else + return NULL; + break; + } + return NULL; +} + +static int theme_process_cmd(char *n, char *v, struct parser *cmd_parser) +{ + int i; + n = strip(n); + v = strip(v); + + if (process_cmd(n, v, cmd_parser)) return -1; + for (i = 0; cmd_parser[i].cmd; i++) { + if (!strcmp(cmd_parser[i].cmd, n)) { + game_theme.changed |= cmd_parser[i].aux; + return 0; + } + } + + return -1; +} + +int theme_setvar(char *name, char *val) +{ + int rc = -1; + struct game_theme *t = &game_theme; + theme_relative = 1; + if (!theme_process_cmd(name, val, cmd_parser)) { + int i; + for (i = 0; theme_scalables[i].name; i++) { + int val; + if (strcmp(theme_scalables[i].name, name)) + continue; + val = *(theme_scalables[i].val); + theme_scalables_unscaled[i] = val; + if (val == -1 && (theme_scalables[i].flags & TF_NEG)) + continue; + val *= t->scale; + if (theme_scalables[i].flags & TF_POSX) + val += t->xoff; + if (theme_scalables[i].flags & TF_POSY) + val += t->yoff; + *(theme_scalables[i].val) = val; + break; + } + rc = 0; + } + theme_relative = 0; + return rc; +} + +static int theme_bg_scale(void) +{ + struct game_theme *t = &game_theme; if (t->bg) { img_t screen, pic; int xoff = (t->w - gfx_img_w(t->bg))/2; @@ -359,105 +570,148 @@ int game_theme_optimize(void) return 0; } -int game_theme_init(int w, int h) +static int game_theme_update_data(void) { struct game_theme *t = &game_theme; - - game_theme_scale(w, h); - - if (t->font_name) { + + if (t->font_name && (t->changed & CHANGED_FONT)) { fnt_free(t->font); if (!(t->font = fnt_load(t->font_name, FONT_SZ(t->font_size)))) goto err; } - if (t->inv_font_name) { + if (t->inv_font_name && (t->changed & CHANGED_IFONT)) { fnt_free(t->inv_font); if (!(t->inv_font = fnt_load(t->inv_font_name, FONT_SZ(t->inv_font_size)))) goto err; } - if (t->menu_font_name) { + if (t->menu_font_name && (t->changed & CHANGED_MFONT)) { fnt_free(t->menu_font); if (!(t->menu_font = fnt_load(t->menu_font_name, t->menu_font_size))) /* do not scale menu!!! */ goto err; } - - if (t->a_up_name) { + if (t->a_up_name && (t->changed & CHANGED_UP)) { gfx_free_image(t->a_up); if (!(t->a_up = gfx_load_image(t->a_up_name))) goto err; + if (theme_img_scale(&t->a_up)) + goto err; } - if (t->a_down_name) { + if (t->a_down_name && (t->changed & CHANGED_DOWN)) { gfx_free_image(t->a_down); if (!(t->a_down = gfx_load_image(t->a_down_name))) goto err; + if (theme_img_scale(&t->a_down)) + goto err; } - if (t->inv_a_up_name) { + if (t->inv_a_up_name && (t->changed & CHANGED_IUP)) { gfx_free_image(t->inv_a_up); if (!(t->inv_a_up = gfx_load_image(t->inv_a_up_name))) goto err; - } - - - if (t->inv_a_down_name) { - gfx_free_image(t->inv_a_down); - if (!(t->inv_a_down = gfx_load_image(t->inv_a_down_name))) + if (theme_img_scale(&t->inv_a_up)) goto err; } - if (t->bg_name) { + if (t->inv_a_down_name && (t->changed & CHANGED_IDOWN)) { + gfx_free_image(t->inv_a_down); + if (!(t->inv_a_down = gfx_load_image(t->inv_a_down_name))) + goto err; + if (theme_img_scale(&t->inv_a_down)) + goto err; + } + + if (t->bg_name && (t->changed & CHANGED_BG)) { gfx_free_image(t->bg); t->bg = NULL; if (t->bg_name[0] && !(t->bg = gfx_load_image(t->bg_name))) goto err; + if (theme_img_scale(&t->bg)) + goto err; + if (theme_bg_scale()) + goto err; } - if (t->use_name) { + if (t->use_name && (t->changed & CHANGED_USE)) { gfx_free_image(t->use); if (!(t->use = gfx_load_image(t->use_name))) goto err; + if (theme_img_scale(&t->use)) + goto err; } - if (t->cursor_name) { + if (t->cursor_name && (t->changed & CHANGED_CURSOR)) { gfx_free_image(t->cursor); if (!(t->cursor = gfx_load_image(t->cursor_name))) goto err; - } - - if (t->menu_button_name) { - gfx_free_image(t->menu_button); - if (!(t->menu_button = gfx_load_image(t->menu_button_name))) + if (theme_img_scale(&t->cursor)) goto err; } - if (t->click_name) { + if (t->menu_button_name && (t->changed & CHANGED_BUTTON)) { + gfx_free_image(t->menu_button); + if (!(t->menu_button = gfx_load_image(t->menu_button_name))) + goto err; + if (theme_img_scale(&t->menu_button)) + goto err; + } + + if (t->click_name && (t->changed & CHANGED_CLICK)) { snd_free_wav(t->click); t->click = snd_load_wav(t->click_name); } - free_theme_strings(); - +// free_theme_strings(); /* todo, font */ + t->changed = 0; if (!t->cursor || !t->use || !t->inv_a_up || !t->inv_a_down || !t->a_down || !t->a_up || !t->font || !t->inv_font || !t->menu_font || !t->menu_button) { fprintf(stderr,"Can't init theme. Not all required elements are defined.\n"); goto err; } - - if (theme_gfx_scale()) { - fprintf(stderr, "Can't scale theme.\n"); - goto err; - } return 0; err: - fprintf(stderr, "Can not init theme!\n"); - game_theme_free(); + t->changed = 0; return -1; } +int game_theme_update(void) +{ + game_release_theme(); + if (game_theme_update_data()) { + fprintf(stderr, "Can not update theme!\n"); + return -1; + } + + if (game_apply_theme()) { + fprintf(stderr, "Can not apply theme!\n"); + return -1; + } + return 0; +} + +int game_theme_init(void) +{ + int w = opt_mode[0]; + int h = opt_mode[1]; + + if ((w == -1) + && (gfx_get_max_mode(&w, &h) || (game_theme.w <= w && game_theme.h <= h))) { + w = opt_mode[0]; + h = opt_mode[1]; + } + + game_theme_scale(w, h); + if (game_theme_update_data()) { + fprintf(stderr, "Can not init theme!\n"); + game_theme_free(); + game_theme_select(DEFAULT_THEME); + return -1; + } + return 0; +} static int theme_parse(const char *path) { @@ -473,8 +727,6 @@ int theme_load(const char *name) { if (theme_parse(name)) return 0; /* no theme loaded if error in parsing */ -// if (game_theme_init()) -// return -1; return 0; } @@ -607,14 +859,18 @@ int game_theme_load(const char *name) { struct theme *theme; char cwd[PATH_MAX]; + int rel = theme_relative; getdir(cwd, sizeof(cwd)); setdir(game_cwd); theme = theme_lookup(name); + theme_relative = 0; if (!theme || setdir(theme->path) || theme_load(dirpath(THEME_FILE))) { setdir(cwd); + theme_relative = rel; return -1; } setdir(cwd); + theme_relative = rel; return 0; } diff --git a/src/sdl-instead/themes.h b/src/sdl-instead/themes.h index eca2316..d58d26c 100644 --- a/src/sdl-instead/themes.h +++ b/src/sdl-instead/themes.h @@ -33,6 +33,7 @@ struct game_theme { char *font_name; int font_size; + float font_height; fnt_t font; int gfx_x; @@ -44,6 +45,8 @@ struct game_theme { char *a_down_name; img_t a_up; img_t a_down; + int a_up_x; int a_up_y; + int a_down_x; int a_down_y; color_t fgcol; color_t lcol; @@ -59,12 +62,16 @@ struct game_theme { color_t iacol; char *inv_font_name; int inv_font_size; + float inv_font_height; fnt_t inv_font; char *inv_a_up_name; char *inv_a_down_name; img_t inv_a_up; img_t inv_a_down; + + int inv_a_up_x; int inv_a_up_y; + int inv_a_down_x; int inv_a_down_y; // int lstyle; // int ilstyle; @@ -78,6 +85,7 @@ struct game_theme { int border_w; char *menu_font_name; int menu_font_size; + float menu_font_height; fnt_t menu_font; char *menu_button_name; @@ -90,8 +98,22 @@ struct game_theme { void *click; int xoff; int yoff; + int changed; }; +#define CHANGED_FONT 1 +#define CHANGED_IFONT 2 +#define CHANGED_MFONT 4 +#define CHANGED_BG 8 +#define CHANGED_CLICK 0x10 +#define CHANGED_CURSOR 0x20 +#define CHANGED_USE 0x40 +#define CHANGED_UP 0x80 +#define CHANGED_DOWN 0x100 +#define CHANGED_IUP 0x200 +#define CHANGED_IDOWN 0x400 +#define CHANGED_BUTTON 0x800 +#define CHANGED_ALL 0xffff struct theme { char *path; char *name; @@ -103,18 +125,25 @@ extern int themes_nr; extern char *curtheme_dir; extern struct game_theme game_theme; +extern struct game_theme game_theme_unscaled; + extern int game_default_theme(void); extern int game_theme_select(const char *name); extern int themes_lookup(const char *path); extern int themes_rename(void); extern int game_theme_load(const char *name); +extern int game_theme_init(void); extern int game_theme_free(void); -extern int game_theme_init(int w, int h); extern int game_theme_optimize(void); +extern int game_theme_update(void); + extern int theme_load(const char *name); extern char *game_local_themes_path(void); extern int theme_img_scale(img_t *p); + +extern int theme_relative; + #define GFX_MODE_FLOAT 0 #define GFX_MODE_FIXED 1 #define GFX_MODE_EMBEDDED 2 diff --git a/src/sdl-instead/util.c b/src/sdl-instead/util.c index 396a1d2..188daa6 100644 --- a/src/sdl-instead/util.c +++ b/src/sdl-instead/util.c @@ -51,7 +51,7 @@ char *strip(char *s) return s; } -static int process_cmd(char *n, char *v, struct parser *cmd_parser) +int process_cmd(char *n, char *v, struct parser *cmd_parser) { int i; n = strip(n); @@ -80,6 +80,7 @@ static int fgetsesc(char *oline, size_t size, FILE *fp) if (line[i - 1] == '\\') { line[i - 1] = 0; strncat(oline, line, size); + line[0] = 0; size -= strlen(line); if (size <= 0) return nr; @@ -261,10 +262,38 @@ int parse_int(const char *v, void *data) return 0; } +int parse_float(const char *v, void *data) +{ + float *f = (float *)data; + if (sscanf(v, "%f", f) != 1) + return -1; + return 0; +} + +static int parse_path(const char *v, void *data) +{ + char **p = ((char **)data); + if (*p) + free(*p); + if (!v[0]) { + *p = strdup(""); + return (*p)?0:-1; + } + *p = strdup(v); + if (!*p) + return -1; + *p = sdl_path(*p); + return 0; +} +extern int theme_relative; /* hack, theme layer here :( */ int parse_full_path(const char *v, void *data) { char cwd[PATH_MAX]; char **p = ((char **)data); + + if (theme_relative || !strncmp(v, "blank:", 6) || !strncmp(v, "box:", 4)) /* hack for special files*/ + return parse_path(v, data); + if (*p) free(*p); if (!v[0]) { diff --git a/src/sdl-instead/util.h b/src/sdl-instead/util.h index 0698cf7..8c6e318 100644 --- a/src/sdl-instead/util.h +++ b/src/sdl-instead/util.h @@ -7,6 +7,7 @@ struct parser { const char *cmd; parser_fn fn; void *p; + long aux; }; extern int is_space(int c); @@ -22,7 +23,11 @@ extern char *lookup_lang_tag(const char *fname, const char *tag, const char *com extern int parse_esc_string(const char *v, void *data); extern int parse_string(const char *v, void *data); extern int parse_int(const char *v, void *data); +extern int parse_float(const char *v, void *data); + extern int parse_full_path(const char *v, void *data); +extern int process_cmd(char *n, char *v, struct parser *cmd_parser); + extern char *encode_esc_string(const char *v); extern char *find_in_esc(const char *l, const char *s); #ifdef _HAVE_ICONV diff --git a/stead/Makefile b/stead/Makefile index 22841cd..5757b1d 100644 --- a/stead/Makefile +++ b/stead/Makefile @@ -25,6 +25,8 @@ install: $(INSTALL) kbd.lua $(STEADPATH)/kbd.lua $(INSTALL) hotkeys.lua $(STEADPATH)/hotkeys.lua $(INSTALL) hideinv.lua $(STEADPATH)/hideinv.lua + $(INSTALL) theme.lua $(STEADPATH)/theme.lua + $(INSTALL) visual.lua $(STEADPATH)/visual.lua uninstall: $(RM) $(STEADPATH)/stead.lua diff --git a/stead/Makefile.windows b/stead/Makefile.windows index 28312e4..94dab01 100644 --- a/stead/Makefile.windows +++ b/stead/Makefile.windows @@ -22,3 +22,5 @@ install: copy kbd.lua ..\bin\stead copy hotkeys.lua ..\bin\stead copy hideinv.lua ..\bin\stead + copy theme.lua ..\bin\stead + copy visual.lua ..\bin\stead diff --git a/stead/format.lua b/stead/format.lua index ecbe15d..e930fdc 100644 --- a/stead/format.lua +++ b/stead/format.lua @@ -3,7 +3,8 @@ format = { para_space = ' '; quotes = false; dash = false; - filter = nil + filter = nil; + nopara = '_'; } stead.fmt = stead.hook(stead.fmt, function(f, ...) @@ -26,8 +27,7 @@ stead.fmt = stead.hook(stead.fmt, function(f, ...) r = r:gsub(',,','„'):gsub("''",'”'); end if call_bool(format, 'para') then - r = r:gsub('\n([^\n])', '<¶>%1'):gsub('<¶>[ \t]*', '\n'..txtnb(format.para_space)); - r = r:gsub('^[ \t]*',txtnb(format.para_space)) + r = r:gsub('^[ \t]*', '<¶>'):gsub('\n([^\n])', '<¶>%1'):gsub('<¶>[ \t]*'..format.nopara,''):gsub('<¶>[ \t]*', '\n'..txtnb(format.para_space)); end end return r; diff --git a/stead/goto.lua b/stead/goto.lua index 4003128..2a08a42 100644 --- a/stead/goto.lua +++ b/stead/goto.lua @@ -33,7 +33,7 @@ go = function (self, where, back, noenter, noexit, nodsc) stead.in_exit_call = true -- to break recurse v,r = call(ref(self.where), 'exit', ref(where)); stead.in_exit_call = nil - if r == false then + if r == false or (stead.api_version >= "1.3.0" and v == false and r == nil) then return v, ret(r) end if self.where ~= was then @@ -51,7 +51,7 @@ go = function (self, where, back, noenter, noexit, nodsc) if not jump and not noenter then v, r = call(ref(where), 'enter', ref(was)); - if r == false then + if r == false or (stead.api_version >= "1.3.0" and v == false and r == nil) then self.where = was; return par('^^', res, v), ret(r) end diff --git a/stead/gui.lua b/stead/gui.lua index 27cd5ba..5e73975 100644 --- a/stead/gui.lua +++ b/stead/gui.lua @@ -50,10 +50,19 @@ iface.img = function(self, str) return ""; end; -iface.nb = function(self, str) +iface.imgl = function(self, str) if str == nil then return nil; end; - if str == '' then return ''; end - return ""; + return ""; +end; + +iface.imgr = function(self, str) + if str == nil then return nil; end; + return ""; +end; + +iface.nb = function(self, str) + if type(str) ~= 'string' then return nil end + return "","\\\\>"):gsub("%^","\\%^")..">"; end; iface.under = function(self, str) @@ -115,29 +124,27 @@ iface.ways = function(self, str) end; function get_inv(horiz) - str = iface:cmd("inv"); + str = me():inv(); if str then str = stead.string.gsub(str, '\n$',''); - str = stead.string.gsub(str, '\\'..stead.delim, '<&delim;>') - str = stead.string.gsub(str, stead.delim..'$', '') +-- str = stead.string.gsub(str, stead.delim..'$', '') if not horiz then - str = stead.string.gsub(str, stead.delim, game.gui.inv_delim); + str = stead.string.gsub(str, '\\?[\\'.. stead.delim ..']', { [stead.delim] = game.gui.inv_delim }); else - str = stead.string.gsub(str, stead.delim, game.gui.hinv_delim); + str = stead.string.gsub(str, '\\?[\\'.. stead.delim ..']', { [stead.delim] = game.gui.hinv_delim }); end - str = stead.string.gsub(str, '<&delim;>', stead.delim); + str = stead.string.gsub(str, '\\(.)', '%1'); end return str end instead.get_inv = get_inv; function get_ways() - str = iface:cmd("way"); - if str then + str = me():ways(); + if str and str ~= '' then str = stead.string.gsub(str, '\n$',''); - str = stead.string.gsub(str, '\\'..stead.delim, '<&delim;>'); - str = stead.string.gsub(str, stead.delim, game.gui.ways_delim); - str = stead.string.gsub(str, '<&delim;>', stead.delim); + str = stead.string.gsub(str, '\\?[\\'.. stead.delim ..']', { [stead.delim] = game.gui.ways_delim }); + str = stead.string.gsub(str, '\\(.)', '%1'); return iface:center(str); end return str @@ -152,8 +159,9 @@ function get_title() if type(s) ~= 'string' then s = call(here(), 'nam'); end - if type(s) == 'string' then - s = stead.string.gsub(s, '\\'..stead.delim, stead.delim); + if type(s) == 'string' and s ~= '' then + s = stead.string.gsub(s, '\\(.)', '%1'); + s = ""..s..""; end return s end @@ -246,7 +254,8 @@ fmt = function(...) end for i=1,stead.table.maxn(arg) do if type(arg[i]) == 'string' then - local s = stead.string.gsub(arg[i],'\t', ' '):gsub('[\n]+', ' '):gsub('%^','\n'); + local s = stead.string.gsub(arg[i],'\t', ' '):gsub('[\n]+', ' '); + s = stead.string.gsub(s, '\\?[\\^]', { ['^'] = '\n' }):gsub('\\(.)', '%1'); res = stead.par('', res, s); end end diff --git a/stead/input.lua b/stead/input.lua index 369c741..1bfec37 100644 --- a/stead/input.lua +++ b/stead/input.lua @@ -5,7 +5,7 @@ kbden = { ["3"] = "#", ["4"] = "$", ["5"] = "%", - ["6"] = "6", + ["6"] = "^", ["7"] = "&", ["8"] = "*", ["9"] = "(", @@ -268,7 +268,8 @@ function input_esc(s) return txtnb(s) end if not s then return end - return s:gsub("\\","\\\\"):gsub(">","\\>"):gsub("[^ ]+", rep):gsub("[ \t]", rep); +-- return s:gsub("\\","\\\\\\\\"):gsub(">","\\\\>"):gsub("%^","\\%^"): + return s:gsub("[^ ]+", rep):gsub("[ \t]", rep); end function inp(n, info, txt) diff --git a/stead/prefs.lua b/stead/prefs.lua index ddbbf29..c73f8e8 100644 --- a/stead/prefs.lua +++ b/stead/prefs.lua @@ -22,6 +22,12 @@ prefs = obj { end, purge = function(s) local name = get_savepath() .. '/prefs'; + local k,v + for k,v in pairs(s) do + if type(v) ~= 'function' and k ~= 'nam' and k ~= 'system_type' then + s[k] = nil + end + end return stead.os.remove(name); end }; diff --git a/stead/stead.lua b/stead/stead.lua index 1d86552..c45d858 100644 --- a/stead/stead.lua +++ b/stead/stead.lua @@ -1,5 +1,5 @@ stead = { - version = "1.2.3", + version = "1.3.0", api_version = "1.1.6", -- last version before 1.2.0 table = table, delim = ',', @@ -205,6 +205,16 @@ function img(v) return iface:img(v); end +function imgl(v) + if type(v) ~= 'string' then return nil; end; + return iface:imgl(v); +end + +function imgr(v) + if type(v) ~= 'string' then return nil; end; + return iface:imgr(v); +end + function txtem(v) if type(v) ~= 'string' then return nil; end; return iface:em(v) @@ -269,8 +279,8 @@ fmt = function(...) if type(arg[i]) == 'string' then local s = stead.string.gsub(arg[i],'[\t ]+',' '); s = stead.string.gsub(s, '[\n]+', ' '); - s = stead.string.gsub(s,'%^','\n'); - res = stead.par('',res,s); + s = stead.string.gsub(s, '\\?[\\^]', { ['^'] = '\n' }):gsub('\\(.)', '%1'); + res = stead.par('', res, s); end end return res @@ -360,7 +370,7 @@ end function obj_xref(self,str) function xrefrep(str) - local s = stead.string.gsub(str,'[{}]',''); + local s = stead.string.gsub(str,'[\001\002]',''); return xref(s, self); end if not str then @@ -369,7 +379,7 @@ function obj_xref(self,str) if not isObject(self) then return str; end - local s = stead.string.gsub(str,'{[^}]+}',xrefrep); + local s = stead.string.gsub(str, '\\?[\\{}]', { ['{'] = '\001', ['}'] = '\002' }):gsub('\001([^\002]+)\002', xrefrep); return s; end @@ -948,6 +958,9 @@ function dialog_rescan(self) return true end +function dialog_empty(self) + return not dialog_rescan(self); +end function dialog_phrase(self, num) if not tonumber(num) then @@ -1049,6 +1062,9 @@ function dlg(v) --constructor if v.punseen == nil then v.punseen = dialog_punseen; end + if v.empty == nil then + v.empty = dialog_empty; + end v = room(v); return v; end diff --git a/stead/xact.lua b/stead/xact.lua index a6a8d06..95a9f61 100644 --- a/stead/xact.lua +++ b/stead/xact.lua @@ -34,15 +34,15 @@ __do_xact = function(str, self) return '' end local xrefrep = function(str) - local s = stead.string.gsub(str,'[{}]',''); + local s = stead.string.gsub(str,'[\001\002]',''); local o,d,a, oo; local delim = ':' if stead.api_version >= "1.2.2" then delim = stead.delim; end - s = s:gsub("\\"..delim, "<&delim;>"); - local i = s:find(delim, 1, true); + s = s:gsub('\\?[\\'..delim..']', { [delim] = '\001' }); + local i = s:find('\001', 1, true); aarg = {} if i then o = s:sub(1, i - 1); @@ -71,20 +71,23 @@ __do_xact = function(str, self) else error("Wrong link: "..s, 3); end - d = d:gsub("<&delim;>", delim); + d = d:gsub("\001", delim); return xref(d, ref(oo, true), unpack(aarg)); end if type(str) ~= 'string' then return end - local s = stead.string.gsub(str,'{[^}]+}', xrefrep); + local s = stead.string.gsub(str, '\\?[\\{}]', { ['{'] = '\001', ['}'] = '\002' }):gsub('\001([^\002]+)\002',xrefrep); return s; end stead.fmt = stead.hook(stead.fmt, function(f, ...) - local r = f(unpack(arg)) - if type(r) == 'string' and stead.state then - r = __do_xact(r); + local i, res, s + for i=1,stead.table.maxn(arg) do + if type(arg[i]) == 'string' then + s = __do_xact(arg[i]); + res = stead.par('', res, s); + end end - return r; + return f(res); end) obj = stead.inherit(obj, function(v) diff --git a/themes/default/theme.ini b/themes/default/theme.ini index 1e75086..9a27a53 100644 --- a/themes/default/theme.ini +++ b/themes/default/theme.ini @@ -21,11 +21,16 @@ win.h = 568 win.fnt.name = sans.ttf win.fnt.size = 16 +win.fnt.height = 1.0 win.gfx.up = aup.png win.gfx.down = adown.png win.col.fg = black win.col.link = #b02c00 win.col.alink = #606060 +win.up.x = -1 +win.up.y = -1 +win.down.x = -1 +win.down.y = -1 inv.x = 620 inv.y = 8 @@ -34,13 +39,18 @@ inv.h = 564 inv.fnt.name = sans.ttf inv.fnt.size = 16 +inv.fnt.height = 1.0 inv.gfx.up = aup.png inv.gfx.down = adown.png inv.col.fg = #CCCCCC inv.col.link = #CCCCCC inv.col.alink = goldenrod inv.mode = vertical - +inv.up.x = -1 +inv.up.y = -1 +inv.down.x = -1 +inv.down.y = -1 + menu.col.bg = white menu.col.fg = black menu.col.link = blue @@ -50,6 +60,7 @@ menu.col.border = black menu.bw = 1 menu.fnt.name = sans.ttf menu.fnt.size = 15 +menu.fnt.height = 1.0 menu.gfx.button = menu.png menu.button.x = 776 menu.button.y = 576