diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..d464203
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,18 @@
+SUBDIRS = src/instead src/sdl-instead stead games themes
+
+all:
+ @for dir in $(SUBDIRS); do \
+ $(MAKE) -C $$dir $(@) || exit 1; \
+ done;
+
+clean:
+ @for dir in $(SUBDIRS); do \
+ $(MAKE) clean -C $$dir $(@) || exit 1; \
+ done;
+
+install: all
+ @for dir in $(SUBDIRS); do \
+ $(MAKE) -C $$dir install || exit 1; \
+ done;
+
+
diff --git a/Rules.make b/Rules.make
new file mode 120000
index 0000000..ea604df
--- /dev/null
+++ b/Rules.make
@@ -0,0 +1 @@
+Rules.make.system
\ No newline at end of file
diff --git a/Rules.make.standalone b/Rules.make.standalone
new file mode 100644
index 0000000..b79aef5
--- /dev/null
+++ b/Rules.make.standalone
@@ -0,0 +1,23 @@
+VERSION := \"0.7\"
+
+DESTDIR=
+BIN=
+STEADPATH=./stead
+THEMESPATH=./themes
+GAMESPATH=./games
+
+LUA_CFLAGS=$(shell pkg-config --cflags lua5.1)
+LUA_LFLAGS=$(shell pkg-config --libs lua5.1)
+
+# for arch linux use this
+#
+#LUA_CFLAGS=$(shell pkg-config --cflags lua)
+#LUA_LFLAGS=$(shell pkg-config --libs lua)
+#
+
+SDL_CFLAGS=$(shell sdl-config --cflags)
+SDL_LFLAGS=$(shell sdl-config --libs) -lSDL_ttf -lSDL_mixer -lSDL_image
+
+CFLAGS += -g -Wall -DHAVE_ICONV -DRUSSIAN
+
+
diff --git a/Rules.make.system b/Rules.make.system
new file mode 100644
index 0000000..aa6a92b
--- /dev/null
+++ b/Rules.make.system
@@ -0,0 +1,23 @@
+VERSION := \"0.7.2\"
+
+DESTDIR=/usr/local
+BIN=$(DESTDIR)/bin
+STEADPATH=$(DESTDIR)/share/stead
+THEMESPATH=$(DESTDIR)/share/stead/themes
+GAMESPATH=$(DESTDIR)/share/stead/games
+
+LUA_CFLAGS=$(shell pkg-config --cflags lua5.1)
+LUA_LFLAGS=$(shell pkg-config --libs lua5.1)
+
+# for arch linux use this
+#
+# LUA_CFLAGS=$(shell pkg-config --cflags lua)
+# LUA_LFLAGS=$(shell pkg-config --libs lua)
+#
+
+SDL_CFLAGS=$(shell sdl-config --cflags)
+SDL_LFLAGS=$(shell sdl-config --libs) -lSDL_ttf -lSDL_mixer -lSDL_image
+
+CFLAGS += -g -Wall -DHAVE_ICONV -DRUSSIAN
+
+
diff --git a/doc/1.jpg b/doc/1.jpg
new file mode 100644
index 0000000..7ea9e45
Binary files /dev/null and b/doc/1.jpg differ
diff --git a/doc/2.jpg b/doc/2.jpg
new file mode 100644
index 0000000..dafb23e
Binary files /dev/null and b/doc/2.jpg differ
diff --git a/doc/4.jpg b/doc/4.jpg
new file mode 100644
index 0000000..cb6a26e
Binary files /dev/null and b/doc/4.jpg differ
diff --git a/doc/5.png b/doc/5.png
new file mode 100644
index 0000000..a3c9124
Binary files /dev/null and b/doc/5.png differ
diff --git a/doc/6.png b/doc/6.png
new file mode 100644
index 0000000..f00b62b
Binary files /dev/null and b/doc/6.png differ
diff --git a/doc/index.html b/doc/index.html
new file mode 100644
index 0000000..4b5e1a1
--- /dev/null
+++ b/doc/index.html
@@ -0,0 +1,40 @@
+
+
+Интерпретатор простых текстовых приключений -- INSTEAD
+
+[ Что это такое? ] [ Скриншоты ] [ Скачать ]
+
+INSTEAD 0.7 -- интерпретатор простых текстовых приключений для Unix
+
+Интерпретатор STEAD (Simply Text Adventure) позволяет проигрывать игры, которые по жанру являются
+смесью визуальной новеллы, текстового квеста и классических квестов 90-х. Особенности STEAD игры:
+
+- очень простой исходный текст историй. (В качестве основы используется LUA);
+
- возможность использования графического или текстового (readline) интерфейса для игры;
+
- в графическом интерфейсе поддерживается музыка и графика;
+
- поддержка тем для графического интерпретатора -- конкретная игра может менять вид интерфейса;
+
- переносимость (изначально написана для Linux, зависит от SDL и lua).
+
+На данный момент автором STEAD написана одна игра: 'Возвращение Квантового Кота', которая входит в состав архива с исходным кодом.
+Игра содержит около 70 сцен, графику и oldschool треки.
+
+
+Работа графического интерпретатора.
+
+Настройки.
+
+Диалоги.
+
+Фрагмент исходного кода STEAD игры.
+
+Работа текстового интерпретатора (автодополнение readline).
+
+
+
+Скачать текущую версию можно здесь: http://sites.google.com/site/sdlinstead/
+
+[ Что это такое? ] [ Скриншоты ] [ Скачать ]
+
+(c)by Peter Kosyh, a.k.a. gl00my '2009 (gl00my(dog)mail.ru, jabber:gl00my@jabber.ru)
+
+
diff --git a/games/Makefile b/games/Makefile
new file mode 100644
index 0000000..3a7e598
--- /dev/null
+++ b/games/Makefile
@@ -0,0 +1,10 @@
+include ../Rules.make
+all:
+install:
+ install -d -m0755 $(GAMESPATH)
+ for f in *; do \
+ if [ ! -d $$f ]; then continue; fi;\
+ install -d -m0755 $(GAMESPATH)/$$f;\
+ tar -c -C $$f . | tar -x -C $(GAMESPATH)/$$f;\
+ done
+clean:
diff --git a/games/cat/autosave b/games/cat/autosave
new file mode 100644
index 0000000..18b7954
--- /dev/null
+++ b/games/cat/autosave
@@ -0,0 +1,104 @@
+wboxes._num = 0
+pdlg.obj[1]._disabled = false
+pdlg.obj[2]._disabled = true
+pdlg.obj[3]._disabled = false
+kitchendlg.obj[1]._disabled = false
+kitchendlg.obj[2]._disabled = false
+kitchendlg.obj[3]._disabled = true
+kitchendlg.obj[4]._disabled = true
+kitchendlg.obj[5]._disabled = true
+kitchendlg.obj[6]._disabled = true
+kitchendlg.obj[7]._disabled = true
+kitchendlg.obj[8]._disabled = true
+kitchendlg.obj[9]._disabled = true
+kitchendlg.obj[10]._disabled = true
+kitchendlg.obj[11]._disabled = true
+kitchendlg.obj[12]._disabled = true
+kitchendlg.obj[13]._disabled = true
+kitchendlg.obj[14]._disabled = true
+up._num = 0
+p51._off = true
+shopdlg.obj[1]._disabled = false
+shopdlg.obj[2]._disabled = true
+shopdlg.obj[3]._disabled = false
+shopdlg.obj[4]._disabled = true
+shopdlg.obj[5]._disabled = true
+shopdlg.obj[6]._disabled = true
+shopdlg.obj[7]._disabled = true
+gudlg.obj[1]._disabled = false
+gudlg.obj[2]._disabled = true
+gudlg.obj[3]._disabled = true
+gudlg.obj[4]._disabled = true
+gudlg.obj[5]._disabled = true
+gudlg.obj[6]._disabled = true
+gudlg.obj[7]._disabled = true
+gudlg.obj[8]._disabled = true
+gudlg.obj[9]._disabled = true
+p3._off = true
+metdlg.obj[1]._disabled = false
+metdlg.obj[2]._disabled = false
+facectrl.obj[1]._disabled = false
+facectrl.obj[2]._disabled = true
+facectrl.obj[3]._disabled = true
+facectrl.obj[4]._disabled = true
+facectrl.obj[5]._disabled = true
+facectrl.obj[6]._disabled = true
+facectrl.obj[7]._disabled = true
+mycat._lflast = 0
+shop2.obj[1]._disabled = false
+shop2.obj[2]._disabled = false
+shop2.obj[3]._disabled = false
+shop2.obj[4]._disabled = false
+shop2.obj[5]._disabled = false
+shop2.obj[6]._disabled = false
+shop2.obj[7]._disabled = true
+gdlg1.obj[1]._disabled = false
+gdlg1.obj[2]._disabled = true
+gdlg1.obj[3]._disabled = false
+p5._off = true
+escape2._timer = 0
+handgdlg.obj[1]._disabled = false
+handgdlg.obj[2]._disabled = false
+handgdlg.obj[3]._disabled = false
+p7._off = true
+p6._off = true
+p71._off = true
+p4._off = false
+carbox._num = 0
+p2._off = true
+p1._off = false
+gudlg2.obj[1]._disabled = false
+gudlg2.obj[2]._disabled = false
+gudlg2.obj[3]._disabled = true
+gudlg2.obj[4]._disabled = true
+gudlg2.obj[5]._disabled = true
+gudlg2.obj[6]._disabled = true
+p9._num = 1
+metdlg2.obj[1]._disabled = false
+metdlg2.obj[2]._disabled = false
+metdlg2.obj[3]._disabled = true
+p8._num = 1
+povardlg.obj[1]._disabled = false
+povardlg.obj[2]._disabled = false
+povardlg.obj[3]._disabled = false
+povardlg.obj[4]._disabled = false
+guydlg.obj[1]._disabled = false
+guydlg.obj[2]._disabled = false
+guydlg.obj[3]._disabled = false
+guydlg.obj[4]._disabled = true
+guydlg.obj[5]._disabled = true
+guydlg.obj[6]._disabled = true
+guydlg.obj[7]._disabled = true
+guydlg.obj[8]._disabled = false
+guarddlg.obj[1]._disabled = false
+guarddlg.obj[2]._disabled = false
+guarddlg.obj[3]._disabled = true
+guarddlg.obj[4]._disabled = true
+guarddlg.obj[5]._disabled = true
+guarddlg.obj[6]._disabled = true
+guarddlg.obj[7]._disabled = true
+pl.where = "main";
+game.pl = 'pl'
+game._music="mus/new.s3m"
+game._running = true
+game._time = 2
diff --git a/games/cat/ep1.lua b/games/cat/ep1.lua
new file mode 100644
index 0000000..bb1b2b6
--- /dev/null
+++ b/games/cat/ep1.lua
@@ -0,0 +1,903 @@
+mywear = obj {
+ nam = 'ватник',
+ dsc = function(s)
+ if here() == stolcorridor then
+ local st='';
+ if not have('gun') then
+ st = 'Под которым спрятан дробовик.';
+ end
+ return 'А еще на вешалке висит мой {ватник}.'..st;
+ else
+ return 'На гвоздике, вбитом в сосновую дверь, висит {ватник}.';
+ end
+ end,
+ inv = 'Зима. Но я одет в теплый ватник.',
+ tak = function(s)
+ if here() == stolcorridor then
+ if have('alienwear') then
+ return 'Я уже одет... Если я еще схвачу свой ватник, то буду выглядеть подозрительно...', false;
+ end
+ if me()._walked then
+ me()._walked = false;
+ inv():add('gun');
+ return 'Все-же мой ватник самый лучший!';
+ end
+ return 'Это слишком заметно... ', false;
+ else
+ return 'Я снял с гвоздика свой ватник.';
+ end
+ end,
+ use = function(s, o)
+ if o == 'guy' then
+ return 'Немного помешкав, вы поменялись ватниками...';
+ end
+ end
+};
+
+money = obj {
+ nam = 'деньги',
+ inv = 'Большие деньги -- большое зло... Хорошо что у меня немного денег...',
+ use = function(s, w)
+ if w == 'shopman' then
+ if shopman._wantmoney then
+ shopman._wantmoney = false;
+ return 'Я расплачиваюсь с Владимиром.';
+ end
+ return 'Я не хочу платить просто так...';
+ end
+ end
+};
+
+mybed = obj {
+ nam = 'кровать',
+ dsc = 'У окна стоит {кровать}.',
+ act = 'Сейчас не время спать.',
+};
+
+mytable = obj {
+ nam = 'стол',
+ dsc = 'В левом углу стоит дубовый {стол} с ящиками.',
+ act = function()
+ if not have(money) then
+ take('money');
+ return 'Порывшись в ящиках я достал деньги.';
+ end
+ return 'Стол... Этот стол я сделал своими руками.';
+ end,
+};
+
+foto = obj {
+ nam = 'фото',
+ dsc = 'На столе стоит {фотокарточка} в рамке.',
+ tak = 'Я взял фотографию.',
+ inv = 'На этой фотографии изображены я и мой Барсик.',
+};
+
+gun = obj {
+ nam = 'дробовик',
+ dsc = 'В правом углу хижины стоит {дробовик}.',
+ tak = 'Я взял дробовик и повесил его за спину.',
+ inv = function(s)
+ local st = '';
+ if s._obrez then
+ st = ' Кстати, теперь это обрез.';
+ if s._hidden then
+ st = st..' Он спрятан в моей одежде.';
+ end
+ end
+ if s._loaded then
+ return 'Дробовик заряжен...'..st;
+ else
+ return 'Разряженный дробовик... Я редко пользовался им в лесу...'..st;
+ end
+ end,
+ use = function(s, w)
+ if w == 'guard' then
+ return 'Да, они негодяи, но во-первых они люди, а во-вторых все-равно не поможет...', false;
+ end
+ if w == 'wire' then
+ return 'Слишком близко... Тут нужно что-то вроде кусачек...', false;
+ end
+ if w == 'cam' and not cam._boken then
+ cam._broken = true;
+ s._loaded = false;
+ return 'Я прицелился в камеру и выстрелил из обоих стволов... Глухой выстрел потонул в порывах вьюги...';
+ end
+ if not s._hidden then
+ if w == 'mywear' or w == 'alienwear' then
+ if not s._obrez then
+ return 'Я попытался спрятать дробовик в одежду, но он слишком длинный.'
+ else
+ s._hidden = true;
+ return 'Теперь я могу спрятать обрез в одежде!.';
+ end
+ end
+ end
+ if not s._loaded then
+ return 'Не заряжен...', false;
+ end
+ if w == 'mycat' or w == 'shopman' or w == 'guy' then
+ return 'Это не моя мысль...', false;
+ end
+ end
+};
+
+fireplace = obj {
+ nam = 'камин',
+ dsc = 'У стены стоит {камин}. Огоньки пламени неравномерно освещают хижину.',
+ act = 'Мне нравится сидеть у камина долгими зимними вечерами.',
+};
+
+mycat = obj {
+ nam = 'Барсик',
+ _lflast = 0,
+ lf = {
+ [1] = 'Барсик шевелится у меня за пазухой.',
+ [2] = 'Барсик выглядывает из за пазухи.',
+ [3] = 'Барсик мурлычит у меня за пазухой.',
+ [4] = 'Барсик дрожит у меня за пазухой.',
+ [5] = 'Я чувствую тепло Барсика у себя за пазухой.',
+ [6] = 'Барсик высовывает голову из за пазухи и осматривает местность.',
+ },
+ life = function(s)
+ local r = rnd(6);
+ if r > 2 then
+ return;
+ end
+ r = rnd(6);
+ while (s._lflast == r) do
+ r = rnd(6);
+ end
+ s._lflast = r;
+ return s.lf[r];
+ end,
+ desc = { [1] = 'Возле камина уютно свернувшись в клубок спит мой кот {Барсик}.',
+ [2] = '{Барсик} изучает местность вокруг хижины.',
+ [3] = '{Барсик} сидит на соседнем сидении.',
+ [4] = '{Барсик} что-то изучает у мусорных баков...',
+ [5] = '{Барсик} трется у моих ног.',
+ },
+ inv = 'Барсик у меня за пазухой... Бедный мой котик... Я спасу тебя!!! И весь мир...',
+ dsc = function(s)
+ local state
+ if here() == home then
+ state = 1;
+ elseif here() == forest then
+ state = 2;
+ elseif here() == inmycar then
+ state = 3;
+ elseif here() == village then
+ state = 4;
+ elseif here() == escape3 then
+ state = 5;
+ end
+ return s.desc[state];
+ end,
+ act = function(s)
+ if here() == escape3 then
+ take('mycat');
+ lifeon('mycat');
+ return 'Я забираю Барсика к себе за пазуху.';
+ end
+ return 'Я почесал Барсика за ушами...';
+ end,
+};
+
+inmycar = room {
+ nam = 'в машине',
+ dsc = 'Я в своей машине... Моя рабочая лошадка...',
+ pic = 'gfx/incar.png',
+ way = {'forest', 'village'},
+ enter = function(s, f)
+ local s = 'Я открываю дверь машины.';
+ if have('mybox') then
+ return 'Я не могу залезть в кабину вместе с этим ящиком...', false;
+ end
+ if seen('mycat') then
+ s = s..' Барсик запрыгивает в кабину.'
+ move('mycat','inmycar');
+ elseif not me()._know_where then
+ return 'Нет... Сначала я должен найти Барсика!', false
+ end
+ if f == 'guarddlg' then
+ return 'Хмм... Нужно что-то придумать...';
+ end
+ return cat(s, ' Ну что же, пора ехать...');
+ end,
+ exit = function(s, t)
+ local s=''
+ if seen('mycat') then
+ s = ' Барсик выпрыгивает из машины первым.';
+ move('mycat',t);
+ end
+ if ref(t) ~= from() then
+ from().obj:del('mycar');
+ move('mycar', t);
+ return [[
+Машина неохотно заводится... После длинного пути я, наконец, выключаю мотор и открываю дверь...]]..s;
+ end
+ return 'Нет... Кажется я что-то забыл...'..s;
+ end
+};
+
+mycar = obj {
+ nam = 'моя машина',
+ desc = {
+ [1] = 'Перед хижиной стоит мой старенький {пикап} Toyota.',
+ [2] = 'На стоянке машин стоит мой старенький {пикап}.',
+ [3] = 'Возле КПП стоит мой {пикап}.',
+ [4] = 'За углом стены стоит мой {пикап}.',
+ },
+ dsc = function(s)
+ local state
+ if here() == forest then
+ state = 1;
+ elseif here() == village then
+ state = 2;
+ elseif here() == inst then
+ state = 3;
+ elseif here() == backwall then
+ state = 4;
+ end
+ return s.desc[state];
+ end,
+ act = function(s)
+ return goto('inmycar');
+ end
+};
+
+iso = obj {
+ nam = 'изолента',
+ inv = 'Моток изоленты. Синего цвета...',
+ use = function(s, o)
+ if o == 'trap' and not trap._iso then
+ trap._iso = true;
+ return 'Я изолировал капкан изолентой.';
+ end
+ if o == 'wire' then
+ return 'Зачем мне это? Я все-равно не пролезу по колючей проволоке. К тому же я не могу ее изолировать -- меня долбанет током!';
+ end
+ end
+};
+
+trap = obj {
+ nam = 'капкан',
+ dsc = 'В траве лежит стальной {капкан}.',
+ tak = 'Проклятые браконьеры! Я беру капкан себе.',
+ inv = function(s)
+ if s._salo then
+ return 'Большая мышеловка! К тому же изолированная изолентой.';
+ end
+ if s._iso then
+ return 'Стальной. Очень острый. К тому же изолированный изолентой.';
+ else
+ return 'Стальной. Очень острый.';
+ end
+ end,
+ use = function(s, o)
+ if o == 'wire' and not wire._broken then
+ if not s._iso then
+ return 'Капкан железный... Тряхонет током и будь здоров...';
+ end
+ wire._broken = true;
+ onwall.way:add('eside');
+ return 'Я подношу взведенный капкан к проволоке... Как я и думал -- капкан перебил проволоку!';
+ end
+ end
+};
+
+deepforest = room {
+ i = 0,
+ nam = 'чаща',
+ pic = 'gfx/deepforest.png',
+ dsc = function(s)
+ local st = 'Я в чаще... ';
+ if s._i == 1 then
+ return st..'Сосны и ели... Больше ничего...';
+ elseif s._i == 2 then
+ return st..'Красивая березы -- только бы не заблудиться...';
+ elseif s._i == 3 then
+ return st..'Непроходимая чаща... Ничего не пойму -- я что -- заблудился?...';
+ elseif s._i == 4 then
+ return st..'Красивое озеро... Да... Может пора возвращаться?';
+ elseif s._i == 5 then
+ s._trap = true;
+ return st..'Какие-то кусты... Кусты.. Кусты...';
+ else
+ return st..'Пенек... Какой красивый пенек...';
+ end
+ end,
+ enter = function(s,f)
+ if f == 'forest' then
+ s._trap = false;
+ end
+ s._lasti = s._i;
+ while (s._i == s._lasti) do
+ s._i = rnd(6);
+ end
+ s.obj:del('trap');
+ s.way:del('forest');
+ if s._i == 5 and not inv():srch('trap') then
+ s.obj:add('trap');
+ end
+ if s._i == 3 and s._trap then
+ s.way:add('forest');
+ end
+ if f == 'forest' and inv():srch('trap') then
+ return [[Спасибо, я уже погулял по лесу...]], false;
+ end
+ if f == 'deepforest' then
+ return 'Хмм... Посмотрим...';
+ end
+ return [[В дикую чащу, пешком?
+Хм... Почему бы и нет -- это же моя работа... Браконьеров погоняю...]], true;
+--Я пол часа бродил по лесу, когда наткнулся на капкан...
+--Проклятые ьраконьеры! Я взял капкан с собой.]], false;
+ end,
+ way = {'deepforest'},
+};
+
+road = room {
+ nam = 'дорога',
+ enter = function()
+ return 'Пешком? Нееет...', false;
+ end
+};
+
+forest = room {
+ nam = 'перед хижиной',
+ pic = 'gfx/forest.png',
+ dsc = [[
+На улице перед хижиной все занесено снегом. Дикий лес окружает хижину со всех сторон. Дорога, ведущая в поселок занесена снегом.]],
+ way = { 'home', 'deepforest', 'road' },
+ obj = { 'mycar' },
+};
+
+home = room {
+ nam = 'хижина',
+ pic ="gfx/house.png",
+ dsc = [[
+В этой хижине я провел 10 лет. 10 лет назад я своими руками построил ее. Довольно тесно, но уютно.]],
+ obj = { 'fireplace', 'mytable', 'foto', 'mycat', 'gun',
+ vobj(1,'окно', 'В хижине есть единственное {окно}.'),
+ 'mybed', 'mywear' },
+ way = { 'forest' },
+ act = function(s,o)
+ if o == 1 then
+ return 'За окном белым-бело...';
+ end
+ end,
+ exit = function()
+ if not have('mywear') then
+ return 'На улице холодно... Я не пойду туда без моего ватника.', false
+ end
+ if seen(mycat) then
+ move('mycat','forest');
+ return [[
+Когда я выходил из хижины Барсик внезапно проснулся и бросился мне под ноги.
+Я погладил его за ушами -- Значит едем вместе?
+]]
+ end
+ end
+};
+---------------- here village begins
+truck = obj {
+ nam = 'черная машина',
+ dsc = 'Черная {машина} с тонированными стеклами стоит возле магазина.',
+ act = 'Гм... Это фургон... Кузов бронирован, это видно по нагрузке на колеса...',
+};
+
+guydlg = dlg {
+ pic = 'gfx/guy.png',
+ nam = 'разговор с бездомным',
+ dsc = 'Я подошел к нему... Он оглянулся и посмотрел на меня беглым взглядом - невысокий человек в потертой кепке и драном ватнике.',
+ obj = {
+ [1] = phr('Привет! Холодно наверное?', 'Да... Немного...'),
+ [2] = phr('Как случилось что ты оказался на улице?',
+[[Когда то я хотел стать кандидатом наук... Писал диссертацию на тему строения материи.. Но... Мой мозг
+переутомился... Я пытался успокоиться и вот... Теперь я здесь...]]),
+ [3] = phr('Как тебя зовут?', 'Эдуард...'),
+ [4] = _phr('Когда я уходил тут возле тебя был Кот... Где он?', 'Гм...', 'pon(5)'),
+ [5] = _phr('Да... Кот. Обычный кот, бродящий по снегу возле мусорных баков.', 'Так это был твой кот? Эммм...', 'pon(6)');
+ [6] = _phr('Да... Это мой Барсик! Говори же!',
+'... Ммм... Кажется его взял этот человек... Ммм... -- холодок пробежал у меня по спине...', 'pon(7)'),
+ [7] = _phr('Куда, куда он поехал?', 'Извини, братишка, я не видел...', 'shopdlg:pon(4); pon(8);'),
+ [8] = phr('Ладно... Не важно...', '...', 'pon(8); back()'),
+ },
+ exit = function()
+ pon(1);
+ return 'Он отвернулся от меня и снова стал шарить по бакам...';
+ end
+};
+
+guy = obj {
+ nam = 'бездомный',
+ dsc = 'В мусорных баках копается {бездомный}.',
+ act = function()
+ return goto('guydlg');
+ end,
+ used = function(s, w)
+ if w == 'money' then
+ return [[
+Я подошел и попытался дать немного денег... -- Мне не нужны чужие деньги... -- ответил он.]];
+ else
+ return 'Зачем это ему?';
+ end
+ end,
+};
+
+nomoney = function()
+ pon(1,2,3,4,5);
+ shopdlg:pon(2);
+ return cat('Тут я вспоминаю, что у меня нет денег... Совсем...^',back());
+end
+
+ifmoney ='if not have("money") then return nomoney(); end; shopman._wantmoney = true; ';
+
+dshells = obj {
+ nam = 'гильзы',
+ dsc = function(s)
+ if here()._dshells > 4 then
+ return 'Под ногами валяется '..here()._dshells..' {гильз} от моего дробовика...';
+ else
+ return 'Под ногами валяются '..here()._dshells..' {гильзы} от моего дробовика...';
+ end
+ end,
+ act = 'Это мои гильзы... Мне они больше не нужны...';
+};
+
+function dropshells()
+ if here() == deepforest then
+ return;
+ end
+ if not here()._dshells then
+ here()._dshells = 2;
+ else
+ here()._dshells = here()._dshells + 2;
+ end
+ here().obj:add('dshells');
+end
+
+shells = obj {
+ nam = 'патроны',
+ inv = 'Патроны для моего дробовика. Я очень редко их использую в лесу, в основном -- против браконьеров.',
+ use = function(s, on)
+ if on == 'gun' then
+ if gun._loaded then
+ return 'Уже заряжен...';
+ end
+ if gun._loaded == false then
+ gun._loaded = true;
+ dropshells();
+ return 'Открыв дробовик я выбрасываю две гильзы и перезаряжаю дробовик.';
+ end
+ gun._loaded = true;
+ return 'Я беру два патрона и отправляю их в оба ствола дробовика...';
+ end
+ end
+};
+
+news = obj {
+ nam = 'газета',
+ inv = [[
+Свежая газета... <<недавно построенный в тайге институт квантовой механики категорически опровергает
+причастность к аномальным явлениям>>.. Гм...]],
+ used = function(s, w)
+ if w == 'poroh' then
+ if have('trut') then
+ return 'У меня уже есть трут.';
+ end
+ inv():add('trut');
+ inv():del('poroh');
+ return 'Я высыпаю порох на клочок бумаги, которую я оторвал от газеты...';
+ end
+ end,
+};
+
+hamb = obj {
+ nam = 'гамбургер',
+ inv = function()
+ inv():del('hamb');
+ return 'Я перекусил. Вредная пища...';
+ end
+};
+
+zerno = obj {
+ nam = 'крупа',
+ inv = 'Просто гречка. Гречневая крупа...',
+};
+
+shop2 = dlg {
+ nam = 'купить',
+ pic = 'gfx/shopbuy.png',
+ obj = {
+ [1] = phr('Патронов... Мне нужны патроны...', 'Хорошо... Цена как обычно', ifmoney..'inv():add("shells")'),
+ [2] = phr('Зерна..', 'Хорошо... ', ifmoney..'inv():add("zerno")'),
+ [3] = phr('И еще гамбургер...', 'Ок..', ifmoney..'inv():add("hamb")'),
+ [4] = phr('Свежую прессу...', 'Конечно...', ifmoney..'inv():add("news")'),
+ [5] = phr('Моток изоленты...', 'Да. Держи.', ifmoney..'inv():add("iso")'),
+ [6] = phr('Ничего не надо...', 'Как пожелаешь.', 'pon(6); back()'),
+ [7] = _phr('Еще мне нужна лестница и кусачки...', 'Извини, этого у меня нет -- качает головой Владимир'),
+ },
+ exit = function(s)
+ if have('news') then
+ s.obj[4]:disable();
+ end
+ end
+};
+
+shopdlg = dlg {
+ nam = 'разговор с продавцом',
+ pic = 'gfx/shopman.png',
+ dsc = 'Маленькие глазки буравят меня маслянистым взглядом.',
+ obj = {
+ [1] = phr('Здравствуй, Владимир! Ну как оно?', 'Здравствуй, '..me().nam..'... Да потихоньку... - Владимир хитро улыбается.', 'pon(2)'),
+ [2] = _phr('Хочу сделать покупки.', 'Хорошо... Давай посмотрим, что тебе нужно?', 'pon(2); return goto("shop2")'),
+ [3] = phr('Ну пока!...', 'Ага... Удачи!', 'pon(3); return back();'),
+ [4] = _phr('Здесь только что был человек -- кто он?', 'Гм? -- тонкие брови Володи приподнимаются..','pon(5)'),
+ [5] = _phr('Он почему-то взял моего кота... Наверное подумал, что он бездомный... Кто этот человек в сером пальто?',
+[[
+Вообще-то он какая-то шишка... - поскреб Владимир свой небритый подбородок. -- В этом новом институте, что построили в
+нашей глуши год назад... -- пенсне Владимира задергалось в такт его речи -- он часто заходит в наш магазин,
+не любит толпы -- эти физики -- ну ты понимаешь... Странный народ -- Владимир пожал плечами...]],'pon(6)'),
+ [6] = _phr('А где этот институт находится?',
+'Да на 127-ом.. Только это, знаешь чего -- Владимир понизил голос -- об этом институте всякое говорят...', 'me()._know_where = true; inmycar.way:add("inst");pon(7)'),
+ [7] = _phr('Я только заберу своего кота назад...', 'Ну смотри, как знаешь.. Я бы на твоем месте... - качает головой Владимир. - Да, кажется его фамилия Белин. Я видел его кредитку... Хотя ты знаешь -- я их не принимаю -- Владимир зашмакал губами, пенсне хитро зашевелилось.'),
+ },
+};
+
+shopman = obj {
+ nam = 'продавец',
+ dsc = 'За прилавком стоит {продавец}. Довольно полное его лицо с небритой щетиной дополняет монокль.',
+ act = function()
+ return goto('shopdlg');
+ end
+};
+
+shop = room {
+ nam = 'магазин',
+ pic = 'gfx/inshop.png',
+ enter = function(s, f)
+ if village.obj:look('truck') then
+ village.obj:del('truck');
+ village.obj:del('mycat');
+ return [[
+Когда я заходил в магазин я чуть не с толкнулся с неприятным типом в сером пальто и
+шляпе с длинными полями... Он извинился каким-то шипящим голосом и сделал вид, что приподнимает шляпу... Из под
+ее полей блеснули белые зубы... Дойдя до прилавка я услышал звук запускающегося двигателя.]];
+ end
+ end,
+ act = function(s,w)
+ if w == 1 then
+ return 'Теперь на стоянке стоит только моя машина.';
+ end
+ end,
+ dsc = [[
+Это довольно странный магазин... Здесь вы найдете и скобяные изделия, и продукты и
+даже патроны... Не удивительно, ведь это единственный магазин на 100км...]],
+ way = { 'village' },
+ obj = {'shopman',vobj(1, 'окно', 'Сквозь {окно} видно стоянку машин.') },
+ exit = function(s, t)
+ if t ~= 'village' then
+ return;
+ end
+ if shopman._wantmoney then
+ return 'Я собираюсь выйти, когда меня останавливает деликатное покашливание Владимира... Конечно, я забыл заплатить...', false;
+ end
+ if not have('news') then
+ shop2.obj[4]:disable();
+ inv():add('news');
+ return 'Я собираюсь уходить, когда меня останавливает голос Владимира -- Возьми свежую прессу, для тебя -- бесплатно. Я возвращаюсь, беру газету и выхожу из магазина.';
+ end
+ end
+};
+
+carbox = obj {
+ _num = 0,
+ nam = function(s)
+ if s._num > 1 then
+ return 'ящики в машине';
+ else
+ return 'ящик в машине';
+ end
+ end,
+ act = function(s)
+ if inv():srch('mybox') then
+ return 'У меня уже есть ящик в руках...';
+ end
+ s._num = s._num - 1;
+ if s._num == 0 then
+ mycar.obj:del('carbox');
+ end
+ take('mybox');
+ return 'Я взял ящик из машины.';
+ end,
+ dsc = function(s)
+ if s._num == 0 then
+ return;
+ elseif s._num == 1 then
+ return 'В кузове моей машины лежит один {ящик}.';
+ elseif s._num < 5 then
+ return 'В кузове моей машины лежат '..tostring(s._num)..' {ящика}.';
+ else
+ return 'В кузове моей машины лежит '..tostring(s._num)..' {ящиков}.';
+ end
+ end,
+};
+
+mybox = obj {
+ nam = 'ящик',
+ inv = 'Я держу в руках ящик.... Добротно сделанная вещь! Пригодится в хозяйстве.',
+ use = function(s, o)
+ if o == 'boxes' then
+ inv():del('mybox');
+ return 'Я положил ящик обратно...';
+ end
+ if o == 'mycar' then
+ inv():del('mybox');
+ mycar.obj:add('carbox');
+ carbox._num = carbox._num + 1;
+ return 'Я положил ящик в кузов своей машины...';
+ end
+ if o == 'ewall' or o == 'wboxes' then
+ if not cam._broken then
+ return 'Мне мешает камера...';
+ end
+ inv():del('mybox');
+ ewall.obj:add('wboxes');
+ wboxes._num = wboxes._num + 1;
+ if wboxes._num > 1 then
+ return 'Я поставил следующий ящик на предыдущий...';
+ end
+ return 'Я поставил ящик у стены...';
+ end
+ end
+};
+
+boxes = obj {
+ nam = 'ящики',
+ desc = {
+ [1] = 'Около стоянки валяются пустые деревянные {ящики} из-под тушенки.',
+ },
+ dsc = function(s)
+ local state = 1;
+ return s.desc[state];
+ end,
+ act = function(s, t)
+ if carbox._num >= 5 then
+ return 'А может хватит уже брать ящики?...';
+ end
+ if inv():srch('mybox') then
+ return 'У меня уже есть один ящик...';
+ end
+ take('mybox');
+ return 'Я взял ящик в руки.';
+ end,
+};
+
+village = room {
+ nam = 'стоянка перед магазином',
+ dsc = 'Привычное место перед магазином. Стоянка машин. Все в снегу...',
+ pic = 'gfx/shop.png',
+ act = function(s, w)
+ if w == 1 then
+ return 'Баки как баки... Белый снег прикрывает мусор...';
+ end
+ end,
+ exit = function(s, t)
+ if t == 'shop' and seen('mycat') then
+ return 'Я позвал барсика, но он был сильно увлечен мусорными баками... Ладно -- я не на долго...';
+ end
+ end,
+ enter = function(s, f)
+ if ewall:srch('wboxes') and wboxes._num == 1 then
+ ewall.obj:del('wboxes');
+ ewall._stolen = true;
+ wboxes._num = 0;
+ end
+ if f == 'shop' and not s._ogh then
+ s._ogh = true;
+ set_music("mus/revel.s3m");
+ guydlg:pon(4);
+ guydlg:poff(8);
+ return 'Окинув стоянку беглым взглядом я позвал -- Барсик! Барсик! -- Куда запропастился мой кот?';
+ end
+ end,
+ way = { 'road', 'shop' },
+ obj = { 'truck', vobj(1,'баки', 'Ржавые мусорные {баки} покрыты снегом.'), 'guy','boxes' },
+};
+----------- trying to go over wall
+function guardreact()
+ pon(7);
+ if inst:srch('mycar') then
+ inst.obj:del('mycar');
+ inmycar.way:add('backwall');
+ inst.way:add('backwall');
+ return cat([[Четверо людей с автоматами провожают меня до моей машины.
+Мне пришлось завести двигатель и отъехать от института. Я проехал с дюжину километров, прежде чем в зеркале заднего вида
+исчез военный джип, с моими провожающими... ]], goto('inmycar'));
+ end
+ return cat([[Четверо вооруженных людей вышвыривают меня из КПП.^^]], goto('inst'));
+end
+
+guarddlg = dlg {
+ nam = 'охранник',
+ pic = 'gfx/guard.png',
+ dsc = [[Передо мной угловатое лицо охранника. Его глаза глядят насмешливо, но уголки рта загнуты
+вниз, что не располагает к беседе...]],
+ obj = {
+ [1] = phr('Моего кота по ошибке забрал сотрудник вашего института -- мне нужно войти.','-- Пропуск...', 'poff(2); pon(3);'),
+ [2] = phr('Я забыл свой пропуск -- можно мне зайти?','-- Нет...', 'poff(1); pon(3);'),
+ [3] = _phr('Вы знаете Белина? У него мой кот -- мне нужно его забрать...', '-- Нет пропуска?', 'pon(4)'),
+ [4] = _phr('Я просто пришел забрать своего кота! Дайте телефон Белина.',
+[[Глаза охранника меняют свой цвет. Уголки губ поднимаются наверх -- вот что, господин хороший -- я так понял,
+пропуска у вас нет, идите-ка отсюда пока можете...]], 'pon(5, 6)'),
+ [5] = _phr('Ну все, щас я дам по твоей роже...', 'Рука охранника тянется к автомату. ', 'poff(6); return guardreact();'),
+ [6] = _phr('Ладно, я пошел...', '-- Не спеши - охранник уже не скрывает свою ухмылку - ты мне не нравишься...','poff(5); return guardreact()'),
+ [7] = _phr('Щас я вас всех перестреляю из своего дробовика...', 'На этот раз охранник даже не отвечает. Его налитые кровью глаза красноречивей всяких слов.','return guardreact()'),
+ },
+};
+guard = obj {
+ nam = 'охрана',
+ dsc = [[
+В будке сидит {охрана}. Кажется она вооружена автоматами калашникова.
+]],
+ act = function(s)
+ return goto('guarddlg');
+ end,
+};
+kpp = room {
+ nam = 'КПП',
+ pic = 'gfx/kpp.png',
+ dsc = [[КПП -- контрольно пропускной пункт не оставляет никаких сомнений в том, что в институте не жалуют посторонних. Шлагбаум. Решетчатая будка. И тишина.
+]],
+ obj = { 'guard' },
+ way = { 'inst' }
+};
+inst = room {
+ nam = 'институт',
+ pic = 'gfx/inst.png',
+ dsc = [[
+Институт возвышается посреди пустынного снежного поля. Его зловещие контуры напоминают скорее тюрьму, чем научное
+учреждение. Позади территории института находятся железнодорожные пути. ]],
+ act = function(s, w)
+ if w == 1 then
+ return 'Высота стены около 5 метров. Но этого мало -- сверху проходит колючая проволока -- думаю она под напряжением...';
+ end
+ if w == 2 then
+ return 'Нет, Владимир был прав... Это какой-то военный штаб...';
+ end
+ if w == 3 then
+ return 'Да -- это похоже тот самый фургон, в котором человек в сером пальто увез моего Барсика.';
+ end
+ end,
+ used = function(s, w, b)
+ if b == 'mybox' and w == 1 then
+ return 'Я думаю, меня сразу заметит охрана.';
+ end
+ if w == 2 and b == 'gun' and gun._loaded then
+ return 'Меня посадят... Или просто побьют... Охранники совсем недалеко.';
+ end
+ if w == 3 and b == 'gun' and gun._loaded then
+ return 'Мне нужен мой кот, а не разрушения...';
+ end
+ end,
+ obj = {vobj(1, 'стена', 'Здание института окружено массивной бетонной {стеной}. В центре находится КПП.'),
+ vobj(2, 'камеры', 'На вышках установлены {камеры} слежения.'),
+ vobj(3, 'фургон', 'За шлагбаумом виднеется черный {фургон}')},
+ way = { 'road', 'kpp' },
+ exit = function(s, t)
+ if have('mybox') and t ~= 'inmycar' then
+ return 'Я не буду ходить с ящиком в руках...', false;
+ end
+ end,
+};
+
+cam = obj {
+ nam = 'камера слежения',
+ dsc = function(s)
+ if not s._broken then
+ return 'Неподалеку от меня -- одна из {камер} слежения. Я прижимаюсь к стене, чтобы меня не заметили.';
+ end
+ return 'Неподалеку валяются осколки {камеры} слежения. Их уже запорошило снегом.';
+ end,
+ act = function(s)
+ if not s._broken then
+ return 'Проклятая камера...';
+ end
+ return 'Ха... Получил, проклятый механизм? Интересно, когда придет охрана...';
+ end,
+};
+
+wire = obj {
+ nam = 'колючая проволока',
+ dsc = function(s)
+ if s._broken then
+ return 'Перед моими глазами обрывки колючей {проволоки}.';
+ end
+ return 'Перед моими глазами колючая {проволока}.';
+ end,
+ act = function(s)
+ if s._broken then
+ return 'Теперь она безопасна! Можно пробраться внутрь...';
+ end
+ return 'А вдруг она под напряжением?';
+ end,
+};
+
+onwall = room {
+ pic = 'gfx/onwall.png',
+ nam = 'на стене',
+ dsc = 'Я стою на ящиках, моя голова находится на уровне вершины стены. Холодно.',
+ enter = function(s)
+ if have('mybox') then
+ return 'Я не могу взобраться на стену с ящиком в руках.', false;
+ end
+ if wboxes._num < 5 then
+ return 'Я пытаюсь взобраться на стену... Но все-еще слишком высоко...',false;
+ end
+ return 'Я взбираюсь на стену по ящикам.';
+ end,
+ obj = { 'wire' },
+ way = { 'backwall' }
+};
+
+wboxes = obj {
+ _num = 0,
+ nam = function(s)
+ if (s._num > 1) then
+ return 'ящики у стены';
+ end
+ return 'ящик у стены';
+ end,
+ act = function(s)
+ return goto('onwall');
+ end,
+ dsc = function(s)
+ if s._num == 0 then
+ return;
+ elseif s._num == 1 then
+ return 'У стены лежит один {ящик}.';
+ elseif s._num < 5 then
+ return 'У стены стоит '..tostring(s._num)..' {ящика}, поставленные один на другой.';
+ else
+ return 'У стены стоят '..tostring(s._num)..' {ящиков}, поставленные один на другой.';
+ end
+ end,
+};
+
+ewall = obj {
+ nam = 'стена',
+ dsc = '{Стена} здесь возвышается на 4 метра. Снежная метель с воем бросает ледяные снежинки к ее подножию.',
+ act = function(s)
+ if not s._ladder then
+ s._ladder = true;
+ shop2:pon(7);
+ end
+ return 'Слишком высокая... Нужна лестница.';
+ end
+};
+
+backwall = room {
+ pic = 'gfx/instback.png',
+ enter = function(s, f)
+ local st = '';
+ if ewall._stolen then
+ ewall._stolen = false;
+ st = 'Ого!!! Кто-то украл мой ящик!!!';
+ end
+ if f == 'inmycar' then
+ return 'Отлично... Кажется удалось добраться незамеченным...'..' '..st;
+ end
+ return 'Плутая по снежному полю я добрался до задней стены.'..' '..st;
+ end,
+ nam = 'восточная стена института',
+ dsc = 'Я нахожусь у задней стороны института.',
+ obj = { 'ewall', 'cam' },
+ way = { 'inst', },
+ exit = function(s, t)
+ if have('mybox') and t ~= 'inmycar' then
+ return 'Я не буду ходить с ящиком в руках...', false;
+ end
+ end,
+};
diff --git a/games/cat/ep2.lua b/games/cat/ep2.lua
new file mode 100644
index 0000000..5c74461
--- /dev/null
+++ b/games/cat/ep2.lua
@@ -0,0 +1,1524 @@
+------------- now got inside!!! -----------------------
+napil = obj {
+ nam = 'напильник',
+ dsc = 'Под воротами валяется {напильник}.',
+ inv = 'Уже начал ржаветь...',
+ tak = 'Я взял напильник.',
+ use = function(s, w)
+ if w == 'knife' and not knife._oster then
+ knife._oster = true;
+ return 'Я затачиваю напильником нож... Теперь он острый!';
+ elseif w == 'gun' and not gun._obrez then
+ if here() == wside or here() == sside then
+ return 'Тут много людей вокруг!';
+ end
+ gun._obrez = true;
+ return 'Я присел, взял покрепче дробовик и укоротил напильником оба ствола.';
+ else
+ return 'Нет, это бесполезно пилить...';
+ end
+ end
+};
+eside = room {
+ pic = 'gfx/eside.png',
+ nam = 'сзади института',
+ dsc = [[ Я нахожусь у задней стены здания института. Здесь проходят рельсы.]],
+ act = function(s,w)
+ if w == 1 then
+ return 'Пулеметы направлены на внешнюю - южную сторону периметра, надо держаться от них подальше.';
+ end
+ if w == 2 then
+ return 'Ворота железные. И заперты изнутри.';
+ end
+ end,
+ obj = {
+ vobj(1,'пулеметные вышки', 'Въезд поезда охраняется пулеметными {вышками}..'),
+ vobj(2,'ворота', 'Железнодорожные пути проходят мимо больших железных {ворот} -- видимо через них обеспечивается снабжение.'),
+ 'napil',
+ },
+ exit = function(s, t)
+ if t == 'sside' then
+ return 'На южной стороне меня смущают пулеметы. Лучше не рисковать.', false
+ end
+ end,
+ enter = function(s, f)
+ if f == 'onwall' then
+ -- end of episode 1
+ inmycar = nil;
+ deepforest = nil;
+ road = nil;
+ forest = nil;
+ home = nil;
+ shop = nil;
+ village = nil;
+ kpp = nil;
+ inst = nil;
+ onwall = nil;
+ backwall = nil;
+ guydlg = nil;
+ shop2 = nil;
+ shopdlg = nil;
+ guarddlg = nil;
+ set_music("mus/ice.s3m");
+ end
+ end,
+ way = {'nside','sside'},
+};
+
+card = obj {
+ nam = 'пропуск',
+ inv = [[Это пропуск.
+Электронная смарткарта с фотографией какого-то металлюги. Написано: Алексей Подковин -- 3-й уровень, категория: материя. Гммм...]],
+};
+alienwear = obj {
+ xnam = {'джинсовка', 'красная куртка', 'пальто','куртка', 'белая куртка', 'пиджак', 'косуха', 'спортивная куртка',},
+ xinv = {
+ 'Холодновато, но стильно!',
+ 'Очень красиво смотрится на фоне снега!',
+ 'Длиннополое пальто -- это ретро!',
+ 'Я терминатор!',
+ 'Я пацифист!',
+ 'Пиджачок сидит на мне как влитой!',
+ 'Рокн рол мертв, а я еше нет!',
+ 'Когда-то я занимался альпинизмом!',
+ },
+ nam = function(s)
+ return s.xnam[s._num];
+ end,
+ inv = function(s)
+ if s._num == 7 and not have('card') then
+ inv():add('card');
+ return 'Немного покопавшись в карманах косухи я нашел карточку.';
+ end
+ return s.xinv[s._num];
+ end,
+};
+
+garderob = obj {
+ nam = 'гардероб',
+ dsc = 'На правой стороне коридора висят {вешалки} с одеждой.',
+ act = function(s, w)
+ if have('mywear') or have('alienwear') then
+ return 'Здесь много людей, я не думаю что я смогу сделать это незаметно.';
+ elseif tonumber(w) and tonumber(w) > 0 and tonumber(w) <= 8 then
+ if not me()._walked then
+ return 'Это будет слишком заметно...';
+ end
+ alienwear._num = w;
+ inv():add('alienwear');
+ ref(s.obj[w]):disable();
+ me()._walked = false;
+ inv():add('gun');
+ return 'Я спокойно беру чужую одежду и также спокойно одеваю ее... Дробовик я снимаю из под своего ватника.';
+ else
+ return 'Надо определиться...';
+ end
+ end,
+ used = function(s, w)
+ if w == 'mywear' then
+ garderob.obj:add('mywear');
+ inv():del('mywear');
+ inv():del('gun');
+ return 'Я вешаю ватник на вешалку. Дробовик придется спрятать под ватником.';
+ end
+ if w == 'alienwear' then
+ local v = alienwear._num;
+ ref(s.obj[v]):enable();
+ inv():del('alienwear');
+ inv():del('gun');
+ return 'Я вешаю чужую одежду на вешалку. Дробовик я вешаю под свой ватник на вешалке.';
+ end
+ end,
+ obj = {
+ vobj(1,'джинсовка','{Джинсовка}.'),
+ vobj(2,'красная куртка','{Куртка} ало-красного цвета.'),
+ vobj(3,'пальто','{Пальто}.'),
+ vobj(4,'куртка терминатора', "{Куртка} с надписью I\'ll back."),
+ vobj(5,'куртка с ромашками', "Белая {куртка} с изображением ромашек."),
+ vobj(6,'пиджак', "Шерстяной {пиджак}."),
+ vobj(7,'косуха','Клевая {косуха}.'),
+ vobj(8,'спортивная куртка', "Оранжевая альпинистская {куртка}."),
+ }
+};
+portrait = obj {
+ nam = 'портреты',
+ dsc = 'По стенам развешены большие {портреты} в деревянных рамах.',
+ act = 'Гм... На портретах одно и тоже лицо! Улыбающееся холодной улыбкой лицо человека лет сорока с холодным взглядом.',
+};
+
+salo = obj {
+ nam = 'сало',
+ inv = 'Это кусочек сала. Я не могу его доесть, он очень жесткий...',
+ use = function(s, w)
+ if w == 'trap' and not trap._salo then
+ inv():del('salo');
+ trap._salo = true;
+ return 'Гм... По-моему у меня получилась мышеловка!';
+ end
+ end
+};
+
+food = obj {
+ nam = 'еда',
+ inv = function (s)
+ inv():del('food');
+ return 'Я не выдерживаю и съедаю все это великолепие стоя, держа поднос в левой руке. Ухх... Затем я отношу поднос в мойку.';
+ end
+};
+
+knife = obj {
+ nam = 'нож',
+ dsc = 'На подносе лежит {нож}.',
+ inv = function(s)
+ if s._oster then
+ return 'Железный и очень острый ножик.';
+ end
+ return 'Железный и тупой ножик.';
+ end,
+ use = function(s, w)
+ if w == 'shells' then
+ if not s._oster then
+ return 'Нож тупой.';
+ end
+ if have('poroh') then
+ return 'У меня уже есть порох.';
+ end
+ inv():add('poroh');
+ return 'Я расковыриваю один из патронов и высыпаю на ладонь порох.';
+ end
+ end,
+ tak = function(s)
+ if have('knife') then
+ return 'У меня уже есть один...', false
+ end
+ return 'Возьму его пока с собой.';
+ end
+};
+
+ostatki = obj {
+ nam = 'остатки еды',
+ dsc = '{Объедки} равномерно распределены по тарелкам.',
+ tak = function(s)
+ if food._num ~= 2 or have('salo') then
+ return 'Ничего полезного...', false;
+ else
+ take('salo');
+ return 'Кусочек сала!', false;
+ end
+ end
+};
+
+podnos = obj {
+ nam = 'поднос',
+ dsc = 'На столе стоит {поднос}.',
+ act = function(s, w)
+ if w == 1 then
+ return 'Вилка как вилка... Не очень чистая.';
+ end
+ if w == 2 then
+ return 'Ложка не отличается оригинальностью своей конструкции.';
+ end
+ return 'Синий пластик. Немного жирный на ощупь.';
+ end,
+ obj = { 'ostatki',
+ vobj(1, 'вилка', 'Рядом лежат {вилка} и'),
+ vobj(2, 'ложка', '{ложка}.')
+ },
+};
+
+moika = room {
+ nam = 'мойка',
+ enter = function()
+ return cat('Я отношу грязную посуду в мойку.^^', goto('kitchen')), false;
+ end
+};
+
+eating = room {
+ pic = 'gfx/podnos.png',
+ enter = function(s, f)
+ podnos.obj:add('knife');
+ inv():del('food');
+ if not me()._kitchendlg then
+ me()._kitchendlg = true;
+ return goto('kitchendlg'), false;
+ end
+ if f ~= 'kitchendlg' then
+ return 'Я сажусь за пустой столик и слегка перекусываю.';
+ end
+ end,
+ nam = 'за столом',
+ dsc = 'Под моими руками гладкая поверхность стола.',
+ obj = { 'podnos' },
+ way = { 'moika' },
+ exit = function(s)
+ end
+};
+
+gotfood = function(w)
+ inv():add('food');
+ food._num = w;
+ return back();
+end
+
+invite = obj {
+ nam = 'приглашение',
+ inv = 'Приглашение на лекцию Белина: 4-й уровень, зал 2... Гммм.... Мне нужно туда попасть... У него мой Барсик.',
+}
+
+povardlg = dlg {
+ nam = 'на кухне',
+ pic = 'gfx/povar.png',
+ dsc = 'Передо мной полное лицо женщины - повара в белом колпаке и усталым взглядом...',
+ obj = {
+ [1] = phr('Мне вот-этих зелененьких... Ага -- и бобов!', 'На здоровье!', [[pon(1); return gotfood(1);]]),
+ [2] = phr('Картошку с салом, пожалуйста!', 'Приятного аппетита!', [[pon(2); return gotfood(2);]]),
+ [3] = phr('Две порции чесночного супа!!!', 'Прекрасный выбор!', [[pon(3);return gotfood(3);]]),
+ [4] = phr('Мне что-нибудь легонькое, у меня язва...', 'Овсянка!', [[pon(4); return gotfood(4);]]),
+ },
+};
+kitchendlg = dlg {
+ nam = 'разговор с сотрудником института',
+ pic = 'gfx/ilya.png',
+ dsc = 'Я взял свой поднос и присел за свободный столик. Через минуту со словами "Не занято?" ко мне подсел молодой парень.',
+ obj = {
+ [1] = phr('Нет, не занято...', '-- Спасибо. Как дела? Ты из какого отдела?', [[pon(3,4,5); poff(2);]]),
+ [2] = phr('Занято...', '-- Ха ха ха! Хорошая шутка! Ты из какого отдела?', [[pon(3,4,5); poff(1);]]),
+ [3] = _phr('Хм... Из отдела искривления пространства...', '-- Старье!', [[pon(6);poff(4,5)]]),
+ [4] = _phr('Ааа... Отдел квантовых скачков..', '-- Хм? Не слышал о таком.', [[pon(6);poff(3,5)]]),
+
+ [5] = _phr('ЭЭэ... Отдел изучения квазипространства!', '-- Ого! Прикольно!', [[pon(6);poff(3,4)]]),
+ [6] = _phr('Хм... ', '-- А у тебя какой уровень секретности?', [[pon(7,8)]]),
+ [7] = _phr('Супер секретно!', '-- Ух ты! ... ', [[poff(8); pon(9)]]),
+ [8] = _phr('Анонимный.', '-- Да? Не слышал о таком, наверное это более секретный уровень, чем мой...',
+[[poff(7); pon(9)]]),
+ [9] = _phr('Мэээ...', '-- Меня зовут Илья... Просто Илья -- тянет худую руку парень -- а тебя как?', [[pon(10, 11, 12)]]),
+ [10] = _phr('Пп.. Пк... Пупкин... Василий Пупкин.', '-- Редкая фамилия!', [[poff(11,12); pon(13)]]),
+ [11] = _phr('Сережка.', '-- Дай пятерню братан!', [[poff(10,12); pon(13)]]),
+ [12] = _phr('Гоша...', '-- Ну, будем знакомы Гошка!', [[poff(10,11); pon(13)]]),
+ [13] = _phr('Кхмм...',
+[[-- Какой ты странный... Но это не важно. Мы все здесь -- Илья сделал выразительное лицо -... Мне тут поручили
+распространить приглашения на закрытую лекцию Белина... Только для друзей... Ты мне нравишься, да и по уровню
+доступа проходишь... Так что...]], [[pon(14)]]),
+ [14] = _phr('Где он?... Гм.. Где лекция?',
+[[-- Четвертый уровень секретности. Зал 2. Ну, приходи! Хороший шанс приблизиться к... -- Илья посмотрел на один из портретов на стене. -- Да, чуть не забыл -- протягивает он своей гибкой рукой кусок белого
+пластика -- Ну, до встречи!... -- Уххх...]],[[inv():add('invite');return goto('eating');]]),
+ }
+};
+kitchen = room {
+ nam = 'столовая',
+ pic = 'gfx/kitchen.png',
+ dsc = 'Небольшой зал столовой.',
+ act = function(s, w)
+ if w == 4 then
+ return 'Я вижу как чьи-то руки берут подносы с грязной посудой и уносят их вглубь...';
+ end
+ if w == 1 then
+ if not have('food') then
+ return 'Я присел за свободный столик. Ну -- отдохнул, теперь пора за работу!';
+ end
+ return goto('eating');
+ end
+ if w == 2 then
+ return 'Гудят как пчелы...';
+ end
+ if w == 3 and not have('food') then
+ return cat([[Я встал в очередь... Взял в руки поднос, столовые приборы и салфетки. Время тянется мучительно долго, но вот, наконец, я заказываю
+еду...^^]], goto('povardlg'));
+ end
+ end,
+ used = function(s, w, ww)
+ if w == 1 and ww == 'food' then
+ return s:act(1);
+ end
+ end,
+ enter = function(s)
+ if not have('mywear') and not have('alienwear') then
+ me()._walked = true;
+ end
+ set_music('mus/foot.mod');
+ end,
+ exit = function(s, t)
+ if have('food') and t ~= 'eating' then
+ return 'Уйти с подносом в руках? Не могу.', false;
+ end
+ if t == 'stolcorridor' then
+ set_music('mus/ice.s3m');
+ end
+ end,
+ obj = { 'portrait', vobj(1, 'столики', 'По залу размещены {столы} на 4 или 8 человек.'),
+ vobj(2, 'люди', 'Столовая полна {людей}.'),
+ vobj(3, 'очередь', '{Очередь} за раздачей еды движется довольно быстро.'),
+ vobj(4, 'мойка', 'В углу расположено {окно} для сдачи грязной посуды.'),
+ },
+ way = { 'stolcorridor' },
+};
+
+stolcorridor = room {
+ nam = 'вход в столовую',
+ pic = 'gfx/kitchencor.png',
+ dsc = 'Длинный и узкий коридор тускло освещен флоуресцентным светом.',
+ act = function(s, w)
+ if w == 1 then
+ return 'Да, эти люди пришли за тем, чтобы поесть...';
+ end
+ end,
+ obj = {'garderob', vobj(1,'люди', 'По коридору ходят {люди}.')},
+ way = {'sside', 'kitchen'},
+ exit = function(s, t)
+ if t == 'sside' and not have('mywear') and not have('alienwear') then
+ return 'На улице холодно... Я не пойду без одежды.. Нет...', false;
+ end
+ end,
+ enter = function(s)
+ -- generate garderob
+ if have('gun') and not gun._hidden then
+ return 'Я боюсь, что мой дробовик там внутри будет вызывать лишние вопросы...', false;
+ end
+ local i
+ for i=1, 8 do
+ local o = garderob.obj[i];
+ ref(o):disable();
+ end
+ local k = 7;
+ for i=1, 5 do
+ if not have('alienwear') or k ~= alienwear._num then
+ local o = garderob.obj[k];
+ ref(o):enable();
+ end
+ k = rnd(8);
+ end
+ end
+};
+
+sside = room {
+ nam = 'южная сторона',
+ pic = 'gfx/sside.png',
+ dsc = [[Я нахожусь у южной стены здания института. ]],
+ act = function(s, w)
+ if w == 1 then
+ ways():add('stolcorridor');
+ return "Я подошел к подъезду. На двери подъезда надпись -- 'Столовая'. Хм -- зайти внутрь?";
+ end
+ if w == 2 then
+ return 'Те, кто выходят, выглядят более довольными...';
+ end
+ end,
+ way = {'eside','wside'},
+ obj = { vobj(1, "подъезд", "У восточного угла находится небольшой {подъезд}."),
+ vobj(2, "люди", "Время от времени дверь подъезда хлопает впуская и выпуская {людей}.")},
+ exit = function(s, t)
+ if t == 'eside' then
+ return 'Если я пойду туда, я попаду в зону видимости пулеметных вышек.', false
+ end
+ end
+};
+
+nside = room {
+ nam = 'северная сторона',
+ pic = 'gfx/nside.png',
+ dsc = 'Я нахожусь у северной стены здания института.',
+ way = {'eside','wside' },
+ act = function(s, w)
+ if w == 1 then
+ return 'Да -- водосточная труба... Довольно крепкая. Но вряд-ли я смогу взобраться по ней наверх.';
+ end
+ end,
+ obj = { vobj(1, 'труба', 'Водосточная {труба} проходит по восточному углу здания.')},
+};
+
+
+wside = room {
+ nam = 'фронтальная сторона',
+ pic = 'gfx/wside.png',
+ dsc = 'Фронтальная часть института.',
+ way = {'entrance', 'nside','sside' },
+ act = function(s, w)
+ if w == 1 then
+ return 'Тот самый фургон с которого все началось...';
+ end
+ if w == 5 then
+ return 'Она начинается слишком высоко, к тому-же снизу она закрыта на замок. Возможно, это будет кому-то полезно при пожаре, хотя я лично сомневаюсь...'
+ end
+ if w == 2 then
+ return 'Наверняка охранники в КПП узнают меня. Лучше я сначала спасу своего Барсика.';
+ end
+ if w == 3 then
+ return 'Красиво сделано, нечего сказать... Но я не могу избавиться от мысли, что институт пожирает входящих в него людей.';
+ end
+ if w == 4 then
+ return 'Уже почти стемнело, но в институт все-еще заходят сотрудники...';
+ end
+ end,
+ obj = { vobj(3, 'вход', 'Главный {вход} представляет собой крутящуюся стеклянную дверь'),
+ vobj(4, 'люди', ' впускающую и выпускающую {людей}.'),
+ vobj(1, 'фургон', 'Перед входом стоит черный {фургон}.'),
+ vobj(2, 'КПП', 'Дальше, в метрах 60 от меня, во все сгущающейся темноте я едва различаю {КПП}.'),
+ vobj(5, 'лестница', 'В южной части стены я вижу пожарную {лестницу}, поднимающуюся со второго до пятого этажа.' ),
+ }
+};
+
+turn1 = obj {
+ nam = 'турникеты',
+ dsc = 'Проход к лифтам с улицы заграждают блестящие стальные {турникеты}. <<Для всех уровней и категорий>> - светится зеленым надпись на турникетах.',
+ act = function(s, w)
+ if s._inside then
+ s._inside = false;
+ here().way:del('lift');
+ return 'Я подхожу к турникетам, подношу карточку и выхожу к двери главного входа.';
+ end
+ if s._unlocked then
+ s._inside = true;
+ here().way:add('lift');
+ return 'Я подхожу к турникетам, подношу карточку и через пару секунд я у лифтов.';
+ end
+ return 'Я подхожу к одному из аппаратов. Турникеты функционируют автономно. Проход закрыт -- на торце горит красная лампочка.';
+ end,
+ used = function(s,w)
+ if w == 'card' then
+ s._unlocked = true;
+ s._inside = true;
+ here().way:add('lift');
+ return 'Я подношу карточку к турникету. Загорается зеленый сигнал. Проход открыт! Я прохожу к лифтам.';
+ end
+ end
+};
+
+lustra = obj {
+ nam = 'люстры',
+ dsc = 'Над головой висят прекрасные сверкающие {люстры}.',
+ act = 'Не могу на них наглядеться... Наверное, это хрусталь?';
+
+};
+
+divan = obj {
+ nam = 'диван',
+ dsc = 'На противоположной стороне от охранника, в углу стоит {диван}.',
+ act = function(s)
+ return 'Черный кожаный, очень мягкий диван.';
+ end,
+};
+
+entrance = room {
+ nam = 'главный вход',
+ pic = 'gfx/entrance.png',
+ dsc = 'Первый этаж института поражает своим великолепием.',
+ act = function(s, w)
+ if w == 2 then
+ return 'Ворота заперты. На них висит замок.';
+ end
+ if w == 3 then
+ if not turn1._inside then
+ return 'К лифтам мне мешают пройти турникеты.';
+ end
+ return 'Четыре лифта явно не справляются с количеством сотрудников института.';
+ end
+ if w == 4 then
+ return 'Стеклянный или хрустальный стол, за которым стоит терминал...';
+ end
+ if w == 5 then
+ return 'Лучше я не буду лишний раз попадаться ему на глаза. Вряд ли он мне поможет.';
+ end
+ if w == 6 then
+ return 'Люди.. Я отвык от такого количества людей.';
+ end
+ end,
+ obj = {
+ 'lustra',
+ vobj(2, 'ворота', 'Железные {ворота}, ведущие к путям, занимают всю восточную стену.'),
+ vobj(3, 'лифты', 'Среднюю часть этажа занимают четыре {лифта}.'),
+ 'turn1',
+ vobj(4, 'стол', 'Перед турникетами находится {стол},'),
+ vobj(5, 'охранник', 'за которым сидит {охранник}.'),
+ vobj(6, 'люди', 'В институт входят и выходят {люди}, образовывая очереди у лифтов.'),
+ 'divan',
+ },
+ way = { 'wside' },
+ enter = function(s, f)
+ if have('gun') and f == 'wside' and not gun._hidden then
+ return 'Мне кажется там внутри возникнет множество вопросов по-поводу моего дробовика... Я должен его как-то спрятать.', false
+ end
+ end,
+ exit = function(s, t)
+ if t == 'wside' then
+ turn1._inside = false;
+ s.way:del('lift');
+ end
+ end,
+};
+
+pinlift = obj {
+ nam = function(s)
+ if s._num == 3 then
+ return '';
+ end
+ return 'люди';
+ end,
+ act = function(s)
+ return 'Подавленные и пустые взгляды... Тягостное молчание.';
+ end,
+ dsc = function(s)
+ if s._num == 1 then
+ return 'В лифте полно {людей}.';
+ end
+ if s._num == 2 then
+ return 'В лифте несколько {человек}.';
+ end
+ if s._num == 3 then
+ return 'Лифт пуст.'
+ end
+ end
+};
+
+lift = room {
+ nam = 'лифт',
+ pic = 'gfx/lift.png',
+ dsc = 'В лифте должно быть светло и уютно, но меня мучает клаустрофобия. На панели я вижу кнопки:',
+ enter = function(s, t)
+ if here() == entrance then
+ s._from = 1;
+ pinlift._num = 1;
+ return 'Я дожидаюсь, когда подойдет один из лифтов и захожу внутрь.';
+ end
+ pinlift._num = rnd(3);
+ if here() == floor2 then
+ s._from = 2;
+ elseif here() == floor3 then
+ s._from = 3;
+ elseif here() == floor4 then
+ s._from = 4;
+ elseif here() == floor5 then
+ s._from = 5;
+ end
+ return 'Я нажимаю кнопку вызова лифта и жду. Проходит некоторое время и я захожу внутрь.';
+ end,
+ act = function(s, w)
+ local to,st
+ if not tonumber(w) then
+ return
+ end
+ if w == s._from then
+ return cat('Нет!!! Клаустрофобия выгоняет меня из лифта.^^', back());
+ end
+ if w == 8 then
+ st = '';
+ if galstuk._wear then
+ st = ' К тому же, я в галстуке.';
+ end
+ if me()._brit then
+ return 'Я смотрю в зеркало и вижу усталое, но гладко-выбритое лицо. Это я.'..st;
+ end
+ return 'Я смотрю в зеркало и вижу усталое, заросшее щетиной лицо. Это я.'..st;
+ end
+ if w == 6 or w == 7 then
+ return 'Я нервничаю... Не надо нервов.';
+ end
+ if w == 1 then
+ to = 'entrance';
+ else
+ to = 'floor'..w;
+ end
+ return cat('Я нажимаю кнопку и жду. Меня мучает клаустрофобия, но я жду.. Уххх... Приехали!^^',
+ goto(to));
+ end,
+ exit = function()
+ return 'За моей спиной закрываются двери лифта.';
+ end,
+ obj = {
+ vobj(1,'1', '{1},'),
+ vobj(2,'2', '{2},'),
+ vobj(3,'3', '{3},'),
+ vobj(4,'4', '{4},'),
+ vobj(5,'5', '{5},'),
+ vobj(6,'стоп','{стоп}'),
+ vobj(7,'ход','и {ход}.'),
+ vobj(8,'зеркало', '{Зеркало} занимает всю заднюю часть.'),
+ 'pinlift',
+ },
+};
+
+floor2 = room {
+ nam = 'площадка 2-го этажа',
+ pic = 'gfx/floor2.png',
+ dsc = "На площадке второго этажа нет окон. Невысокий потолок и серо-зеленые стены. Тихо и холодно.",
+ act = function(s, w)
+ if w == 1 then
+ return 'Дверь, похоже, сделана из свинца... Я не вижу возможности попасть внутрь. И хорошо. На двери, кроме знака надпись -- <<Уровень:2 Категория:Ядерная энергия>>.';
+ end
+ if w == 2 then
+ return 'Да, на одном из этих лифтов я приехал на этот проклятый этаж...';
+ end
+ end,
+ obj = {
+ vobj(1, 'дверь', 'Я вижу массивную {дверь} с знаком <<осторожно - радиация!!!>>'),
+ vobj(2, 'лифты', 'Кажется, что четыре проема дверей {лифтов} мрачно следят за мной.'),
+ },
+ way = { 'lift' },
+};
+
+resh = obj {
+ nam = 'решетка',
+ dsc = function(s)
+ if not s._unscrew then
+ return 'Отверстие закрыто железной {решеткой}.';
+ end
+ if vent._off then
+ return 'В отверстии видны лопасти большого вентилятора. На полу валяется {решетка}.';
+ end
+ return 'В отверстии вращаются лопасти большого вентилятора. На полу валяется {решетка}.';
+ end,
+ act = function(s)
+ if s._unscrew then
+ return 'Вот что можно сделать обычным тупым ножом при наличии сноровки и терпения!';
+ end
+ if not stoly._moved then
+ return 'Не достать...';
+ end
+ return 'Решетка крепко привинчена 12 шурупами...';
+ end,
+ used = function(s, w)
+ if w == 'knife' and not s._unscrew and stoly._moved then
+ s._unscrew = true;
+ return 'Я встаю на стол и долго пытаюсь открутить шурупы ножом. Наконец, мне это удается. Решетка падает на пол. Я спускаюсь со стола.';
+ end
+ if w ~= 'stol' then
+ return 'Не получится...';
+ end
+ end,
+};
+
+vent = obj {
+ nam = 'вентиляция',
+ dsc = 'В центре потолка находится большое квадратное вентиляционное {отверстие}.',
+ act = function(s)
+ if not stoly._moved then
+ return 'До него не достать...';
+ end
+ if not resh._unscrew then
+ return 'Я встаю на стол и изучаю отверстие. Оно закрыто решеткой... Я разочарованно спускаюсь на пол.';
+ end
+ if not s._off then
+ return 'Я встаю на стол и смотрю на острые лопасти вентилятора. Боюсь, это слишком опасно...';
+ end
+ if not s._trap then
+ return 'Я встаю на стол, хватаюсь руками за края отверстия и подтягиваюсь... Темно и сыро. Я пытаюсь забраться внутрь вентиляции, когда вдруг перед моими глазами я вижу красные глазки и зубы жирной крысы... Нет!!! Я падаю обратно на стол и скатываюсь на пол.';
+ end
+-- here we go!
+ return goto('toilet');
+ end,
+
+ used = function(s, w)
+ if w == 'stol' then
+ return
+ end
+ if not stoly._moved then
+ return 'Я не могу добраться до отверстия...';
+ end
+ if not resh._unscrew then
+ return 'Отверстие закрыто решеткой...';
+ end
+ if not s._off then
+ return 'Мне мешают лопасти вентилятора...';
+ end
+ if w == 'gun' and not s._trap then
+ gun._loaded = false;
+ return 'Я встаю на стол и просовываю руку с дробовиком в отверстие. Оба ствола выстреливают одновременно с глухим звуком. Я прислушиваюсь. В отверстии тихо... Я спускаюсь со стола на пол. Я думаю, это бесполезно...';
+ end
+ if w == 'trap' then
+ if not trap._salo then
+ return 'Я устанавливаю капкан на край отверстия. Жду. Но крыса не дура -- я забираю капкан обратно. Нужна приманка.';
+ end
+ inv():del('trap');
+ vent._trap = true;
+ return 'Я встаю на стол и устанавливаю капкан-мышеловку на край отверстия... Мне не приходится долго ждать... Лязг железа и визг крысы красноречиво говорит о том, что дело сделано!';
+ end
+ end,
+ obj = {
+ 'resh'
+ }
+};
+
+stol = obj {
+ nam = 'стол',
+ inv = 'Я держу один из столов за угол. Дуб.',
+ use = function(s, w)
+ if w == 'vent' or w == 'resh' then
+ inv():del('stol');
+ stoly._moved = true;
+ return 'Напрягая свои силы я сдвигаю один из столов в центр комнаты.';
+ end
+ end
+};
+
+stoly = obj {
+ nam = 'столы',
+ dsc = function(s, w)
+ if not s._moved then
+ return 'Четыре дубовых {стола} занимают все углы комнаты.';
+ end
+ return 'Три дубовых {стола} стоят в углах комнаты. Один стол передвинут в центр комнаты.';
+ end,
+ act = function(s, w)
+ if s._moved then
+ return 'Поставить один стол на другой? Нет -- я не смогу...';
+ end
+ inv():add('stol');
+ return [[Добротная мебель... Но стол в моей хижине лучше -- я сделал его своими руками. Я держу
+руками угол стола.]];
+ end
+};
+
+eroom = room {
+ nam = 'отдел СТО',
+ pic = function()
+ if not stoly._moved then
+ return 'gfx/sto.png';
+ end
+ if not resh._unscrew then
+ return 'gfx/sto2.png';
+ end
+ return 'gfx/sto3.png';
+
+ end,
+ dsc = [[Я нахожусь в небольшой комнате с бежевыми стенами.]],
+ enter = function(s, f)
+ if f == 'cor3' then
+ return [[Открыв дверь я заглядываю внутрь комнаты. Ухх... Пусто! Можно осмотреться...]];
+ end
+ if f == 'toilet' then
+ return 'Ну что же... Я поднимаю железную решетку в полу туалета и лезу в темноту... Через несколько минут я уже спрыгиваю из вентиляционного отверстия на стол, и спускаюсь на пол.';
+ end
+ end,
+ act = function(s, w)
+ if w == 1 then
+ return 'Отодвинув жалюзи я смотрю в уже черную даль, но наталкиваюсь на свое тусклое отражение. Опустив глаза вниз я вижу пулеметные вышки и железнодорожные пути.';
+ end
+ if w == 2 then
+ return 'Это всего лишь терминалы. Клиенты, которые подсоединяются к серверам института. Впрочем, меня это не интересует -- я 10 лет не видел компьютеров.';
+ end
+ end,
+ obj = {
+ vobj(1, 'окно', 'Большое {окно} выходит на восток.'),
+ 'stoly',
+ vobj(2, 'терминалы', 'На каждом столе стоит 17 дюймовый {терминал}.'),
+ 'vent',
+ 'portrait',
+ },
+ way = { 'cor3' },
+ exit = function()
+ inv():del('stol');
+ end
+};
+
+key = obj {
+ nam = 'ключ',
+ dsc = 'В двери торчит {ключ}.',
+ tak = 'Я осторожно вытаскиваю ключ и кладу его в карман.',
+ inv = 'Удивительно, но в институте вместе с электроникой используется такой простой и понятный механизм, как обычный дверной замок!',
+};
+
+room33 = room {
+ nam = 'комната',
+ pic = 'gfx/bholes.png',
+ dsc = [[Постояв несколько секунд у двери я открываю ее и вхожу внутрь.]],
+ act = function(s, w)
+ if w == 1 then
+ return cat('Седой человек в толстых очках оборачивается и с секунду смотрит на меня. -- Кто это? Выйдите немедленно!!^^',back());
+ end
+ end,
+ obj = {
+ vobj(1, 'люди', [[Я вижу как группа {людей} в белых халатах расположилась перед доской в центре комнаты и о чем-то ожесточенно спорит.]]),
+ 'portrait',
+ 'key'
+ };
+ way = { 'cor3' },
+ exit = [[ Я осторожно выхожу из комнаты.]];
+};
+room3x = room {
+ nam = 'комната',
+ enter = function(s, f)
+ if s._num == 2 then
+ return [[Я приоткрываю дверь и заглядываю внутрь. Квадратная комната с двумя окнами.
+Множество людей сидят за терминалами, расставленными вдоль стен. Я поскорее прикрываю дверь.]], false;
+ end
+ if s._num == 4 then
+ return [[Я берусь за холодный металл ручки и осторожно открываю дверь... -- Идет моделирование!!!
+-- слышу я из-за двери. Я быстро отпускаю ручку -- дверь закрывается...]],false;
+ end
+ if s._num == 5 then
+ ref(f).way:add('eroom');
+ return goto('eroom'), false;
+ end
+ if s._num == 6 then
+ return [[Я начинаю открывать дверь, когда вдруг начинаю слышать странное все нарастающее гудение. -- Какой идиот не закрыл дверь? -- слышу я изнутри. Я поспешно отхожу от двери.]], false;
+ end
+ end,
+};
+switch = obj {
+ nam = 'выключатель',
+ dsc = function(s)
+ local t
+ if vent._off then
+ t = ' в позиции <<выключено>>.';
+ else
+ t = ' в позиции <<включено>>.';
+ end
+ return 'В углу, перед входной дверью находится {выключатель}'..t;
+ end,
+ act = function(s)
+ if vent._off then
+ vent._off = false;
+ return 'Включаю!'
+ end
+ if not cor3._locked then
+ return [[Я перевожу выключатель в позицию <<выключено>> и иду вдоль стен, когда
+одна из дверей за мной вдруг открывается и старческий голос звучит на весь коридор -- Безобразие!!! Включите обратно!!! --
+мне приходиться вернуться к выключателю и перевести его в позицию <<включено>>.]];
+ end
+ vent._off = true;
+ return 'Выключаю!';
+ end
+};
+
+cor3 = room {
+ nam = 'коридор 3-го этажа',
+ pic = 'gfx/cor3.png',
+ enter = function(s, f)
+ if f == 'floor3' then
+ return 'Я подношу карточку к считывателю... Красная лампочка сначала моргает, а затем меняет свой цвет на зеленый... Проход открыт!';
+ end
+ end,
+ dsc = 'Длинный коридор идет до самой стены здания. На потолке тускло горят лампы дневного света. На полу постелена зеленая ковровая дорожка.',
+ act = function(s, w)
+ if w == 1 then
+ return 'Я подхожу к одной из дверей и заглядываю в окошко-иллюминатор... Люди в белых костюмах, словно пчелы снуют у причудливых аппаратов. -- Наверное это лаборатории -- догадываюсь я.';
+ end
+ if not tonumber(w) then
+ return nil, false
+ end
+ if w == 3 then
+ if s._locked then
+ return 'Эта комната закрыта... И слыша приглушенные, но настойчивые звуки изнутри, мне не хочется ее открывать.';
+ end
+ return goto('room33');
+ end
+ if tonumber(w) >=2 and tonumber(w) <=6 then
+ room3x._num = w;
+ return goto('room3x');
+ end
+ if w == 7 then
+ return 'Окно выходит на южную сторону... Темно -- ничего не видно кроме снежинок, ударяющихся о стекло...';
+ end
+ if w == 8 then
+ return 'Зайти?';
+ end
+ end,
+ used = function(s, w, ww)
+ if w == 1 or w == 2 or w == 4 or w == 5 or w == 6 then
+ return 'Не подходит...';
+ end
+ if w == 3 and ww == 'key' then
+ if s._locked then
+ return 'Уже закрыто...';
+ end
+ s._locked = true;
+ return 'Я вставляю ключ в замочную скважину и закрываю замок на два оборота. Вынимаю ключ и кладу обратно в карман.';
+ end
+ end,
+ obj = {
+ vobj(1, 'белые двери', 'По правой стороне коридора находятся белые металлические {двери} с стеклянными окошками.'),
+ vobj(2, 'гравитация', 'По левой стороне коридора я вижу несколько дверных проемов с надписями: {гравитация},'),
+ vobj(4, 'моделирование','{моделирование},'),
+ vobj(5, 'эффекты СТО','{эффекты СТО},'),
+ vobj(3, 'черные дыры', '{черные дыры},'),
+ vobj(6, 'квазипространство', '{квазипространство}.'),
+ vobj(7, 'окно', 'В конце коридора виднеется {окно}.'),
+ vobj(8, 'туалет', 'Возле окна находятся {туалеты}.'),
+ 'switch',
+ 'portrait',
+ },
+ way = {'floor3', 'toilet3', 'toiletw'},
+};
+
+mylo = obj {
+ nam = 'мыло',
+ inv = function(s)
+ if s._pena then
+ return 'Кусочек мыла в пене.';
+ end
+ return 'Кусочек мыла.';
+ end,
+ dsc = 'На умывальнике лежит кусочек {мыла}.',
+ tak = 'Я взял в руки скользкий кусочек мыла... Он выпал в умывальник, но я поймал его снова и сунул в карман...';
+};
+
+sushka = obj {
+ nam = 'сушка',
+ dsc = 'Рядом с умывальником находится {сушка}.',
+ act = function(s,w)
+ return 'Я подношу руки к сушке, сушка включается... Наваждение...';
+ end,
+};
+
+umyvalnik = obj {
+ nam = 'умывальник',
+ dsc = 'У входа находится {умывальник}.',
+ act = function(s)
+ if me()._mylo then
+ me()._mylo = false;
+ return 'Я смываю мыло со своего лица...';
+ end
+ return 'Я пью хлорированную воду жадными глотками... Да -- это не та вода из ручья которую я пью в лесу...';
+ end,
+ used = function(s, w)
+ if w == 'mylo' then
+ mylo._pena = true;
+ return 'Я опускаю мыло в теплую воду...';
+ end
+ end
+};
+
+toilet3 = room {
+ nam = 'туалет',
+ pic = 'gfx/toil3.png',
+ dsc = 'Я в туалете. Стандартная архитектура. Без окон. Белый кафель.',
+ act = function(s, w)
+ if w == 2 then
+ return 'Все заняты!';
+ end
+ if w == 3 then
+ return 'Люди равномерно распределены по туалету. Все унитазы заняты. Еще пару человек ждут своей очереди.';
+ end
+ end,
+ obj = {
+ 'umyvalnik',
+ 'mylo',
+ 'tzerkalo',
+ 'sushka',
+ vobj(2, 'унитазы', 'В этом туалете установлено 4 {унитаза}.'),
+ vobj(3, 'люди', 'В туалете несколько {человек}...'),
+ },
+ way = { 'cor3' },
+ exit = function()
+ if me()._mylo then
+ return 'В мыле? Нет...', false
+ end
+ objs():del('face');
+ end
+};
+floor3 = room {
+ nam = 'площадка 3-го этажа',
+ pic = 'gfx/floor3.png',
+ dsc = [[На
+площадке третьего этажа довольно просторно. Бежевые стены. Высокие потолки.]],
+ act = function(s, w)
+ if w == 1 then
+ return 'С минуту я зачарованно смотрю в окно... Белая пустыня погруженная в темноту... В эту минуту я понимаю, в какое чужое место я попал...';
+ end
+ if w == 2 then
+ if not s._unlocked then
+ return 'Металл обитый кожей. Дверь снабжена считывателем электронных карт. Надпись на двери: <<Уровень:3 Категория:Прикладная физика>>';
+ end
+ return goto('cor3');
+ end
+ if w == 3 then
+ return 'Крепкие тут двери, не то что в моей хижине... Считыватель карточек возле замка. Надпись на двери: <<Уровень:3 Категория:Нанотехнологии>>';
+ end
+ end,
+ used = function(s,w,ww)
+ if ww ~= 'card' then
+ return 'Это не поможет...';
+ end
+ if w == 2 then
+ s._unlocked = true;
+ s.way:add('cor3');
+ return goto('cor3');
+ end
+ if w == 3 then
+ return 'Я подношу карточку к считывателю... Раздается раздражающий писк -- доступ не разрешен.';
+ end
+ end,
+ obj = {
+ vobj(1, 'окно', 'Широкое {окно} выходит на запад.'),
+ vobj(2, 'коричневая дверь', 'Справа от окна находится коричневая {дверь}.'),
+ vobj(3, 'белая дверь', 'Слева -- белая {дверь}.'),
+ },
+ way = { 'lift' },
+};
+
+britva = obj {
+ nam = 'бритва',
+ dsc = 'На умывальнике лежит безопасная {бритва}.',
+ tak = 'Я незаметно кладу бритву в карман.',
+ inv = 'Бритва, немного ржавое лезвие...',
+};
+
+face = obj {
+ nam = 'лицо',
+ dsc = 'В зеркале отражается мое {лицо}.',
+ act = function(s)
+ local st = '';
+ if me()._brit then
+ st = ' Гладко выбритое.';
+ elseif me()._mylo then
+ st = ' Все в мыле.';
+ end
+ if galstuk._wear then
+ st = st..' К тому же, в галстуке.';
+ end
+ return 'Это мое лицо, отраженное в зеркале.'..st;
+ end,
+ used = function(s, w)
+ if w == 'mylo' then
+ if me()._brit then
+ return 'Я уже брился...';
+ end
+ if not mylo._pena then
+ return 'Мыло совсем сухое...';
+ end
+ if not have('britva') then
+ return 'Я намыливаю лицо и смываю грязь... Фуххх....';
+ end
+ me()._mylo = true;
+ return 'Я намыливаю лицо...';
+ end
+ if w == 'britva' then
+ if me()._brit then
+ return 'Я уже брился...';
+ end
+ if not me()._mylo then
+ return 'Я не намылил лицо...';
+ end
+ me()._brit = true;
+ me()._mylo = false;
+ return 'Я бреюсь... Через несколько минут я смываю мыло...';
+ end
+ end
+};
+
+tzerkalo = obj {
+ nam = 'зеркало',
+ dsc = 'Над умывальником установлено {зеркало}.',
+ act = function(s)
+ local st = '';
+ objs():add('face');
+ if galstuk._wear then
+ st = ' К тому же, в галстуке...';
+ end
+ if me()._brit then
+ return 'Грустное, но гладко выбритое лицо.'..st;
+ end
+ return 'Дикое, заросшее щетиной лицо смотрит из зеркала.'..st;
+ end,
+};
+
+toilet = room {
+ nam = 'туалет',
+ pic = 'gfx/toil4.png',
+ dsc = 'Довольно просторный туалет. Белый кафель. Желтые разводы. Сырость и звуки журчащей воды. Деревянная дверь ведет в коридор.',
+ enter = function(s, f)
+ if f == 'eroom' then
+ return 'Я лезу в вентиляционное отверстие. Внутри пыльно и тихо. Я блуждаю по причудливым переплетениям вентиляции пока, наконец, не вижу над головой свет. Еще мгновение и я выталкиваю железную решетку в полу туалета...';
+ end
+ end,
+ act = function(s, w)
+ if w == 2 then
+ return 'Да... Мне повезло, я чувствую, что туалет мужской...';
+ end
+ if w == 3 then
+ return 'Странная у них система вентиляции, но благодаря ей я здесь!...';
+ end
+ end,
+ obj = {
+ vobj(2, 'унитазы', 'В этом туалете установлено всего 2 {унитаза}.'),
+ 'umyvalnik',
+ 'britva',
+ 'tzerkalo',
+ 'sushka',
+ vobj(3, 'решетка', 'На полу находится железная {решетка}.'),
+ },
+ way = { 'eroom', 'cor4'},
+ exit = function(s, t)
+ if me()._mylo then
+ return 'В мыле? Нет...', false
+ end
+ objs():del('face');
+ if t ~= 'eroom' then
+ return 'Я осторожно выхожу из туалета.';
+ end
+ end
+};
+
+toiletw = room {
+ nam = 'женский туалет',
+ enter = function(s, w)
+ return 'Фууххх... Чуть не ошибся...', false;
+ end
+};
+
+function room4x_hear()
+ local ph = {
+ [1] = '...Согласно соотношению неопределенностей мы не можем одновременно измерить координату частицы и ее импульс...',
+ [2] = '...Мгновенная передача возмущения волновой функции не есть передача сигнала, ибо здесь нет физических объектов, движущихся быстрее света...',
+ [3] = '...Редукция фон Неймана — мгновенное изменение описания квантового состояния (волновой функции) объекта, происходящее при измерении...',
+ [4] = '...Допустим, две одинаковые частицы A и B образовались в результате распада третьей частицы C. В этом случае, по закону сохранения импульса, их суммарный импульс p_A + p_B должен быть равен исходному импульсу третьей частицы p_C...',
+ [5] = '...представим себе, что на двух планетах в разных концах Галактики есть две монетки, выпадающие всегда одинаково. Если запротоколировать результаты всех подбрасываний, а потом сравнить их, то они совпадут. Сами же выпадания случайны, на них никак нельзя повлиять. Нельзя, например, договориться, что орёл — это единица, а решка — это ноль, и передавать таким образом двоичный код. Ведь последовательность нулей и единиц будет случайной и на том и на другом <<конце провода>> и не будет нести никакого смысла...';
+ [6] = '...Впервые ЭПР-парадокс был сформулирован Альбертом Эйнштейном в 1928 году на 5-ом Сольвеевском конгрессе, в дискуссии с Нильсом Бором. Эйнштейн не признавал вероятностного характера квантовой механики и считал вероятностное описание микромира неполным...',
+ [7] = '...это интерпретация квантовой механики, которая предполагает существование <<параллельных вселенных>>, в каждой из которых действуют одни и те же законы природы и которым свойственны одни и те же мировые постоянные, но которые находятся в различных состояниях...',
+ [8] = 'Докторская работа Эверетта как раз и предлагала подобную альтернативу. Эверетт предложил считать, что для составной системы (каковой является частица, взаимодействующая с измерительным прибором) утверждение о том, что какая-либо подсистема находится в определённом состоянии, является бессмысленным. Это привело Эверетта к заключению об относительном характере состояния одной системы по отношению к другой...',
+ [9] = '...Этот шестимерный объект можно представить в виде суперпозиции двух <<альтернативных историй>> системы S, в одной из которых наблюдался результат измерения <<вверх>>, а в другой — <<вниз>>...',
+ [10] = '...Например, можно приготовить две частицы, находящиеся в едином квантовом состоянии так, что когда одна частица наблюдается в состоянии со спином, направленным вверх, то спин другой оказывается направленным вниз, и наоборот, и это несмотря на то, что согласно квантовой механике, предсказать, какие фактически каждый раз получатся направления, невозможно...',
+ };
+ return ph[rnd(10)];
+end
+
+room4x = room {
+ nam = 'комната',
+ enter = function(s, f)
+ if s._num == 1 then
+ return 'Я осторожно берусь за ручку и пытаюсь открыть дверь. Закрыто...', false;
+ elseif s._num == 2 then
+ return 'Я подхожу к двери и прислушиваюсь... -- '..room4x_hear()..' --- Ухх... Я отхожу от двери..', false;
+ elseif s._num == 3 then
+ return 'Я подхожу к двери и прислушиваюсь... -- Внутри я слышу, как кто-то ожесточенно спорит... -- я отхожу от двери...', false;
+ elseif s._num == 4 then
+ return 'Открыв дверь я захожу внутрь. На меня пристально смотрят 12 пар глаз сидящих за столами. . Еще одна пара глаз принадлежит человеку у доски. -- Простите, ошибся -- бормочу я и выхожу из комнаты...', false;
+ elseif s._num == 5 then
+ return 'Закрыто... ', false;
+ end
+ end,
+};
+
+galstuk = obj {
+ nam = function(s)
+ if s._gal then
+ return 'галстук';
+ end
+ return 'тряпка';
+ end,
+ inv = function(s, w)
+ if not s._gal then
+ s._gal = true;
+ return 'Я рассматриваю тряпку и понимаю, что когда-то это было галстуком.';
+ end
+ if s._hot then
+ if not s._wear then
+ s._wear = true;
+ return 'Я с достоинством надеваю галстук...';
+ end
+ return 'Галстук надет...';
+ end
+ if s._mylo then
+ return 'Он весь в мыле!';
+ end
+ if not s._water then
+ return 'Он грязный! Я не надену это!';
+ end
+ if not s._hot then
+ return 'Он мокрый! Я не надену это!';
+ end
+ end,
+ used = function(s, w)
+ if s._wear then
+ return 'Галстук надет...';
+ end
+ if w == 'mylo' then
+ if not mylo._pena then
+ return 'Мыло сухое...';
+ end
+ s._mylo = true;
+ if not s._gal then
+ s._gal = true;
+ return 'Намыливая тряпку, я понимаю, что когда-то это было галстуком.';
+ end
+ return 'Я намылил галстук...';
+ end
+ end,
+ use = function(s, w)
+ if s._wear and w ~= 'hand' then
+ return 'Галстук надет...', false;
+ end
+ if w == 'umyvalnik' then
+ if not s._mylo then
+ return 'Просто водой? Вряд ли это отмоет мел...';
+ end
+ s._water = true;
+ s._mylo = false;
+ return 'Я помыл галстук в теплой воде...';
+ end
+ if w == 'sushka' then
+ if not s._water then
+ return 'Зачем мне сушить это?';
+ end
+ s._hot = true;
+ s._water = false;
+ return 'Через 5 минут я полностью высушил галстук...';
+ end
+ end
+};
+
+room46 = room {
+ nam = 'аудитория 6',
+ pic = 'gfx/room4.png',
+ enter = 'Я открываю дверь и вхожу внутрь... Комната пуста...',
+ dsc = 'Я нахожусь внутри аудитории... Несколько столов стоят в два ряда по направлению к доске.',
+ act = function(s, w)
+ if w == 1 then
+ if not have('galstuk') then
+ inv():add('galstuk');
+ return 'На доске лежит тряпка. Я беру ее в руки.';
+ end
+ return 'Гм... Ничего не понимаю...';
+ end
+ if w == 2 then
+ return 'Внизу я вижу, как следы прожекторов шарят по снежному полю...';
+ end
+ if w == 3 then
+ return 'Я сажусь за клавиатуру, но вовремя вспоминаю, что я завязал с прошлым... Я больше не хакер - я лесник.';
+ end
+ end,
+ obj = {
+ vobj(3,'терминал', 'На каждом столе стоит {терминал}.'),
+ vobj(1,'доска', 'На {доске} написаны какие-то формулы...'),
+ vobj(2,'окно', '{Окно} выходит на восток.'),
+ 'portrait',
+ },
+ way = { 'cor4' },
+};
+
+facectrl = dlg {
+ nam = 'фэйсконтроль',
+ pic = 'gfx/guard4.png',
+ dsc = 'Я вижу перед собой неприятное лицо полного охранника.',
+ obj = {
+ [1] = phr('Я пришел послушать лекцию Белина...',
+ '-- Я не знаю кто вы -- ухмыляется охранник -- но мне велели пускать сюда только приличных людей.',
+ [[pon(2);]]),
+ [2] = _phr('У меня есть приглашение!',
+ '-- А мне плевать! Посмотри на себя в зеркало!!! Ты пришел слушать самого Белина -- правую руку самого... -- охранник почтительно помолчал -- Так что пошел вон..', [[pon(3,4)]]),
+ [3] = _phr('Сейчас я дам тебе по роже!', '-- Ну все... Мощные руки выталкивают меня в коридор...',
+ [[poff(4)]]),
+ [4] = _phr('Ты, кабан! Я же тебе сказал -- у меня есть приглашение!',
+ '-- Чтоооооо? Глаза охранника наливаются кровью... Мощный пинок отправляет меня в коридор...',
+ [[poff(3)]]),
+ [5] = _phr('Я хочу послушать лекцию Белина...',
+ '-- Во-первых -- доктора Белина, а во-вторых -- без галстука нельзя...',
+ [[pon(2)]]),
+ [6] = _phr('Я очень хочу послушать лекцию доктора Белина!!!',
+ 'Охранник смотрит на меня пристальным взглядом и нехотя произносит. -- Ваше приглашение...',
+ [[pon(7)]]),
+ [7] = _phr('Держи... св... пожалуйста...', 'Ладно... Проходите, не задерживайтесь... Лекция уже началась...',
+ [[inv():del('invite'); return goto('hall42')]]);
+ },
+ exit = function(s,w)
+ s:pon(1);
+ end
+};
+
+hall42 = room {
+ nam = 'Зал 2',
+ pic = 'gfx/hall2.png',
+ dsc = 'Множество людей. Судя по тишине -- лекция уже идет.',
+ obj = {
+ vobj(1, 'Белин', 'Перед доской стоит {Белин} -- тот самый человек, который забрал моего кота.'),
+ vobj(2, 'места', 'В третьем ряду с краю я вижу несколько свободных {мест}.'),
+ vobj(3, 'окно', 'Три широких {окна} выходят на запад.'),
+ vobj(4, 'лампы', 'Зал освещают флоуресцентные {лампы}.'),
+ },
+ act = function(s, w)
+ if w == 1 then
+ return 'Сейчас он без пальто и шляпы и я могу его рассмотреть... Довольно полный, но высокий... Хитрая улыбка, но лицо открытое... Он ведет лекцию -- подожду пока она закончится и поговорю с ним...';
+ end
+ if w == 2 then
+ return goto('lection');
+ end
+ if w == 3 then
+ return 'За окнами тьма... Только белые снежинки изредка попадают в зону освещения флоуресцентных ламп.';
+ end
+ if w == 4 then
+ return 'Шесть ламп... Ненавижу этот мерцающий свет...';
+ end
+ end,
+ exit = function(s, t)
+ if t == 'cor4' then
+ return 'Не хочу терять Белина из виду...', false;
+ end
+ end,
+ enter = function(s, f)
+ if f == 'facectrl' then
+ return 'Я прохожу в лекционный зал...';
+ end
+ if not galstuk._wear then
+ facectrl:pon(5);
+ facectrl:poff(1);
+ end
+ if not me()._brit or not galstuk._wear then
+ return cat(
+'Я захожу в зал, когда меня останавливает человек в форме с надписью <<ОХРАНА>>. В его руках помповое ружье.^^', goto('facectrl')), false;
+ end
+ facectrl:poff(1, 5);
+ facectrl:pon(6);
+ return goto('facectrl'), false;
+ end,
+ way = { 'cor4' },
+};
+
+hall41 = room {
+ nam = 'Зал 1',
+ dsc = [[Я захожу в пустой зал. Похоже -- это один из залов для проведения лекций. Множество мест уходят
+под небольшим уклоном к потолку.]],
+ pic = 'gfx/hall1.png',
+ act = function(s, w)
+ if w == 1 then
+ return 'Глядя в ночную темноту я с тоской вспоминаю Барсика...';
+ end
+ if w == 2 then
+ return 'Примерно такие были у нас в институте, когда я... Ладно...';
+ end
+ if w == 3 then
+ return 'Все, что я мог бы вспомнить я благополучно забыл.';
+ end
+ end,
+ obj = {
+ vobj(1, 'окна', 'Три больших {окна} выходят на западную сторону.'),
+ vobj(2, 'стол', 'Длинный {стол} стоит перед доской.'),
+ vobj(3, 'доска', 'На {доске} видны следы формул прошлой лекции.'),
+ 'portrait',
+ },
+ way = {
+ 'cor4',
+ },
+};
+
+cor4 = room {
+ nam = 'коридор 4-го этажа',
+ pic = 'gfx/cor4.png',
+ dsc = 'Я нахожусь в коридоре. Потолки на этом этаже очень высокие. В конце коридора находятся туалеты. Под ногами -- ковровая дорожка зеленого цвета.',
+ act = function(s, w)
+ if not tonumber(w) then
+ return;
+ end
+ if w == 11 then
+ return 'Некоторые из них заходят в зал 2.';
+ end
+ if w == 1 then
+ return 'Я тоскливо гляжу в ночную тьму... Я понимаю -- что очень устал... Но я должен идти...';
+ end
+ if w == 12 then
+ return 'Эта дверь, как и многие здесь, снабжена считывателем смарткарт. На нем горит красная лампочка.';
+ end
+ if tonumber(w) >=5 and tonumber(w) <=9 then
+ room4x._num = w - 4;
+ return goto('room4x');
+ end
+ if w == 10 then
+ ways():add('room46');
+ return goto('room46');
+ end
+ if w == 2 then
+ ways():add('hall41');
+ return goto('hall41');
+ end
+ if w == 3 then
+ ways():add('hall42');
+ return goto('hall42');
+ end
+ end,
+ used = function(s, w, ww)
+ if w == 12 and ww == 'card' then
+ return 'Я подношу карточку к считывателю... Биип... Доступ не разрешен...';
+ end
+ end,
+ obj = {
+ vobj(1, 'окно', '{Окно} выходит на юг.'),
+ vobj(2, 'зал 1','На западной стороне я вижу два широких дверных проема: {зал 1},'),
+ vobj(3, 'зал 2', '{зал 2}.'),
+ vobj(5, 'аудитория 1', 'На восточной стороне расположены двери поменьше. Надписи на дверях: {аудитория 1},'),
+ vobj(6, 'аудитория 2', '{аудитория 2},'),
+ vobj(7, 'аудитория 3', '{аудитория 3},'),
+ vobj(8, 'аудитория 4', '{аудитория 4},'),
+ vobj(9, 'аудитория 5', '{аудитория 5},'),
+ vobj(10, 'аудитория 6', '{аудитория 6}.'),
+ vobj(11, 'люди', 'Время от времени в коридоре появляются {люди}.'),
+ vobj(12, 'входная дверь', 'Входная {дверь} находится на северном конце коридора.'),
+ 'portrait',
+ },
+ way = {
+ 'toilet',
+ 'toiletw',
+ }
+};
+floor4 = room {
+ nam = 'площадка 4-го этажа',
+ pic = 'gfx/floor4.png',
+ dsc = 'На четвертом этаже высокие потолки.',
+ act = function(s, w)
+ if w == 1 then
+ return 'Тьма... Нет ни одного огонька... Я даже не вижу звезд, тусклый, но тягостный свет ламп дневного освещения мешает их увидеть...';
+ end
+ if w == 2 then
+ return 'Я ненавижу лифты...';
+ end
+ if w == 3 or w == 4 then
+ return 'Обычная дверь для этого здания. Электронный замок. Без карточки я не пройду.';
+ end
+ end,
+ used = function(s, w, ww)
+ if ww == 'card' then
+ if w == 3 or w == 4 then
+ return [[Я подношу карточку к считывателю. Бииип... В доступе отказано...]];
+ end
+ end
+ end,
+ obj = {
+ vobj(1, 'окно','{Широкое} окно смотрит на запад.'),
+ vobj(2, 'лифты', 'Площадка с четырьмя {лифтами} тускло освещена лампами.'),
+ vobj(3, 'южная дверь', 'Две двери ведут в северный и южный коридоры. Надпись на южной {двери}: <<уровень:4 категория:теоретическая физика>>'),
+ vobj(4, 'северная дверь', 'На северной {двери}: <<уровень:4 категория: биология>>'),
+ },
+ way = { 'lift' },
+};
+
+floor5 = room {
+ nam = 'площадка 5-го этажа',
+ pic = 'gfx/floor5.png',
+ dsc = [[Потолки на пятом этаже очень высокие.]],
+ act = function(s, w)
+ if w == 1 then
+ return 'Мои ноги утопают в красном бархате... Не наследить бы...';
+ end
+ if w == 2 then
+ return 'Нет, все-таки это хрусталь...';
+ end
+ if w == 3 then
+ return 'Я подхожу к окну... Любопытно, я вижу, что окно выходит на довольно широкий участок крыши, который проходит через фронтальную часть здания...';
+ end
+ if w == 4 or w == 5 then
+ return 'Изучить двери мне мешает охранник... А мой пропуск здесь не подойдет...';
+ end
+ if w == 6 then
+ return 'Пока он не обращает на меня внимания, но все-равно не стоит нарываться...';
+ end
+ end,
+ used = function(s, w)
+ if not tonumber(w) then
+ return
+ end
+ if w == 6 then
+ return 'Не надо его раздражать...';
+ end
+ if w >=1 and w <=5 then
+ return 'Я не буду делать это при охраннике.';
+ end
+ end,
+ obj = {
+ vobj(1, 'ковер', 'Лифтовую площадку покрывает красный {ковер}.'),
+ vobj(2, 'люстра', 'Хрустальная {люстра} висит на высоком потолке.'),
+ vobj(3, 'окно', 'Широкое {окно} выходит на запад.'),
+ vobj(4, 'информация', 'Я вижу две двери, ведущие в южный и северный коридоры. На южной {двери} написано: <<уровень 5, категория: информация>>.'),
+ vobj(5, 'красная дверь', 'На северной {двери} нет надписей. Это массивная дверь, обитая красной кожей.'),
+
+ vobj(6, 'охранник', 'Между проходами в коридоры установлен стол, за котором сидит {охранник},');
+ },
+ way = { 'lift' },
+};
+
diff --git a/games/cat/ep3.lua b/games/cat/ep3.lua
new file mode 100644
index 0000000..4a01b11
--- /dev/null
+++ b/games/cat/ep3.lua
@@ -0,0 +1,1642 @@
+lection = room {
+ nam = 'Лекция Белина',
+ pic = 'gfx/lection.png',
+ dsc = [[Я пробираюсь к месту и сажусь... Отсюда хорошо слышно -- послушаем именитого физика... -- Думаю я... ^^Итак, в ноябре 1935г. Шредингер опубликовал статью,
+в которой проводился следующий мысленный эксперимент -- продолжал Белин --
+в чем суть эксперимента? -- С этими словами Белин вытащил и поставил на стол
+ящик странного вида -- Люблю опыты -- белоснежная улыбка тускло блеснула в свете ламп --
+Как вы можете видеть это ящик -- Белин похлопал ладонью
+по гладкой поверхности. -- В ящик встроена капсула с ядовитым газом
+Кроме того, в статико-динамическом поле ящика находятся счетчик радиации,
+изотопный элемент и таймер. Параметры эксперимента подобраны так, что вероятность того, что ядро распадётся за 1 час, составляет 50%.^^
+
+
+Если ядро распадается, оно приводит механизм в действие, он открывает ёмкость с газом. --
+Пока все просто -- не так ли, господа? -- Улыбается Белин -- но дело в том,
+что Шредингер в своем эксперименте помещает в ящик кота -- живое существо. ^^
+
+Согласно квантовой механике, если над ядром не производится наблюдения, то его состояние описывается суперпозицией (смешением) двух состояний — распавшегося ядра и нераспавшегося ядра, следовательно, кот, сидящий в ящике, и жив, и мёртв одновременно. -- Белин повышает голос. -- можно сказать, что это просто игры разума, отвлеченная лирика, но я покажу и докажу, что это не совсем так... ^^
+
+-- Итак, если ящик открыть, то экспериментатор обязан увидеть только какое-нибудь одно конкретное состояние — <<ядро распалось, кот мёртв>> или <<ядро не распалось, кот жив>>. Сам Шредингер думал, что его парадокс доказывает несостоятельность квантовой механики, но мы то с вами знаем, что квантовая механика и есть истинное представление о нашем мире -- снова повышает тон голоса Белин -- и вот независимо друг от друга, что доказывает отчасти истинность предположения -- Ганс Моравек в 1987 и Бруно Маршал в 1988 рассмотрели ситуацию с точки зрения самого кота!^^
+
+-- Если верна многомировая интерпретация Эверетта, то в результате каждого проведенного эксперимента с котом вселенная расщепляется на две вселенных, в одной из которых кот остается жив, а в другой погибает. В мирах, где кот умирает, он перестает существовать. Напротив, с точки зрения неумершего кота, эксперимент будет продолжаться, не приводя к исчезновению кота. Это происходит потому, что в любом ответвлении кот способен наблюдать результат эксперимента лишь в том мире, в котором он выживает. И если многомировая интерпретация верна, то кот может заметить, что он никогда не погибнет в ходе эксперимента... -- Белин замолкает и осматривает зал... ^^
+
+-- Но что вытекает из этого, господа? Я спрашиваю, что из этого вытекает? -- Представим, что участник эксперимента взрывает ядерную бомбу вблизи себя. С точки зрения многомировой интерпретации, практически во всех параллельных вселенных ядерный взрыв уничтожит участника. Но несмотря на это, должно существовать небольшое множество альтернативных вселенных, в которых участник каким-либо образом выживает. И мы переходим к идее -- Белин снова поднял голос -- идее квантового бессмертия!!! ^^
+
+-- Идея квантового бессмертия состоит в том, что участник остаётся в живых, и тем самым способен воспринимать окружающую реальность, по меньшей мере в одной из вселенных в множестве, пусть даже количество таких вселенных пренебрежимо мало в сравнении с количеством всех возможных вселенных. Таким образом, со временем участник обнаружит, что он может жить вечно!!! ^^
+
+Мы все с вами тяжело работали этот год, под четким руководством... -- тут Белин бросил взгляд в сторону портретов -- и должен вам сказать, что информации в нашем информационном центре -- Белин посмотрел в потолок -- достаточно, чтобы доказать, я повторяю, научно доказать теоретически и экспериментально истинность многомировой интерпретации... -- Но что это значит для нас? -- Вы не можете этого видеть, но -- Белин смотрит на часы -- уже через несколько минут состав с ураном прибывает к задним воротам института... Урана хватит для того, чтобы обеспечить каждого из вас ядерной бомбой. Так как вы скоро убедитесь в том, что квантовое бессмертие это реальность, то каждый из нас сможет стать непобедимым террористом!!! Вселенная расщепится на множество миров, в каждом из который Вы -- палец Белина указывает в зал -- будете его диктатором и господином!!! -- Белин почти кричал...^^
+
+Зал не выдержал и взревел. Люди вставали и хлопали... Их глаза горели каким-то бешеным огнем... О Боже, подумал я -- это какое-то наваждение... Мои ноги не слушались меня -- я сидел на своем месте и не мог пошевелиться...^^
+
+Но я отвлекся -- говорит Белин -- продолжим наш опыт. С этими словами он достал из под стола живой комочек... Это был мой Барсик... -- Сейчас я помещу эту кошку в ящик и мы с вами... -- красная пелена застилает мои глаза...
+ ]],
+ enter = function(s)
+ -- end of episode 2
+ eside = nil;
+ moika = nil;
+ eating = nil;
+ kitchen = nil;
+ stolcorridor = nil;
+ entrance = nil;
+ floor2 = nil;
+ eroom = nil;
+ room33 = nil;
+ room3x = nil;
+ cor3 = nil;
+ toilet3 = nil;
+ floor3 = nil;
+ toilet = nil;
+ toiletw = nil;
+ room4x = nil;
+ room46 = nil;
+ hall42 = nil;
+ hall41 = nil;
+ floor4 = nil;
+ floor5 = nil;
+ povardlg = nil;
+ kitchendlg = nil;
+ facectrl = nil;
+ end,
+ act = function(s, w)
+ if w == 1 then
+ set_music("mus/under.s3m");
+ return goto('escape1');
+ end
+ end,
+ obj = {
+ vobj(1, 'дальше', '{Дальше}'),
+ };
+};
+
+profdlg = dlg {
+ nam = '!!!',
+ pic = 'gfx/me.png',
+ dsc = 'Я собираюсь с силами встаю и во всю глотку кричу...',
+ obj = {
+ [1] = phr('Это кот, а не кошка!',
+ '-- Рука Белина останавливается -- его взгляд фокусируется на мне -- он узнает меня!! -- Охрана -- в зале посторонний!!! Убе... Уберите его!!! -- кричит он..',
+ [[poff(2);escape1.obj:add('guardian')]]),
+ [2] = phr('Не трогай моего кота!',
+ '-- Белин замирает, затем смотрит мне прямо в глаза -- его лицо выражает удивление -- Охрана!!! Охрана!!! В зале посторонний!!!',
+ [[poff(1);escape1.obj:add('guardian')]]),
+ },
+};
+
+profdlg2 = dlg {
+ nam = 'Белин',
+ pic = 'gfx/prof2.png',
+ dsc = 'Белин бледен. Он смотрит на дробовик рассеянным взглядом.',
+ obj = {
+ [1] = phr('Я пришел за своим котом.',
+ 'Я выхватываю Барсика из руки Белина и засовываю себе за пазуху.',
+ [[inv():add('mycat'); lifeon('mycat')]]),
+ [2] = phr('Скажи им, что бы расходились!!!',
+ '-- Белин бледен, похоже он не понимает меня..',
+ [[pon(3)]]),
+ [3] = _phr('Ну же!!! Скажи им, чтобы расходились...', 'Я трясу его. Белин не чувствует, он лишь смотрит на черные стволы дробовика.',[[pon(3); back();]]);
+ },
+};
+gdlg1 = dlg {
+ nam = 'охранник',
+ pic = 'gfx/guard42.png',
+ dsc = 'Я кричу охраннику и не узнаю свой голос...',
+ obj = {
+ [1] = phr('Положи свое ружье прикладом вперед на стол и толкни его сюда..',
+ 'Охранник неуверенно смотрит на меня..',
+ [[pon(2)]]),
+ [2] = _phr('Я сказал на стол ружье!!! -- я посильнее надавливаю стволами на Белина -- он близок к обмороку.', 'Охранник оторожно кладет помповое ружье на стол и толкает его ко мне... -- я быстро забираю ружье. Теперь в левой руке у меня обрез, в правом -- помповое ружье.',
+ [[pon(3); inv():add('shotgun')]]),
+ [3] = phr('Не нравилось тебе мое лицо да?? Дааа???',
+ 'Охранник молчит, на его лбу выступает пот...',
+ [[pon(3); back();]]),
+ };
+};
+
+shotgun = obj {
+ nam = 'ружье',
+ inv = 'Помповое ружье... На 6 зарядов. Интересно, сколько там осталось?',
+ dsc = 'На полу валяется помповое {ружье}.',
+ tak = function(s)
+ if s._unloaded then
+ return 'Оно мне больше не нужно. Полностью разряжено.', false
+ end
+ return 'Я беру свое ружье обратно.';
+ end,
+};
+
+guardian = obj {
+ nam = 'охранник',
+ dsc = function(s, w)
+ if not professor._gun then
+ return 'Я вижу как {охранник} с помповым ружьем медленно, но верно пробирается к моему месту.';
+ end
+ if have('shotgun') then
+ return 'Я вижу обезоруженного {охранника}, внимательно смотрящего на меня.';
+ end
+ return 'Я вижу {охранника}, неуверенно держащего в руках помповое ружье.';
+ end,
+ act = function(s, w)
+ if not professor._gun then
+ return 'Скоро он доберется до меня...';
+ end
+ return goto('gdlg1');
+ end,
+ used = function(s, w)
+ if w == 'shotgun' then
+ return 'Нет, я не могу пойти на это...';
+ end
+ if w == 'gun' then
+ if not professor._gun then
+ return 'Мой обрез не для дальнего боя...';
+ end
+ return 'Я опасаюсь отводить обрез от Белина, к тому же, потом мне придется его перезаряжать...';
+ end
+ end
+};
+
+professor = obj {
+ nam = 'Белин',
+ dsc = function(s, w)
+ if not s._gun then
+ return 'Перед доской стоит {Белин} и держит в руке моего Барсика.';
+ end
+ return 'Я упираюсь обоими стволами дробовика в грудь {Белина}.';
+ end,
+ act = function(s)
+ if not s._gun then
+ return goto('profdlg');
+ end
+ return goto('profdlg2');
+ end,
+ used = function(s, w)
+ if w == 'gun' then
+ if s._gun then
+ return 'Я еще сильнее надавливаю обоими стволами на грудь Белина.';
+ end
+ s._gun = true;
+ objs():add('guardian');
+ gun._hidden = false;
+ return 'Я достаю обрез из-под одежды и, перепрыгивая через стол, бросаюсь к Белину.';
+ end
+ end,
+};
+pdlg = dlg {
+ nam = 'люди',
+ pic = 'gfx/me.png',
+ dsc = 'Я смотрю в зал и кричу...',
+ obj = {
+ [1] = phr('Вас обманывают!!! Никакого доказательства нет!!!',
+ '-- никакой реакции...',[[pon(2)]]),
+ [2] = _phr('Мир един!!! Каждый из вас знает об это с детства!!! Уходите от сюда!! Бегите от этих сектантов!!!', ' -- ответом мне было молчание...'),
+ [3] = phr('Стадо баранов!!! Неужели вас так легко обмануть???',
+ '-- они молчат -- и мне не нравится их взгляды...',
+ [[pon(3); back();]]),
+ },
+};
+narod = obj {
+ nam = 'люди',
+ dsc = function(s)
+ if not professor._gun then
+ if seen('guardian') then
+ return '{Люди} в зале смотрят на меня с недоумением. Они в замешательстве.';
+ end
+ return '{Люди} в зале следят за Белиным.';
+ end
+ return '{Люди} в зале замерли. Они не спускают с меня взгляд. Если я ошибусь -- мне конец... И всему миру...';
+ end,
+ act = function(s)
+ if professor._gun then
+ return goto('pdlg');
+ end
+ if seen('guardian') then
+ return 'Пока они на меня не бросились и это хорошо...';
+ end
+ return 'Фанатики, они фанатики...';
+ end,
+ used = function(s, w)
+ if w == 'gun' or w =='shotgun' then
+ return 'Я думаю, что патронов не хватит.';
+ end
+ return 'Увы...';
+ end
+};
+
+win = obj {
+ nam = 'окно',
+ dsc = function(s)
+ local st = '';
+ if s._broken then
+ st = ' Одно из окон разбито.';
+ end
+ return 'Три широких {окна} выходят на запад.'..st;
+ end,
+ act = 'За окнами тьма... Только белые снежинки изредка попадают в зону освещения флоуресцентных ламп.';
+ used = function(s, w)
+ if w ~= 'gun' and w ~= 'shotgun' then
+ return 'Не поможет...';
+ end
+ if s._broken then
+ return 'Уже разбито...';
+ end
+ if not have('shotgun') then
+ return 'Охранник подстрелит меня..';
+ end
+ s._broken = true;
+ ways():add('window');
+ return 'Я разбиваю прикладом ближайшее окно...';
+ end
+};
+
+escape1 = room {
+ nam = 'Зал 2',
+ dsc = 'Я нахожусь в зале. Люди в зале ждут продолжения эксперимента.',
+ pic = function()
+ if professor._gun then
+ return 'gfx/meandgun.png';
+ end
+ return 'gfx/lection2.png';
+ end,
+ obj = {
+ 'win',
+ vobj(4, 'лампы', 'Зал освещают флоуресцентные {лампы}.'),
+ 'professor',
+ 'narod',
+ vobj(5, 'ящик', 'На столе стоит {ящик}.'),
+ 'portrait',
+ },
+ act = function(s, w)
+ if w == 5 then
+ return 'Проклятая коробка...';
+ end
+ if w == 4 then
+ return 'Шесть ламп... Ненавижу этот мерцающий свет...';
+ end
+ end,
+ used = function(s, w, ww)
+ if ww == 'gun' or ww == 'shotgun' then
+ if not professor._gun then
+ return 'Не стоит...';
+ end
+ if w == 4 then
+ return 'Темнота поможет не только мне, но и им... А их больше...';
+ end
+ if w == 5 then
+ return 'Там яд. Я боюсь навредить моему Барсику.';
+ end
+ end
+ end,
+ exit = function(s, t)
+ if t == 'window' and not have('mycat') then
+ return 'А как же Барсик?', false
+ end
+ if t == 'cor4' then
+ return 'Я должен что-то сделать сейчас же!', false;
+ end
+ end,
+ way = { 'cor4' },
+};
+lest = obj {
+ nam = function(s, w)
+ if s._seen then
+ return 'лестница';
+ else
+ return 'нечто';
+ end
+ end,
+ dsc = function(s, w)
+ if s._seen then
+ return 'За метелью я едва различаю пожарную {лестницу}!';
+ end
+ return 'За метелью я едва различаю контуры какой-то {конструкции}.';
+ end,
+ act = function(s, w)
+ if not s._seen then
+ ways():add('ladder');
+ s._seen = true;
+ return 'Это же пожарная лестница!!!';
+ end
+ return 'Прыгать лили нет? Вот в чем вопрос...';
+ end,
+};
+
+window = room {
+ nam = function(s)
+ if here() == window then
+ return 'на подоконнике';
+ end
+ return 'в окно';
+ end,
+ pic = 'gfx/fromwin1.png',
+ enter = "Это безумие, но все-же я бросаюсь к окну... За спиной я слышу рев толпы...";
+ dsc = 'Я стою на подоконнике и всматриваюсь в ночную пустоту.',
+ obj = {
+ 'lest',
+ },
+ exit = function(s, t)
+ if t == 'escape1' then
+ return 'Мне нельзя назад... Там толпа фанатиков...', false;
+ end
+ end,
+ way = { 'escape1',},
+};
+
+down = room {
+ nam = 'вниз';
+};
+
+window5 = obj {
+ nam = 'окно',
+ dsc = function(s, w)
+ if s._broken then
+ return 'Слева от меня, разбитое {окно}.';
+ end
+ return 'Слева от меня желтый огонек {окна}.';
+ end,
+ act = function(s)
+ if not s._broken then
+ return 'Окно закрыто...';
+ end
+ return goto('room5');
+ end,
+ used = function(s, w)
+ if w == 'gun' or w == 'shotgun' then
+ if s._broken then
+ return 'Уже разбито...';
+ end
+ s._broken = true;
+ return 'Я выбиваю стекло прикладом... Осколки стекла падают в темноту...';
+ end
+ end
+};
+
+
+up = room {
+ _num = 0;
+ nam = 'наверх',
+ enter = function(s, w)
+ s._num = s._num + 1;
+ if s._num == 2 then
+ lifeon('ladder');
+ return 'Внезапно ночную тьму разрезает луч прожектора и тишину нарушает вой сирены... Похоже, внизу меня заметили...', false;
+ end
+ if s._num > 4 then
+ ladder.way:del('up');
+ ladder.obj:add('window5');
+ end
+ return 'Я медленно ползу вверх...', false;
+ end
+};
+
+ladder = room {
+ nam = 'лестница',
+ pic = 'gfx/ladder.png',
+ dsc = [[Я стою на холодной лестнице. Ледяные иголки снежинок больно ударяются о мое лицо.]],
+ act = function(s, w)
+ if w == 1 then
+ return 'Я скоро окоченею... Надо двигаться..';
+ end
+ end,
+ obj = {
+ vobj(1, 'поручни', 'В моих руках, железные {поручни}.'),
+ };
+ enter = function(s)
+ inv():del('gun');
+ return [[Я разбегаюсь и прыгаю... Несколько секунд мое сердце сжимается, но я чувствую тепло Барсика за пазухой и уже в следующий миг мои руки хватаются за черную сталь... Дробовик срывается с моего плеча и летит вниз...]];
+ end,
+ way = { 'up', 'down' },
+ life = function(s)
+ if rnd(2) == 1 then
+ return 'Я слышу треск автоматных очередей -- несколько пуль проходят совсем рядом...';
+ end
+ end,
+ exit = function(s, t)
+ if t == 'down' then
+ if s._shoot then
+ return 'Меня убьют... И Барсика... И разрушат весь мир...', false;
+ end
+ lifeon('ladder');
+ s._shoot = true;
+ return 'Я начинаю спускаться вниз, когда ночную тьму вдруг разрезает луч прожектора и тишину нарушает вой сирены... Похоже, внизу меня заметили...', false;
+ end
+ if t ~= 'up' then
+ lifeoff('ladder');
+ end
+ end
+};
+
+hand = obj {
+ nam = 'кровавая рука',
+ inv = 'Моя рука кровоточит... Мне кажется, что скоро я потеряю сознание...',
+ life = 'Капли крови падают с моей правой руки на пол...',
+ used = function(s, w)
+ if w == 'galstuk' then
+ inv():del('galstuk');
+ inv():del('hand');
+ lifeoff('hand');
+ return 'Я перевязываю руку галстуком... Пока сойдет...';
+ end
+ end
+};
+
+computers = obj {
+ nam = 'компьютеры',
+ dsc = 'Большую площадь занимают высокие стойки с компьютерным {оборудованием}. Тихое жужжание вентиляторов едва слышно. Нервно подмигивают лампочки сетевого оборудования.';
+ act = function(s)
+ if kover._fire then
+ return 'Ну что же... Гори, зло, гори!!! Пора выбираться отсюда.';
+ end
+ return 'Это оборудование хранит зло... Мне нужно уничтожить все это, но как? Из своего прошлого я знаю, что самый надежный способ уничтожить информацию на магнитных носителях -- провести ее через точку Кюри, другими словами -- сжечь это все к чертям собачьим... Но где мне взять огонь?';
+ end,
+ used = function(s, w)
+ if w == 'shotgun' then
+ return 'Расстрелять серверы? Ненадежно... Я должен сжечь это зло...';
+ end
+ end
+};
+
+poroh = obj {
+ nam = 'порох',
+ inv = 'Этот порох должен мне помочь.',
+};
+
+trut = obj {
+ nam = 'трут',
+ inv = 'Кусок газеты с порохом. Да это же трут!!!',
+ use = function(s, w)
+ if w == 'ibp' and ibp._knife and not ibp._trut then
+ ibp._trut = true;
+ inv():del('trut');
+ return 'Я кладу трут на ИБП.';
+ end
+ end
+};
+fire = obj {
+ nam = 'огонь',
+ inv = 'Бумажка быстро горит... Надо что-то делать!!!',
+ use = function(s, w)
+ if w == 'poroh' then
+ return 'Рванет прямо в руке.';
+ end
+ if w == 'news' then
+ return 'Я отрываю еще кусок от газеты. Пламя перекидывается на него.';
+ end
+ inv():del('fire');
+ if w ~= 'kover' then
+ return 'Бумага догорает и гаснет...';
+ end
+ if kover._fire then
+ return 'Я кидаю бумажку на горящий ковер...';
+ end
+ kover._fire = true;
+ return 'Я кладу бумагу на ковер... Волоски ковра вспыхивают... Похоже начинается пожар..';
+ end
+};
+
+ibp = obj {
+ nam = 'ИБП',
+ dsc = 'Один разобранный {ИБП} валяется на полу.',
+ inv = function(s)
+ if not s._knife then
+ return 'Это источник бесперебойного питания. Что мне с ним делать?';
+ end
+ local st = '';
+ if s._trut then
+ st = ' На батарее лежит бумага с порохом.';
+ end
+ return 'Разобранный ИБП. Я вижу клеммы, ведущие к батарее...'..st;
+ end,
+ act = function(s)
+ if not have('ibp') then
+ if not have('fire') and not kover._fire then
+ take('ibp');
+ return 'Я снова беру ИБП в руки.';
+ end
+ return 'Мне он больше не нужен.';
+ end
+ return s:inv();
+ end,
+ used = function(s, w)
+ if not have('ibp') then
+ return 'Не сработает...';
+ end
+ if w == 'knife' then
+ s._knife = true;
+ return 'Я раскручиваю винты и разбираю ИБП. Теперь я вижу клеммы, ведущие к батарее...';
+ end
+ if w == 'provodki' and s._knife then
+ if not provodki._knife then
+ return 'Проводки не оголены.';
+ end
+ if not s._trut then
+ return 'Я подсоединяю проводки к клеммам и замыкаю усики проводов -- от замыкания проскакивает искра. Нужен трут...';
+ end
+ drop('ibp');
+ ibp._trut = false;
+ inv():add('fire');
+ return 'Я подсоединяю проводки к клеммам и замыкаю усики проводов. Проскакивает искра и перекидывается на трут. Трут вспыхивает!!! Огонь!!!';
+ end
+ if w == 'provod' then
+ return 'Я вставил, а затем снова вытащил провод из ИБП... Хммм...';
+ end
+ end,
+};
+
+provodki = obj {
+ nam = 'тонкие проводки',
+ inv = function(s)
+ if s._knife then
+ return 'Пара тонких проводков с усиками на конце.'
+ end
+ return 'Пара тонких проводков.'
+ end,
+ used = function(s, w)
+ if w == 'knife' and not s._knife then
+ s._knife = true;
+ return 'Я отрезаю изоляцию с концов проводка и достаю тоненькие усики.';
+ else
+ return 'Не сработает...';
+ end
+ end
+};
+
+provod = obj {
+ nam = 'провод от ИБП',
+ inv = 'Это провод от ИБП.',
+ used = function(s, w)
+ if w == 'knife' then
+ if not knife._oster then
+ return 'Лезвие ножа слишком тупое...';
+ end
+ inv():del('provod');
+ inv():add('provodki');
+ return 'Я разрезаю оплетку и достаю две жилы провода.'
+ end
+ end
+};
+
+ups = obj {
+ nam = 'ибп',
+ dsc = 'Множество {источников бесперебойного питания} стоят у каждой стойки.',
+ act = function(s)
+ if have('hand') then
+ return 'У меня поранена рука. Кровь так и хлещет, я не могу таскать ИБП.';
+
+ end
+ if not have('ibp') and not seen('ibp') then
+ inv():add('ibp');
+ inv():add('provod');
+ return 'Немного порывшись я отсоединяю один из источников и держу его в руках...';
+ end
+ return 'Я уже брал один UPS.';
+ end,
+};
+
+kover = obj {
+ nam = 'ковер',
+ dsc = function(s)
+ if s._fire then
+ return '{Ковер} на полу занимается пламенем.';
+ end
+ return 'На полу постелен красный {ковер}.';
+ end,
+ act = 'Ненужная роскошь.',
+};
+
+room5 = room {
+ nam = 'центр информации';
+ pic = 'gfx/servers.png',
+ dsc = [[Я в огромном помещении, занимающем всю южную часть института.]],
+ enter = function(s, f)
+ if f == 'ladder' then
+ set_music('mus/hybrid.xm');
+ lifeon('hand');
+ inv():add('hand');
+ return 'Я прыгаю и хватаюсь за раму окна. Моя правая рука в крови. Не обращая внимания на боль, я спрыгиваю на пол комнаты...';
+ end
+ end,
+ exit = function(s, f)
+ set_music("mus/under.s3m");
+ end,
+ act = function(s, w)
+ if w == 1 then
+ return 'Я не полезу назад... Там холодно и стреляют...';
+ end
+ end,
+ obj = { 'computers', 'ups',
+ vobj(1, 'окно', 'В разбитое {окно} дует холодный зимний ветер.'),
+ 'kover',
+ 'dout',
+ 'portrait',
+ },
+};
+dout = obj {
+ nam = 'дверь',
+ dsc = function(s)
+ return 'Далеко впереди я могу видеть выходную {дверь}.'
+ end,
+ act = function(s)
+ if not kover._fire then
+ return 'Это центр обработки информации. Я должен уничтожить его, чтобы спасти мир от заразы, что хранится в недрах его накопителей...';
+ end
+ return 'Я подбегаю к двери. Дверь ведет на площадку пятого этажа и она электронная!!! Это значит, что открыть я ее могу только с помощью карточки с требуемым уровнем доступа. Я сгорю?';
+ end,
+ used = function(s, w)
+ if not kover._fire then
+ return s:act();
+ end
+ if w == 'card' then
+ return 'Я подношу карточку к двери. Биип -- в доступе отказано! Я сгорю здесь!!!';
+ end
+ if w == 'shotgun' then
+ return goto('escape2');
+ end
+ return 'Не поможет...';
+ end
+};
+
+handgdlg = dlg {
+ nam = 'охранник',
+ pic = 'gfx/handhoh.png',
+ dsc = 'Охранник -- еще молодой парень лет 30 -- смотрит на меня. Он растерян.',
+ obj = {
+ [1] = phr('Отдай мне свое оружие!', '-- Я без оружия -- качает охранник головой... Не знаю верить ему или нет, но обыскивать его мне не хочется...'),
+ [2] = phr('Мне нужен ключ от красной двери.', 'Охранник бледнеет. -- Ни у кого нет ключа от ЭТОЙ двери. -- произносит он. -- Что за чушь? -- Думаю я.'),
+ [3] = phr('Ок! Просто стой и не дергайся.', 'Охранник молча смотрит на меня',
+ [[pon(3);back();]]),
+ },
+};
+
+win5 = obj {
+ nam = 'окно',
+ dsc = function (s)
+ if s._broken then
+ return 'В разбитое {окно} завывает зимний ветер. Снежинки вихрем залетают на этаж.';
+ end
+ return 'Широкое {окно} выходит на запад.';
+ end,
+ act = function(s)
+ if not s._broken then
+ return 'Я подхожу к окну... Любопытно, я вижу, что окно выходит на довольно широкий участок крыши, который проходит через фронтальную часть здания...';
+ end
+ return 'Окно разбито... Третье за сегодня.';
+ end,
+ used = function(s, w)
+ if s._broken then
+ return s:act();
+ end
+ if w == 'shotgun' then
+ s._broken = true;
+ ways():add('krysha');
+ return 'Уххх.... Третье окно за сегодня... Я размахиваюсь и осколки стекла вылетают на крышу...';
+ end
+ end,
+};
+
+escape2 = room {
+ _timer = 0,
+ nam = 'площадка 5-го этажа',
+ pic = 'gfx/floor5e.png',
+ dsc = [[Потолки на пятом этаже очень высокие.]],
+ enter = function(s, f)
+ if f == 'room5' then
+ lifeon('escape2');
+ return 'В бессилии я бью прикладом в ненавистную дверь. И вдруг, через несколько секунд слышу, как кто-то подходит к двери с внешней стороны... Это охранник!!! Писк срабатывания считывателя и вот дверь открывается. Охранник пятится -- ему в грудь упирается ствол помпового ружья. Мы выходим на площадку пятого этажа.';
+ end
+ if f == 'krysha' then
+ lifeon('escape2');
+ end
+ end,
+ life = function(s)
+ s._timer = s._timer + 1;
+ if s._timer == 3 then
+ return 'Внезапно на этаже раздается звук сирены. -- Внимание!!! На пятом этаже лицо с нулевым уровнем допуска. Повторяю... -- льется голос из невидимых динамиков.';
+ end
+ if s._timer > 3 then
+ return '-- На пятом этаже лицо с нулевым уровнем доступа!!! -- от воя сирены меня начинает мутить.';
+ end
+ end,
+ act = function(s, w)
+ if w == 1 then
+ return 'Мои ноги утопают в красном бархате... Проклятая роскошь!';
+ end
+ if w == 2 then
+ return 'Нет, все-таки это хрусталь...';
+ end
+ if w == 4 then
+ return 'Пожар уже начался...';
+ end
+ if w == 5 then
+ return 'Не думаю, что мой пропуск здесь подойдет.';
+ end
+ if w == 6 then
+ return goto('handgdlg');
+ end
+ end,
+ used = function(s, w, ww)
+ if w == 6 then
+ return 'Я держу охранника на мушке.';
+ end
+ if w == 5 then
+ return 'Не поможет.';
+ end
+ end,
+ obj = {
+ vobj(1, 'ковер', 'Лифтовую площадку покрывает красный {ковер}.'),
+ vobj(2, 'люстра', 'Хрустальная {люстра} висит на высоком потолке.'),
+ 'win5',
+ vobj(4, 'информация', '{Дверь} в центр обработки информации распахнута. Из нее начинает валить дым.'),
+ vobj(5, 'красная дверь', 'Напротив нее находится {дверь} без надписей. Это массивная дверь, обитая красной кожей.'),
+
+ vobj(6, 'охранник', 'В центре площадки подняв руки, стоит {охранник}.');
+ },
+ way = { 'lift','room5' },
+ exit = function(s, t)
+ if t == 'room5' then
+ return 'Там пламя!', false
+ end
+ if t == 'lift' then
+ return 'Я вижу что лампочки вызова всех лифтов горят. Скорее всего это означает, что сюда поднимается охрана... Надо спешить!', false;
+ end
+ if t == 'krysha' then
+ lifeoff('escape2');
+ end
+ end
+};
+
+swin = obj {
+ nam = 'южное окно',
+ dsc = 'Из южного {окна} валит дым.',
+ act = 'Да, это одно из окон информационного центра. Я заглядываю в окно и вижу пламя.',
+};
+nwin = obj {
+ nam = 'северное окно',
+ dsc = function(s)
+ local st = '';
+ if s._broken then
+ st = ' Оно разбито.';
+ end
+ return 'Северное {окно} светит в темноту желтым светом.'..st;
+ end,
+ act = function(s)
+ if s._broken then
+ return goto('hall5');
+ end
+ return 'Гм... Я заглядываю в окно и вижу прекрасный зал.';
+ end,
+ used = function(s, w)
+ if w == 'shotgun' then
+ s._broken = true;
+ ways():add('hall5');
+ return 'Уххх... Надеюсь, это последнее??? Я размахиваюсь и разбиваю стекло прикладом помпового ружья.';
+ end
+ end,
+};
+
+hall5 = room {
+ nam = 'зал',
+ pic = 'gfx/hall5.png',
+ enter = function(s, f)
+ if f == 'krysha' then
+ return 'Я спрыгиваю в зал и оглядываюсь...';
+ end
+ end,
+ act = function(s, w)
+ if w == 1 then
+ return 'Ненужная роскошь.';
+ end
+ if w == 2 then
+ return 'Я провожу ладонью по скользкой поверхности одной из колонн... Мрамор!';
+ end
+ if w == 3 then
+ return 'Но уж эта то люстра точно из горного хрусталя.';
+ end
+ if w == 4 then
+ return 'Темно... Хотя... Что это? Мне кажется, что у задней стороны института стоит поезд.';
+ end
+ if w == 5 then
+ return 'У разбитого окна кружатся снежинки.';
+ end
+ if w == 6 then
+ if s.way:srch('escape3') then
+ return goto('escape3');
+ end
+ return goto('gudlg');
+ end
+ if w == 7 then
+ return 'Эта дверь закрыта. Вряд ли ее можно открыть моим ключом.';
+ end
+ if w == 8 then
+ return 'Гммм... Пикассо?';
+ end
+ if w == 9 then
+ return 'Страшная слабость охватывает меня... Нет -- мне нельзя спать...';
+ end
+ end,
+ used = function(s, w, ww)
+ return 'Зачем?';
+ end,
+ dsc = 'Прекрасный и огромный зал занимает почти всю северную часть здания!',
+ obj = {
+ vobj(1,'ковер', 'Под ногами бархат красного {ковра}.'),
+ vobj(2,'колонны', 'Восемь мраморных {колонн} образуют коридор.'),
+ vobj(3,'люстра', 'Великолепная {люстра} свисает с потолка.'),
+ vobj(4,'восточные окна', 'На восток выходит четыре {окна}.'),
+ vobj(5,'западные окна', 'Разбитое {окно} находится слева от меня.'),
+ vobj(6,'небольшая дверь', 'В конце зала, в его северной части, я вижу небольшую деревянную {дверь}.'),
+ vobj(7,'входная дверь', 'За моей спиной входная {дверь}.'),
+ vobj(8,'картины', 'По стенам развешены {картины} в красивых рамах.'),
+ vobj(9,'диваны', 'У стен расставлены мягкие {диваны}.'),
+ },
+ way = { 'krysha' },
+};
+
+krysha = room {
+ nam = 'крыша',
+ pic = 'gfx/krysha.png',
+ enter = function(s, f)
+ return 'Я быстро подхожу к разбитому окну и вот, я на крыше...';
+ end,
+ dsc = 'Видимо, пятый этаж был достроен позже остальных четырех. По участку крыши я могу добраться до первых окон южного и северного крыла.',
+ obj = {'nwin', 'swin'},
+ way = {'escape2'},
+};
+
+gudlg2 = dlg {
+ nam = 'человек с портрета',
+ pic = 'gfx/pmanb.png',
+ dsc = 'Я смотрю на его поникшее лицо. Оно по-прежнему спокойно.',
+ obj = {
+ [1] = phr('Получил, гад?',
+ 'В ответ я слышу едва различимый стон.',
+ [[pon(1); back();]]),
+ [2] = phr('Но зачем, зачем это все?',
+ 'Он поднял на меня свои глаза. -- Я просто делал свою работу...',
+ [[pon(3);poff(1);]]),
+ [3] = _phr('Что за ерунда?',
+ '-- А потом, потом стал не нужен... Ну что же -- подумал я... -- Мир заплатит за эту ошибку...',[[pon(4)]]),
+ [4] = _phr('Что ты несешь?',
+ '-- Я работал профессором... Но я был не нужен.. Я ... Я не мог это вынести...',
+ [[pon(5)]]),
+ [5] = _phr('Какой мерзавец...',
+ '-- Но я заставлю их... Заставлю... Я, я, я - я буду жить вечно... Сам... Один.',
+ [[pon(6)]]),
+ [6] = _phr('Мне кажется, что ты спятил...',
+ 'Его тело дергается в углу -- это озноб.',
+ [[pon(1); back()]]),
+ }
+};
+
+gudlg = dlg {
+ nam = 'человек с портрета',
+ pic = 'gfx/pman.png',
+ enter = function(s)
+ lifeoff('mycat');
+ inv():del('shotgun');
+ return [[Странно... Дверь не закрыта... Я осторожно открываю дверь и вхожу в комнату.^^Внезапно я обнаруживаю, что на меня смотрит дуло револьвера. -- Браво, браво, браво -- говорит мне человек в кресле, владелец револьвера. -- Я уже заждался. Тот самый лесник? Ну что же, подождем охрану. А пока -- брось ружье на пол. Мне ничего не остается, как сделать то - что он сказал.]];
+ end,
+ dsc = [[Передо мной то самое лицо. Лицо с портретов, которые увешивают почти все комнаты этого здания. Лицо спокойное, ничего не выражающее. Слабая улыбка на губах. Надо тянуть время... И я спрашиваю у него:]],
+ obj = {
+ [1] = phr('Может, поговорим?',
+ 'Гм... Ну о чем нам говорить? О чем мне говорить с лесником?', [[pon(2)]]),
+ [2] = _phr('Например, правда ли то, что многомировая интерпретация Эверетта верна?',
+ '-- Ха ха ха ха!!! -- невыразительно смеется человек с портрета -- Конечно, это фокус... Что бы заставить этих идиотов верить в собственное бессмертие... А может...',[[pon(3)]] ),
+ [3] = _phr('...То-есть никакого доказательства нет?',
+ 'Человек перестает смеяться -- ...А может -- это все-таки правда? -- загадочно произносит он -- Какой ответ истина? Как ТЫ думаешь?', [[pon(4)]]),
+ [4] = _phr('Я знаю, что это ложь!',
+ 'Знаешь ли? -- пустые глаза смотрят на меня -- Да или нет? - Вдруг паника оглушает меня.'
+ ,[[pon(5,9)]]),
+ [5] = _phr('Ложь!',
+ 'А что если? Представь, что если?... Ты же хакер да? Любишь продумывать все заранее...',
+[[pon(6);poff(9)]]),
+ [6] = _phr('Нет! Это не может быть правдой! Если это правда -- рано или поздно мир будет обречен! Тоггда...',
+ '-- Да, ты правильно понял... Тогда есть только ТЫ!!! Послушай себя -- кто дал тебе этот ответ? Не его ли ты жаждешь? Не его ли жаждет твое Я? -- Я проваливаюсь в его бездонный взгляд.', [[pon(7)]]),
+ [7] = _phr('Если... Если... То зачем?',
+ '-- Правильно... Правильно -- вкрадчиво говорит мне человек с портрета... Новая волна страха оглушает меня я падаю на колени... Сердце бешено стучит и вылетает из груди...',
+ [[pon(8)]]),
+ [8] = _phr('Не могу... Нет...',
+ '-- И если все так, то тебе нечего бояться -- мурлычет он. -- Сердце бьется еще сильнее. И наконец, моя грудь взрывается, мягкий комочек шерсти отталкивается от нее лапами и летит в лицо человеку с портрета. Раздается выстрел, резкая боль в левом плече отрезвляет меня, я вскакиваю на ноги и бросаюсь вперед...',[[return goto('escape3')]]),
+ [9] = _phr('Допустим, это правда.',
+ '-- Так... Правильно... Думай, думай...Ты же хакер, да? -- шепчет человек с портрета.',
+ [[pon(6);poff(5)]])
+ },
+};
+
+--shkf = obj {
+-- nam = 'край шкафа',
+-- inv = 'Я держу в руках край шкафа.',
+--};
+
+shkaf = obj {
+ nam = 'шкаф',
+ inv = 'Я держу в руках край шкафа.',
+ dsc = function(s)
+ if s._fall then
+ return 'Дверь завалена {шкафом}.';
+ end
+ return 'Один из книжных {шкафов} стоит возле двери.';
+ end,
+ act = function(s)
+ if not escape3._guards or s._fall then
+ return 'Какая-то философия... И еще физика.';
+ end
+ inv():add('shkaf');
+ return 'Я крепко схватился за край шкафа.';
+ end,
+};
+
+fromw5 = room {
+ nam = 'на подоконнике',
+ dsc = 'Я стою на подоконнике, ледяной ветер мешает дышать.',
+ pic = 'gfx/fromwin2.png',
+ enter = 'Ну что-же, надеюсь это в последний раз...',
+ act = function(s, w)
+ if w == 1 then
+ return goto('nwall');
+ end
+ end,
+ obj = {
+ vobj(1, 'труба', 'Справа от себя я едва различаю водосточную {трубу}.'),
+ },
+ way = { 'escape3' },
+ exit = function(s, t)
+ if t == 'escape3' then
+ return 'Надо спешить!', false;
+ end
+ end
+};
+
+winr5 = obj {
+ nam = 'окно',
+ dsc = function(s)
+ if s._broken then
+ return 'Сквозь разбитое {окно} в комнату дышит зимний ветер.';
+ else
+ return '{Окно} выходит на северную сторону.';
+ end
+ end,
+ act = function(s, w)
+ if escape3._guards then
+ if not shkaf._fall then
+ return 'Некогда любоваться видами... Надо задержать охранников.';
+ end
+ if not have('mycat') then
+ return 'Без Барсика? Лучше погибнуть вместе!';
+ end
+-- if not have('revol') then
+-- return 'Лучше поднять с пола пистолет, на всякий случай.';
+-- end
+ if s._broken then
+ ways():add('fromw5');
+ return goto('fromw5');
+ else
+ return 'Окно закрыто.';
+ end
+ end
+ escape3._guards = true;
+ lifeon('escape3');
+ return 'За окном полная темнота. Я смотрю в темноту, когда вдруг слышу за спиной приглушенный шум шагов... Звуки идут из зала, наверное охрана добралась сюда! Нужно действовать!';
+ end,
+ used = function(s, w)
+ if escape3._guards and not shkaf._fall then
+ return 'Некогда... Скоро охрана ворвется сюда...';
+ end
+ if w == 'shotgun' then
+ if not s._broken then
+ s._broken = true;
+ return 'Опять? Ну что же... Я размахиваюсь и разбиваю стекло прикладом. Осколки улетает в темноту.';
+ end
+ return 'Это окно уже разбито.';
+ end
+ end,
+};
+
+revol = obj {
+ nam = 'револьвер',
+ dsc = 'На полу валяется {револьвер}.',
+ inv = 'Шесть зарядов.',
+ tak = 'Я поднимаю с пола револьвер.',
+};
+
+escape3 = room {
+ nam = 'в комнате',
+ pic = 'gfx/manroom.png',
+ enter = function(s, f)
+ if f == 'gudlg' then
+ inv():del('mycat');
+ hall5.way:add('escape3');
+ return 'Я слышу звук падающего пистолета... Потом я бью в чье-то лицо изо-всех сил. Снова и снова. Барсик носится вокруг и жалобно мяукает. Через несколько секунд я встаю с пола.';
+ end
+ end,
+ act = function(s, w)
+ if w == 1 then
+ return goto('gudlg2');
+ end
+ if w == 2 then
+ return 'Абстракционисты не в моем вкусе.';
+ end
+ if w == 3 then
+ local st = '';
+ if shkaf._fall then
+ st = ' Завалена шкафом.';
+ end
+ return 'Дверь ведущая в зал.'..st;
+ end
+ end,
+ used = function(s, w, ww)
+ if w == 1 and ww == 'shotgun' or ww == 'revol' then
+ return 'Да -- это зло. Но я не могу стрелять в беспомощного человека.';
+ end
+ if w == 3 and ww == 'shkaf' then
+ shkaf._fall = true;
+ inv():del('shkaf');
+ return 'Я толкаю шкаф и он падает, заграждая собой дверь.';
+ end
+ end,
+ dsc = [[Я нахожусь в небольшой, но уютной комнате. Посреди стоит стол. Рядом опрокинуто кресло. Из небольшой люстры равномерно льется свет. Два небольших книжных шкафа стоят у стен.]],
+ obj = {
+ vobj(1, 'человек', 'На полу, прислонившись к столу, сидит {человек} с портретов. Струйка крови стекает с его губ -- он стонет.'),
+ vobj(2, 'картины', 'По стенам развешены {картины}.'),
+ vobj(3, 'дверь', 'За моей спиной {дверь}.'),
+ 'revol',
+ 'shkaf',
+ 'shotgun',
+ 'mycat',
+ 'winr5',
+ },
+ life = function(s)
+ if rnd(3) == 1 then
+ return 'Я слышу выстрелы... Пули прошивают дверь... Надо что-то делать...';
+ end
+ end,
+ exit = function(s,t)
+ if t == 'hall5' then
+ if shkaf._fall then
+ return 'Проход завален шкафом.', false;
+ end
+ if s._guards then
+ return 'Меня там подстрелят...', false;
+ end
+ s._guards = true;
+ lifeon('escape3');
+ return 'Я собираюсь выйти в зал, когда вдруг на другом конце открывается дверь и в зал вбегают охранники. Я быстро захлопываю дверь.',false;
+ end
+ lifeoff('escape3');
+ end,
+ way = {
+ 'hall5'
+ },
+};
+
+nwall = room {
+ nam = 'северная сторона',
+ dsc = 'Я нахожусь у северной стены здания института.',
+ pic = 'gfx/nside.png',
+ way = {'eside2','wside' },
+ act = function(s, w)
+ if w == 1 then
+ return 'Да -- водосточная труба... Довольно крепкая. Но вряд-ли я смогу взобраться по ней наверх.';
+ end
+ end,
+ enter = function(s, f)
+ if f == 'fromw5' then
+ return 'Превозмогая боль в левом плече я прыгаю с подоконника на трубу... Мое сердце бешено стучит в груди, пока мы падаем с Барсиком в зимнюю темноту. Но вот, в следующее мгновение я уже соскальзываю, обдирая кожу с ладоней, по водосточной трубе...';
+ end
+ end,
+ obj = { vobj(1, 'труба', 'Водосточная {труба} проходит по восточному углу здания.')},
+ exit = function(s, t)
+ if t == 'wside' then
+ if not s._guards then
+ s._guards = true;
+ return 'Я высовываюсь из-за угла и вижу, как толпа охранников приближается ко мне из КПП. -- Вон он -- слышу я крик... Треск выстрелов отгоняет меня обратно.', false;
+ end
+ return 'Там меня ждут...', false;
+ end
+ end
+};
+
+eside2 = room {
+ nam = 'сзади института',
+ pic = 'gfx/esidee.png',
+ dsc = [[ Я нахожусь у задней стены здания института. Здесь проходят рельсы.]],
+ act = function(s,w)
+ if w == 1 then
+ return 'Пулеметы направлены на внешнюю - южную сторону периметра, надо держаться от них подальше.';
+ end
+ if w == 2 then
+ return 'Гм... Похоже это тот самый поезд... Разгрузка еще не началась, но ворота уже открыты.';
+ end
+ if w == 3 then
+ return 'Четыре вагона. Тип тепловоза - ЧМЭ3. Поезд полностью помещается на территории института.';
+ end
+ end,
+ obj = {
+ vobj(1,'пулеметные вышки', 'Въезд поезда охраняется пулеметными {вышками}..'),
+ vobj(3,'поезд', 'Перед институтом стоит темная громада {поезда}.'),
+ vobj(2,'ворота', 'Большие железные {ворота} в стене института открыты -- я вижу свет, который льется из дверного проема.'),
+ },
+ exit = function(s, t)
+ if t == 'sside' then
+ return 'На южной стороне меня смущают пулеметы. Лучше не рисковать.', false
+ end
+ if t == 'nwall' and nwall._guards then
+ return 'Назад пути нет...', false;
+ end
+ end,
+ way = {'nwall','train','sside'},
+};
+function checkloc()
+ if p1._off or p2._off then -- battary or switch off off
+ p3._off = true;
+ p4._off = true;
+ p5._off = true;
+-- p51._off = true;
+-- p6._off = true;
+ end
+ if p3._off or p4._off then
+-- p7._off = true;
+-- p71._off = true;
+ end
+ if p5._off then
+ p7._off = true;
+ end
+ if p51._off then
+ p71._off = true;
+ end
+ if p6._off then
+-- p7._off = true;
+-- p71._off = true;
+ end
+ if p7._off then
+-- p71._off = true;
+ end
+end
+p1 = obj {
+ _off = false,
+ nam = 'разъеденитель',
+ dsc = function(s)
+ local st = 'включено.';
+ if s._off then
+ st = 'выключено.';
+ end
+ return '{Разъеденитель} батареи ВБ: '..st;
+ end,
+ act = function(s)
+ if s._off then
+ s._off = false;
+ else
+ s._off = true;
+ end
+ checkloc();
+ return 'Переключаю...';
+ end
+};
+
+p2 = obj {
+ _off = true;
+ nam = 'ключ',
+ dsc = function(s)
+ local st = 'повернут вниз.';
+ if s._off then
+ st = 'повернут вверх.';
+ end
+ return '{Ключ} кнопочных выключателей: '..st;
+ end,
+ act = function(s)
+ if s._off then
+ s._off = false;
+ else
+ s._off = true;
+ end
+ checkloc();
+ return 'Я поворачиваю ключ.';
+ end
+};
+p3 = obj {
+ _off = true,
+ nam = 'электроманометр',
+ dsc = function(s)
+ local st = 'включено.';
+ if s._off then
+ st = 'выключено.';
+ end
+ return '{Электроманометр}: '..st;
+ end,
+ act = function(s)
+ if p1._off or p2._off then
+ return 'Странно... Не получается.'
+ end
+ if s._off then
+ s._off = false;
+ else
+ s._off = true;
+ end
+ checkloc();
+ return 'Переключаю...'
+ end
+};
+p4 = obj {
+ _off = false,
+ nam = 'электротермометр',
+ dsc = function(s)
+ local st = 'включено.';
+ if s._off then
+ st = 'выключено.';
+ end
+ return '{Электротермометр}: '..st;
+ end,
+ act = function(s)
+ if p1._off or p2._off then
+ return 'Странно... Не получается.'
+ end
+ if s._off then
+ s._off = false;
+ else
+ s._off = true;
+ end
+ checkloc();
+ return 'Переключаю...'
+ end
+};
+p5 = obj {
+ _off = true,
+ nam = 'насос 2-й секции',
+ dsc = function(s)
+ local st = 'включено.';
+ if s._off then
+ st = 'выключено.';
+ end
+ return 'Топливный {насос} 2-й секции: '..st;
+ end,
+ act = function(s)
+ if p1._off or p2._off then
+ return 'Странно... Не получается.'
+ end
+ if s._off then
+ s._off = false;
+ else
+ s._off = true;
+ end
+ checkloc();
+ return 'Переключаю...'
+ end
+};
+
+p6 = obj {
+ _off = true,
+ nam = 'управление',
+ dsc = function(s)
+ local st = 'включено.';
+ if s._off then
+ st = 'выключено.';
+ end
+ return '{Управление}: '..st;
+ end,
+ act = function(s)
+ if p1._off or p2._off then
+ return 'Странно... Не получается.'
+ end
+ if s._off then
+ s._off = false;
+ else
+ s._off = true;
+ end
+ checkloc();
+ return 'Переключаю...'
+ end
+};
+
+p7 = obj {
+ _off = true,
+ nam = 'пуск дизеля 2-й секции',
+ dsc = function(s)
+ local st = 'включено.';
+ if s._off then
+ st = 'выключено.';
+ end
+ return '{Пуск} дизеля 2-й секции: '..st;
+ end,
+ act = function(s)
+ if p3._off or p4._off or p5._off or p6._off then
+ return 'Странно... Не получается.'
+ end
+ if s._off then
+ s._off = false;
+ else
+ s._off = true;
+ end
+ checkloc();
+ return 'Переключаю...'
+ end
+};
+
+p51 = obj {
+ _off = true,
+ nam = 'насос 1-й секции',
+ dsc = function(s)
+ local st = 'включено.';
+ if s._off then
+ st = 'выключено.';
+ end
+ return 'Топливный {насос} 1-й секции: '..st;
+ end,
+ act = function(s)
+ if p1._off or p2._off then
+ return 'Странно... Не получается.'
+ end
+ if s._off then
+ s._off = false;
+ else
+ s._off = true;
+ end
+ checkloc();
+ return 'Переключаю.';
+ end
+};
+
+p71 = obj {
+ _off = true,
+ nam = 'пуск дизеля 1-й секции',
+ dsc = function(s)
+ local st = 'включено.';
+ if s._off then
+ st = 'выключено.';
+ end
+ return '{Пуск} дизеля 1-й секции: '..st;
+ end,
+ act = function(s)
+ if p3._off or p4._off or p5._off or p6._off or p7._off then
+ return 'Странно... Не получается.'
+ end
+ if s._off then
+ s._off = false;
+ else
+ s._off = true;
+ end
+ checkloc();
+ return 'Переключаю...';
+ end
+};
+
+p8 = obj {
+ _num = 1,
+ nam = 'реверсор',
+ dsc = function(s)
+ local st;
+ if s._num == 1 then
+ st = 'нейтрально.';
+ elseif s._num == 2 then
+ st = 'назад.';
+ elseif s._num == 3 then
+ st = 'вперед.';
+ end
+ return 'Рукоятка {реверсора}: '..st;
+ end,
+ act = function(s)
+ s._num = s._num + 1;
+ if s._num == 4 then
+ s._num = 1;
+ end
+ return 'Переключаю...';
+ end
+};
+
+p9 = obj {
+ _num = 1,
+ nam = 'контроллер',
+ dsc = function(s)
+ local st;
+ if s._num == 1 then
+ st = '0.';
+ elseif s._num == 2 then
+ st = '1.';
+ elseif s._num == 3 then
+ st = '2.';
+ end
+ return 'Рукоятка {контроллера}: '..st;
+ end,
+ act = function(s)
+ s._num = s._num + 1;
+ if s._num == 4 then
+ s._num = 1;
+ end
+ if s._num == 1 then
+ return 'Переключаю.';
+ end
+ if not p71._off and not p7._off then
+ if p8._num == 2 then
+ s._num = 1;
+ return 'Локомотив вздрагивает и начинает ехать назад. Я перевожу контроллер на 0.';
+ elseif p8._num == 3 then
+ lifeoff('mycat');
+ set_music('mus/liberty.s3m');
+ return goto('theend');
+ end
+ end
+ s._num = 1;
+ return 'Ничего не происходит... Я перевожу контроллер в положение 0.';
+ end
+};
+
+train = room {
+ nam = function(s)
+ if here() == train then
+ return 'в локомотиве';
+ end
+ return 'к поезду';
+ end,
+ pic = 'gfx/cab.png',
+ dsc = 'Итак, я в локомотиве. Толстая сталь надежно укрывает меня от пуль. Кабина машиниста оказалась пуста. Я вижу перед собой множество приборов.',
+ act = function(s, w)
+ if w == 2 then
+ if p1._off or p2._off then
+ return 'Я нажал кнопку гудка, но ничего не услышал.';
+ end
+ return 'Раздается унылый звук сигнала. -- Я машинист!';
+ end
+ if w == 1 then
+ return 'Только бы успеть завести эту штуку... И никакие ворота меня не остановят.';
+ end
+ end,
+ life = function(s)
+ local st = '';
+ if not p7._off or not p71._off then
+ st = 'Я чувствую как дрожит локомотив. Работает дизель. ';
+ end
+ if rnd(10) < 5 then
+ st = st..'В кабине раздаются звуки ударов пуль о металл.';
+ end
+ return st;
+ end,
+ exit = function(s,t)
+ if t == 'eside2' then
+ return 'Нет... Лучше остаться здесь, мы будем сопротивляться до последнего.', false;
+ end
+ lifeoff('train');
+ end,
+ enter = function(s, f)
+ if f == 'eside2' and not guards1._broken then
+ return cat('Пригнувшись, я бегу к поезду.^^', goto('vorota')), false;
+ end
+ lifeon('train');
+ set_music('mus/hispeed.s3m');
+ return 'Пригнувшись, я бегу к поезду... Пробегая мимо вагонов я успеваю заметить знаки <<осторожно -- радиация!!>>. Еще немного и я добираюсь до локомотива. Сзади я слышу звуки выстрелов. Впереди охрана разворачивает пулеметы. Я открываю тяжелую дверь и вот я -- внутри.'
+ end,
+ obj = {
+ 'p2', 'p1', 'p4', 'p3', 'p71','p51', 'p7', 'p5', 'p9', 'p8', 'p6',
+ vobj(2, 'гудок', '{Гудок}.');
+ vobj(1, 'окно', 'В {окнах} я вижу закрытые ворота.'),
+ },
+ way = { 'eside2' },
+};
+
+guards1 = obj {
+ nam = 'охрана',
+ dsc = function(s, w)
+ if s._broken then
+ return '{Охранники} за турникетами завалены обломками люстры.';
+ end
+ if s._shoot then
+ return 'Я вижу {охранников}, которые укрываются от моего огня за турникетами.';
+ end
+ return 'Я вижу {охранников} с автоматами, которые пробираются ко мне через зал первого этажа.';
+ end,
+ act = function(s, w)
+ if s._broken then
+ return 'Похоже, они в замешательстве...';
+ end
+ if s._shoot then
+ return 'Вот негодяи!';
+ end
+ return 'Удивительно, что я еще жив...';
+ end,
+ used = function(s, w)
+ if w == 'shotgun' or w == 'revol' then
+ if s._shoot then
+ return 'Бесполезно, охранники защищены металлом турникетов.';
+ end
+ s._shoot = true;
+ return 'Я высовываюсь из-за стены и стреляю несколько раз наугад.';
+ end
+ end,
+};
+
+lustra1 = obj {
+ nam = 'люстры',
+ dsc = function(s, w)
+ if s._broken then
+ return 'На потолке висит одна {люстра}.';
+ end
+ return 'Две ослепительные {люстры} свисают с потолка.';
+ end,
+ act = function(s, w)
+ if guards1._shoot then
+ return 'Одна из люстр находится прямо над турникетами.';
+ end
+ return 'Не могу на них наглядеться... Наверное, это хрусталь?';
+ end,
+ used = function(s, w)
+ if w == 'revol' then
+ return 'Вряд ли этот пистолет принесет сильный ущерб люстрам.';
+ end
+ if w == 'shotgun' then
+ shotgun._unloaded = true;
+ s._broken = true;
+ guards1._broken = true;
+ lifeoff('vorota');
+ drop('shotgun');
+ return 'Я высовываюсь из-за стены и разряжаю помповое ружье. Сильный грохот и звуки щелкающего затвора оглушают меня. Я вижу как одна из люстр, сопровождаемая криками охранников, медленно оторвавшись летит вниз. Я выбрасываю бесполезное ружье на пол.';
+ end
+ end,
+
+};
+
+vorota = room {
+ nam = 'у ворот',
+ pic = 'gfx/shooting.png',
+ enter = function(s, f)
+ if f == 'eside2' and not guards1._broken then
+ lifeon('vorota');
+ return 'Поравнявшись с открытыми воротами я слышу треск выстрелов и прижимаюсь к стене.';
+ end
+ end,
+ life = function(s)
+ if rnd(6) < 4 then
+ return 'Раздается треск выстрелов. Я вжимаюсь в стену.';
+ end
+ end,
+ act = function(s, w)
+ if w == 1 then
+ return 'Те самые турникеты, через которые я попал внутрь. Теперь я нахожусь с другой стороны.';
+ end
+ end,
+ dsc = 'Я нахожусь у открытых ворот. Ворота ведут на первый этаж института.',
+ obj = {
+ vobj(1, 'турникеты', 'Я вижу ряд {турникетов}.'),
+ 'lustra1',
+ 'guards1',
+ },
+ exit = function(s, t)
+ if not guards1._broken and t == 'train' then
+ return 'Я бросаюсь вперед, но автоматные очереди заставляют меня вернуться.', false;
+ end
+ end,
+ way = { 'train', 'eside2' },
+};
+
+theend = room {
+ nam = 'эпилог',
+ pic = 'gfx/chme3.png',
+ dsc = [[Я передвинул ручку контроллера в самое переднее положение и локомотив,
+вздрогнув, двинулся вперед. Я услышал крики, и пулеметные очереди с новой силой застучали
+по стенкам кабины... Но локомотив набирал ход, и скоро послышался сильный лязг -- это ворота,
+не выдержав натиска 1350 лошадиных сил, вылетели из своих петель и протащились несколько
+десятков метров вдоль путей...^^
+
+Барсик высунул морду из-за пазухи и осмотрелся вокруг. Я привычно погладил его за ушами.
+Когда лязг раздавленных ворот и стук пуль утихли, я выглянул из окна и последний раз посмотрел в сторону института. Он полыхал словно факел -- пожар уже захватил весь пятый этаж.
+Я посмотрел на небо и теперь, уже в полной темноте, смог разглядеть россыпи звезд. ^^
+
+Совсем скоро поле уступило место тайге, и привычные очертания сосен и елей замелькали под
+ровный стук колес. Рана в плече ныла, и я почувствовал сильную усталость... Присев на пол
+и прислонившись к холодному железу кабины, я слушал гудение локомотива и гладил Барсика за
+ушами...^^
+
+Барсик посмотрел на меня своими умными глазами и вопросительно замурлыкал -- Домой,
+ответил я ему -- Мы едем домой...^^
+КОНЕЦ^^
+
+ ---^^
+
+История и движок: ^
+Косых Петр a.k.a. gl00my // 2009^^
+
+Графика: ^
+Косых Петр, несколько фотографий из открытых источников.^^
+
+Музыка: ^
+One fine day // Elwood^
+Revelation // necros^
+New beginning // Purple Motion^
+Ice frontier // Skaven^
+Planete football // Frank Amoros^
+Underwater world II // Slightly Magic^
+Hybrid song // Quazar^
+Hispeed - track whatever // Purple Motion^
+Liberty // Zapper^^
+
+Шрифт темы по-умолчанию:^
+Arial от Microsoft.^^
+
+Тестеры:^
+Каличев Сергей a.k.a. Pkun^
+Подобаев Владимир a.k.a. zloyvov^^
+
+
+Если вам понравилась игра, самое лучшее, что вы можете сделать, это написать свою историю на движке instead. :)^^
+
+Благодарности:^
+Всем тем, кто не мешал. :)^^
+]],
+};
+
diff --git a/games/cat/gfx/bholes.png b/games/cat/gfx/bholes.png
new file mode 100644
index 0000000..e60787c
Binary files /dev/null and b/games/cat/gfx/bholes.png differ
diff --git a/games/cat/gfx/cab.png b/games/cat/gfx/cab.png
new file mode 100644
index 0000000..229c8ce
Binary files /dev/null and b/games/cat/gfx/cab.png differ
diff --git a/games/cat/gfx/chme3.png b/games/cat/gfx/chme3.png
new file mode 100644
index 0000000..e5af8a6
Binary files /dev/null and b/games/cat/gfx/chme3.png differ
diff --git a/games/cat/gfx/cor3.png b/games/cat/gfx/cor3.png
new file mode 100644
index 0000000..569ac56
Binary files /dev/null and b/games/cat/gfx/cor3.png differ
diff --git a/games/cat/gfx/cor4.png b/games/cat/gfx/cor4.png
new file mode 100644
index 0000000..a19df96
Binary files /dev/null and b/games/cat/gfx/cor4.png differ
diff --git a/games/cat/gfx/deepforest.png b/games/cat/gfx/deepforest.png
new file mode 100644
index 0000000..ccd18a3
Binary files /dev/null and b/games/cat/gfx/deepforest.png differ
diff --git a/games/cat/gfx/entrance.png b/games/cat/gfx/entrance.png
new file mode 100644
index 0000000..d823259
Binary files /dev/null and b/games/cat/gfx/entrance.png differ
diff --git a/games/cat/gfx/eside.png b/games/cat/gfx/eside.png
new file mode 100644
index 0000000..c322b88
Binary files /dev/null and b/games/cat/gfx/eside.png differ
diff --git a/games/cat/gfx/esidee.png b/games/cat/gfx/esidee.png
new file mode 100644
index 0000000..8cdb12c
Binary files /dev/null and b/games/cat/gfx/esidee.png differ
diff --git a/games/cat/gfx/floor2.png b/games/cat/gfx/floor2.png
new file mode 100644
index 0000000..6deb460
Binary files /dev/null and b/games/cat/gfx/floor2.png differ
diff --git a/games/cat/gfx/floor3.png b/games/cat/gfx/floor3.png
new file mode 100644
index 0000000..37fd4b1
Binary files /dev/null and b/games/cat/gfx/floor3.png differ
diff --git a/games/cat/gfx/floor4.png b/games/cat/gfx/floor4.png
new file mode 100644
index 0000000..84a0ad1
Binary files /dev/null and b/games/cat/gfx/floor4.png differ
diff --git a/games/cat/gfx/floor5.png b/games/cat/gfx/floor5.png
new file mode 100644
index 0000000..8863b1f
Binary files /dev/null and b/games/cat/gfx/floor5.png differ
diff --git a/games/cat/gfx/floor5e.png b/games/cat/gfx/floor5e.png
new file mode 100644
index 0000000..b7c8dc0
Binary files /dev/null and b/games/cat/gfx/floor5e.png differ
diff --git a/games/cat/gfx/forest.png b/games/cat/gfx/forest.png
new file mode 100644
index 0000000..b1b0678
Binary files /dev/null and b/games/cat/gfx/forest.png differ
diff --git a/games/cat/gfx/fromwin1.png b/games/cat/gfx/fromwin1.png
new file mode 100644
index 0000000..43239a3
Binary files /dev/null and b/games/cat/gfx/fromwin1.png differ
diff --git a/games/cat/gfx/fromwin2.png b/games/cat/gfx/fromwin2.png
new file mode 100644
index 0000000..dfb53c1
Binary files /dev/null and b/games/cat/gfx/fromwin2.png differ
diff --git a/games/cat/gfx/guard.png b/games/cat/gfx/guard.png
new file mode 100644
index 0000000..ab43dd9
Binary files /dev/null and b/games/cat/gfx/guard.png differ
diff --git a/games/cat/gfx/guard4.png b/games/cat/gfx/guard4.png
new file mode 100644
index 0000000..47f719e
Binary files /dev/null and b/games/cat/gfx/guard4.png differ
diff --git a/games/cat/gfx/guard42.png b/games/cat/gfx/guard42.png
new file mode 100644
index 0000000..aef7016
Binary files /dev/null and b/games/cat/gfx/guard42.png differ
diff --git a/games/cat/gfx/guy.png b/games/cat/gfx/guy.png
new file mode 100644
index 0000000..289c90a
Binary files /dev/null and b/games/cat/gfx/guy.png differ
diff --git a/games/cat/gfx/hall1.png b/games/cat/gfx/hall1.png
new file mode 100644
index 0000000..bb0eac3
Binary files /dev/null and b/games/cat/gfx/hall1.png differ
diff --git a/games/cat/gfx/hall2.png b/games/cat/gfx/hall2.png
new file mode 100644
index 0000000..5db01db
Binary files /dev/null and b/games/cat/gfx/hall2.png differ
diff --git a/games/cat/gfx/hall5.png b/games/cat/gfx/hall5.png
new file mode 100644
index 0000000..fdbf143
Binary files /dev/null and b/games/cat/gfx/hall5.png differ
diff --git a/games/cat/gfx/handhoh.png b/games/cat/gfx/handhoh.png
new file mode 100644
index 0000000..7d1908a
Binary files /dev/null and b/games/cat/gfx/handhoh.png differ
diff --git a/games/cat/gfx/house.png b/games/cat/gfx/house.png
new file mode 100644
index 0000000..f4ff443
Binary files /dev/null and b/games/cat/gfx/house.png differ
diff --git a/games/cat/gfx/ilya.png b/games/cat/gfx/ilya.png
new file mode 100644
index 0000000..ba2a523
Binary files /dev/null and b/games/cat/gfx/ilya.png differ
diff --git a/games/cat/gfx/incar.png b/games/cat/gfx/incar.png
new file mode 100644
index 0000000..9725bdd
Binary files /dev/null and b/games/cat/gfx/incar.png differ
diff --git a/games/cat/gfx/inshop.png b/games/cat/gfx/inshop.png
new file mode 100644
index 0000000..00f0249
Binary files /dev/null and b/games/cat/gfx/inshop.png differ
diff --git a/games/cat/gfx/inst.png b/games/cat/gfx/inst.png
new file mode 100644
index 0000000..7c9330b
Binary files /dev/null and b/games/cat/gfx/inst.png differ
diff --git a/games/cat/gfx/instback.png b/games/cat/gfx/instback.png
new file mode 100644
index 0000000..2a5dd80
Binary files /dev/null and b/games/cat/gfx/instback.png differ
diff --git a/games/cat/gfx/kitchen.png b/games/cat/gfx/kitchen.png
new file mode 100644
index 0000000..e352e0e
Binary files /dev/null and b/games/cat/gfx/kitchen.png differ
diff --git a/games/cat/gfx/kitchencor.png b/games/cat/gfx/kitchencor.png
new file mode 100644
index 0000000..00e288a
Binary files /dev/null and b/games/cat/gfx/kitchencor.png differ
diff --git a/games/cat/gfx/kpp.png b/games/cat/gfx/kpp.png
new file mode 100644
index 0000000..3675983
Binary files /dev/null and b/games/cat/gfx/kpp.png differ
diff --git a/games/cat/gfx/krysha.png b/games/cat/gfx/krysha.png
new file mode 100644
index 0000000..6ef7e80
Binary files /dev/null and b/games/cat/gfx/krysha.png differ
diff --git a/games/cat/gfx/ladder.png b/games/cat/gfx/ladder.png
new file mode 100644
index 0000000..9d95f47
Binary files /dev/null and b/games/cat/gfx/ladder.png differ
diff --git a/games/cat/gfx/lection.png b/games/cat/gfx/lection.png
new file mode 100644
index 0000000..6b2b142
Binary files /dev/null and b/games/cat/gfx/lection.png differ
diff --git a/games/cat/gfx/lection2.png b/games/cat/gfx/lection2.png
new file mode 100644
index 0000000..aa462fa
Binary files /dev/null and b/games/cat/gfx/lection2.png differ
diff --git a/games/cat/gfx/lift.png b/games/cat/gfx/lift.png
new file mode 100644
index 0000000..381717b
Binary files /dev/null and b/games/cat/gfx/lift.png differ
diff --git a/games/cat/gfx/manroom.png b/games/cat/gfx/manroom.png
new file mode 100644
index 0000000..61b4b7c
Binary files /dev/null and b/games/cat/gfx/manroom.png differ
diff --git a/games/cat/gfx/me.png b/games/cat/gfx/me.png
new file mode 100644
index 0000000..ee49220
Binary files /dev/null and b/games/cat/gfx/me.png differ
diff --git a/games/cat/gfx/meandgun.png b/games/cat/gfx/meandgun.png
new file mode 100644
index 0000000..64d454c
Binary files /dev/null and b/games/cat/gfx/meandgun.png differ
diff --git a/games/cat/gfx/nside.png b/games/cat/gfx/nside.png
new file mode 100644
index 0000000..5030741
Binary files /dev/null and b/games/cat/gfx/nside.png differ
diff --git a/games/cat/gfx/onwall.png b/games/cat/gfx/onwall.png
new file mode 100644
index 0000000..028ac34
Binary files /dev/null and b/games/cat/gfx/onwall.png differ
diff --git a/games/cat/gfx/pman.png b/games/cat/gfx/pman.png
new file mode 100644
index 0000000..640c44d
Binary files /dev/null and b/games/cat/gfx/pman.png differ
diff --git a/games/cat/gfx/pmanb.png b/games/cat/gfx/pmanb.png
new file mode 100644
index 0000000..f8fad7f
Binary files /dev/null and b/games/cat/gfx/pmanb.png differ
diff --git a/games/cat/gfx/podnos.png b/games/cat/gfx/podnos.png
new file mode 100644
index 0000000..70808de
Binary files /dev/null and b/games/cat/gfx/podnos.png differ
diff --git a/games/cat/gfx/povar.png b/games/cat/gfx/povar.png
new file mode 100644
index 0000000..6897b7b
Binary files /dev/null and b/games/cat/gfx/povar.png differ
diff --git a/games/cat/gfx/prof2.png b/games/cat/gfx/prof2.png
new file mode 100644
index 0000000..afbfa30
Binary files /dev/null and b/games/cat/gfx/prof2.png differ
diff --git a/games/cat/gfx/room4.png b/games/cat/gfx/room4.png
new file mode 100644
index 0000000..a2d73d8
Binary files /dev/null and b/games/cat/gfx/room4.png differ
diff --git a/games/cat/gfx/servers.png b/games/cat/gfx/servers.png
new file mode 100644
index 0000000..21eb055
Binary files /dev/null and b/games/cat/gfx/servers.png differ
diff --git a/games/cat/gfx/shooting.png b/games/cat/gfx/shooting.png
new file mode 100644
index 0000000..c0ca5cb
Binary files /dev/null and b/games/cat/gfx/shooting.png differ
diff --git a/games/cat/gfx/shop.png b/games/cat/gfx/shop.png
new file mode 100644
index 0000000..5c715dd
Binary files /dev/null and b/games/cat/gfx/shop.png differ
diff --git a/games/cat/gfx/shopbuy.png b/games/cat/gfx/shopbuy.png
new file mode 100644
index 0000000..d0637b6
Binary files /dev/null and b/games/cat/gfx/shopbuy.png differ
diff --git a/games/cat/gfx/shopman.png b/games/cat/gfx/shopman.png
new file mode 100644
index 0000000..d9bbc9d
Binary files /dev/null and b/games/cat/gfx/shopman.png differ
diff --git a/games/cat/gfx/sside.png b/games/cat/gfx/sside.png
new file mode 100644
index 0000000..72f3b4b
Binary files /dev/null and b/games/cat/gfx/sside.png differ
diff --git a/games/cat/gfx/sto.png b/games/cat/gfx/sto.png
new file mode 100644
index 0000000..48587e0
Binary files /dev/null and b/games/cat/gfx/sto.png differ
diff --git a/games/cat/gfx/sto2.png b/games/cat/gfx/sto2.png
new file mode 100644
index 0000000..02cf407
Binary files /dev/null and b/games/cat/gfx/sto2.png differ
diff --git a/games/cat/gfx/sto3.png b/games/cat/gfx/sto3.png
new file mode 100644
index 0000000..b7532da
Binary files /dev/null and b/games/cat/gfx/sto3.png differ
diff --git a/games/cat/gfx/thecat.png b/games/cat/gfx/thecat.png
new file mode 100644
index 0000000..6a39ae6
Binary files /dev/null and b/games/cat/gfx/thecat.png differ
diff --git a/games/cat/gfx/toil3.png b/games/cat/gfx/toil3.png
new file mode 100644
index 0000000..df9a80a
Binary files /dev/null and b/games/cat/gfx/toil3.png differ
diff --git a/games/cat/gfx/toil4.png b/games/cat/gfx/toil4.png
new file mode 100644
index 0000000..8238781
Binary files /dev/null and b/games/cat/gfx/toil4.png differ
diff --git a/games/cat/gfx/wside.png b/games/cat/gfx/wside.png
new file mode 100644
index 0000000..43337b0
Binary files /dev/null and b/games/cat/gfx/wside.png differ
diff --git a/games/cat/main.lua b/games/cat/main.lua
new file mode 100644
index 0000000..3007888
--- /dev/null
+++ b/games/cat/main.lua
@@ -0,0 +1,49 @@
+game.codepage="UTF-8";
+game.act = 'Не получается.';
+game.inv = 'Гм.. Странная штука..';
+game.use = 'Не сработает...';
+game.dsc = [[Команды:^
+ look(или просто ввод), act <на что> (или просто на что), use <что> [на что], go <куда>,^
+ back, inv, way, obj, quit, save , load . Работает автодополнение по табуляции.^^
+Олег Г., Владимир П., Илья.Р., и другие в фантастической и драматической text-adventure Петра К.^^
+ВОЗВРАЩЕНИЕ КВАНТОВОГО КОТА^^
+В прошлом хакер. Он ушел жить в лес. Но он вернулся. Вернулся чтобы забрать своего кота.^^
+- Я ПРОСТО ПРИШЕЛ ЗАБРАТЬ СВОЕГО КОТА... ^^]];
+me().nam = 'Олег';
+main = room {
+ nam = 'ВОЗВРАЩЕНИЕ КВАНТОВОГО КОТА',
+ pic = 'gfx/thecat.png',
+ dsc = [[
+За окном моей хижины снова белеет снег, а в камине также как и тогда потрескивают дрова... Третья зима.
+Прошло уже две зимы, но те события, о которых я хочу рассказать, встают перед моими глазами так,
+словно это было вчера...^^
+
+Я работал лесником уже больше десяти лет. Больше десяти лет я жил в своей хижине, окруженной лесом, собирая
+капканы браконьеров и выезжая раз в одну или две недели в близлежащий поселок... После воскресной
+службы в местной церкви я заходил в магазинчик и покупал необходимые мне вещи: патроны к дробовику,
+крупу, хлеб, лекарства...^^
+
+Когда-то я был неплохим компьютерным специалистом... Впрочем, это уже не важно... Десять лет я не видел экрана
+монитора, и не жалею об этом.^^
+
+Теперь я понимаю, что корни того, что тогда произошло лежат давно -- во второй половине 30-х... Хотя лучше
+начать все по-порядку...^^
+
+В тот холодный февральский день я как всегда собрался ехать в поселок...]],
+obj = { vobj(1,'Дальше','{Дальше}') },
+act = function()
+ return goto('home');
+end,
+exit = function()
+ set_music("mus/ofd.xm");
+end,
+};
+set_music("mus/new.s3m");
+dofile("ep1.lua");
+dofile("ep2.lua");
+dofile("ep3.lua");
+
+--me().where = 'eside';
+--inv():add('mywear');
+--inv():add('gun');
+--inv():add('trap');
diff --git a/games/cat/mus/foot.mod b/games/cat/mus/foot.mod
new file mode 100644
index 0000000..2ded75e
Binary files /dev/null and b/games/cat/mus/foot.mod differ
diff --git a/games/cat/mus/hispeed.s3m b/games/cat/mus/hispeed.s3m
new file mode 100644
index 0000000..98f8fea
Binary files /dev/null and b/games/cat/mus/hispeed.s3m differ
diff --git a/games/cat/mus/hybrid.xm b/games/cat/mus/hybrid.xm
new file mode 100644
index 0000000..2f8d2eb
Binary files /dev/null and b/games/cat/mus/hybrid.xm differ
diff --git a/games/cat/mus/ice.s3m b/games/cat/mus/ice.s3m
new file mode 100644
index 0000000..d7ac6ef
Binary files /dev/null and b/games/cat/mus/ice.s3m differ
diff --git a/games/cat/mus/liberty.s3m b/games/cat/mus/liberty.s3m
new file mode 100644
index 0000000..a36f05c
Binary files /dev/null and b/games/cat/mus/liberty.s3m differ
diff --git a/games/cat/mus/new.s3m b/games/cat/mus/new.s3m
new file mode 100644
index 0000000..e39b131
Binary files /dev/null and b/games/cat/mus/new.s3m differ
diff --git a/games/cat/mus/ofd.xm b/games/cat/mus/ofd.xm
new file mode 100644
index 0000000..7d0a831
Binary files /dev/null and b/games/cat/mus/ofd.xm differ
diff --git a/games/cat/mus/revel.s3m b/games/cat/mus/revel.s3m
new file mode 100644
index 0000000..ca166bd
Binary files /dev/null and b/games/cat/mus/revel.s3m differ
diff --git a/games/cat/mus/under.s3m b/games/cat/mus/under.s3m
new file mode 100644
index 0000000..8b34df0
Binary files /dev/null and b/games/cat/mus/under.s3m differ
diff --git a/games/cat/theme.ini b/games/cat/theme.ini
new file mode 100644
index 0000000..1c4fba4
--- /dev/null
+++ b/games/cat/theme.ini
@@ -0,0 +1,2 @@
+;include = plain
+
diff --git a/games/tutorial/main.lua b/games/tutorial/main.lua
new file mode 100644
index 0000000..6a3c8d5
--- /dev/null
+++ b/games/tutorial/main.lua
@@ -0,0 +1,178 @@
+game.codepage="UTF-8"
+game.dsc = [[Команды:^
+ look(или просто ввод), act <на что> (или просто на что), use <что> [на что], go <куда>,^
+ back, inv, way, obj, quit, save , load . Работает автодополнение по табуляции.^^]];
+
+main = room {
+ nam = 'туториал',
+ act = function()
+ return goto('r1');
+ end,
+ dsc = [[Добро пожаловать в режим обучения instead (sdl версия).
+Каждая сцена игры представляет собой описание статической и динамической части.^^
+
+Динамическая часть сцены состоит из объектов, персонажей и т.д. С динамической частью
+игрок может взаимодействовать с помощью мыши, с помощью нажатий на подсвеченные ссылки.^^
+
+В данной сцене единственным объектом является объект "Дальше" -- который вы видите внизу текста.
+Итак, для продолжения обучения вы можете нажать на "Дальше".
+]],
+ obj = {
+ vobj(1, 'Дальше', '{Дальше}'),
+ },
+};
+apple = obj {
+ nam = 'яблоко',
+ dsc = 'На полу лежит {яблоко}.',
+ tak = 'Вы взяли яблоко.',
+ inv = function(s)
+ s._seen = true;
+ if s._knife then
+ inv():del('apple');
+ return 'Яблоко почищено! Вы его съели.';
+ end
+ return 'Выглядит аппетитно!';
+ end,
+ used = function(s, w)
+ if w == 'knife' and not s._knife and here() == r4 then
+ s._knife = true;
+ return 'Вы чистите яблоко.';
+ end
+ end,
+};
+knife = obj {
+ nam = 'нож',
+ dsc = 'На полу лежит {нож}.',
+ tak = 'Вы взяли нож.',
+ inv = function(s)
+ s._seen = true;
+ return 'Острый нож.';
+ end,
+};
+
+r1 = room {
+ enter = function()
+ lifeon('r1');
+ end,
+ exit = function()
+ lifeoff('r1');
+ end,
+ life = function()
+ if have('apple') and have('knife') then
+ return goto('r2');
+ end
+ end,
+ nam = 'урок 1',
+ dsc = [[Продолжим урок. Сейчас вы находитесь в комнате. Возьмите оба предмета, которые вы видите в этой комнате.
+Напомним, что для этого вы просто используете мышь.]],
+ obj = { 'apple', 'knife' },
+};
+
+r2 = room {
+ nam = 'урок 2',
+ enter = function()
+ lifeon('r2');
+ end,
+ exit = function()
+ lifeoff('r2');
+ end,
+ life = function()
+ if apple._seen and knife._seen then
+ return goto('r3');
+ end
+ end,
+ dsc = [[Отлично!! Теперь у вас появились предметы, которые вы можете использовать или изучать.
+Для этого используется инвентарь. Вы можете смотреть на предметы инвентаря с помощью двойного щелчка мыши.^^
+Итак, посмотрите на ножик. Затем, повторите эту операцию с яблоком.]],
+};
+
+tabl = obj {
+ nam = 'стол',
+ dsc = 'На этом уроке вы видите деревянный {стол}.',
+ act = function(s)
+ if s._knife then
+ s._seen = true;
+ return 'На столе стоит ваш автограф.';
+ end
+ return 'Обычный стол, из дуба.';
+ end,
+ used = function(s, w)
+ if w == 'knife' and not s._knife then
+ s._knife = true;
+ return 'Вы вырезаете что-то ножиком на столе.';
+ end
+ end,
+ obj = { 'vasa' },
+};
+
+vasa = obj {
+ nam = 'ваза',
+ dsc = 'На столе стоит {ваза}.';
+ act = 'Ваза как ваза.';
+}
+
+r3 = room {
+ nam = 'урок 3',
+ enter = function()
+ lifeon('r3');
+ end,
+ exit = function()
+ lifeoff('r3');
+ end,
+ life = function()
+ if tabl._seen then
+ return goto('r4');
+ end
+ end,
+ dsc = [[Хорошо! Вы можете действовать
+предметами инвентаря на другие предметы сцены или инвентаря. Попробуйте использовать нож на стол.
+Для этого нажмите мышью на нож, а за затем на стол. Затем посмотрите на стол.]],
+ obj = { 'tabl' },
+};
+
+r4 = room {
+ nam = 'урок 4',
+ enter = function()
+ apple._knife = false;
+ lifeon('r4');
+ end,
+ exit = function()
+ lifeoff('r4');
+ end,
+ life = function()
+ if not have('apple') then
+ return goto('r5');
+ end
+ end,
+ dsc = [[Ладно, а теперь -- почистите яблоко. Затем съешьте яблоко.]],
+};
+
+r5 = room {
+ nam = 'урок 5',
+ dsc = [[Хорошо. Изучаем переходы. Идите на урок 6. Для этого нажмите мышью на соответствующую ссылку.]],
+ exit = function(s, t)
+ if t ~= 'r6' then
+ return 'Я просил идти на урок 6...', false;
+ end
+ end,
+ way = { 'r1', 'r2', 'r3', 'r4', 'r6'},
+};
+
+r6 = room {
+ nam = 'урок 6',
+ dsc = [[Идите на последний урок.]],
+ exit = function(s, t)
+ if t ~= 'theend' then
+ return 'Я просил идти на последний урок...', false;
+ end
+ end,
+ way = { 'r1', 'r2', 'r3', 'r4', 'r6', 'theend'},
+};
+
+theend = room {
+ nam = 'последний урок',
+ dsc = [[Вы можете сохранять игру, выбрать другую игру или выполнять иные действия с помощью меню.
+Для вызова меню нажмите клавишу esc или нажмите мышью на символ меню (справа снизу).
+Теперь вы готовы к игре. Удачи!!!]],
+};
+
diff --git a/readme.txt b/readme.txt
new file mode 100644
index 0000000..88d9920
--- /dev/null
+++ b/readme.txt
@@ -0,0 +1,19 @@
+Deps:
+sdl, sdl-mixer, sdl-image, sdl-ttf, lua5.1
+
+On debian systems:
+apt-get install liblua5.1-dev libreadline-dev libsdl1.2-dev libsdl-ttf2.0-dev libsdl-image1.2-dev libsdl-mixer1.2-dev libreadline5-dev
+
+make
+make install
+sdl-instead
+
+To run just from build dir use:
+
+rm Rules.make
+ln -s Rules.make.standalone Rules.make
+make clean
+make
+./sdl-instead
+
+
diff --git a/sdl-instead b/sdl-instead
new file mode 120000
index 0000000..9a492ab
--- /dev/null
+++ b/sdl-instead
@@ -0,0 +1 @@
+src/sdl-instead/sdl-instead
\ No newline at end of file
diff --git a/src/instead/COPYING b/src/instead/COPYING
new file mode 100644
index 0000000..d60c31a
--- /dev/null
+++ b/src/instead/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ , 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/src/instead/Makefile b/src/instead/Makefile
new file mode 100644
index 0000000..c24a715
--- /dev/null
+++ b/src/instead/Makefile
@@ -0,0 +1,11 @@
+#!/usr/bin/make -f
+include ../../Rules.make
+all: instead
+instead: instead.c rline.c
+ $(CC) $(CFLAGS) -DSTEAD_PATH=\"${STEADPATH}/\" instead.c $(LUA_CFLAGS) $(LUA_LFLAGS) rline.c -lreadline -o instead
+clean:
+ rm -rf *.o instead
+install:
+ install -d -m 0755 $(BIN)
+ install -m 0755 instead $(BIN)/instead
+
diff --git a/src/instead/instead.c b/src/instead/instead.c
new file mode 100644
index 0000000..a821d7f
--- /dev/null
+++ b/src/instead/instead.c
@@ -0,0 +1,84 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+/* the Lua interpreter */
+
+lua_State* L;
+
+extern char *fromgame(char *s);
+
+char *getstring(char *cmd)
+{
+ char *s;
+ if (luaL_dostring(L, cmd)) {
+ fprintf(stderr,"Error: %s\n", lua_tostring(L, -1));
+ exit(1);
+ }
+ s = (char*)lua_tostring(L, -1);
+ if (s)
+ s = fromgame(s);
+ return s;
+}
+
+int luacall(char *cmd)
+{
+ int rc;
+ if (luaL_dostring(L, cmd)) {
+ fprintf(stderr,"Error: %s\n", lua_tostring(L, -1));
+ exit(1);
+ }
+ rc = lua_tonumber(L, -1);
+ return rc;
+}
+
+extern int loop(void);
+extern int width;
+extern int height;
+int main (int argc, char *argv[])
+{
+ int opt;
+ setlocale(LC_ALL,"");
+ /* initialize Lua */
+
+ while ((opt = getopt(argc, argv, "w:h:")) != -1) {
+ switch (opt) {
+ case 'w':
+ width = atoi(optarg);
+ break;
+ case 'h':
+ height = atoi(optarg);
+ break;
+ }
+ }
+ if (argc < 2 || argc - optind < 1) {
+ fprintf(stderr,"Usage: %s [-w] [-h]\n", argv[0]);
+ return 1;
+ }
+ if (width == 0 || height == 0) {
+ fprintf(stderr,"Wrong geometry.\n");
+ return 1;
+ }
+
+ L = lua_open();
+ luaL_openlibs(L);
+ if (luaL_loadfile(L,STEAD_PATH"stead.lua") || lua_pcall(L, 0, 0, 0)) {
+ fprintf(stderr,"Error:%s\n", lua_tostring(L, -1));
+ return 1;
+ }
+
+ if (luaL_loadfile(L,argv[optind]) || lua_pcall(L, 0, 0, 0)) {
+ fprintf(stderr,"Error:%s\n", lua_tostring(L, -1));
+ return 1;
+ }
+ loop();
+ /* cleanup Lua */
+ lua_close(L);
+ return 0;
+}
+
diff --git a/src/instead/rline.c b/src/instead/rline.c
new file mode 100644
index 0000000..a8de73c
--- /dev/null
+++ b/src/instead/rline.c
@@ -0,0 +1,526 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#ifdef HAVE_ICONV
+#include
+#include
+#endif
+
+extern char *getstring(char *cmd);
+
+char *stripwhite(char *string)
+{
+ char *s, *t;
+
+ for (s = string; isspace(*s); s++);
+
+ if (*s == 0)
+ return (s);
+
+ t = s + strlen(s) - 1;
+ while (t > s && isspace(*t))
+ t--;
+ *++t = '\0';
+
+ return s;
+}
+
+#define MAX_WORDS 255
+struct completion;
+struct completion {
+ char *list;
+ char *words[MAX_WORDS + 1];
+ int ids[MAX_WORDS + 1];
+ int num;
+ int period;
+ int id;
+ int hide;
+ struct completion *next;
+};
+
+struct completion obj_comp = { .list = NULL, .id = 1,};
+struct completion way_comp = { .list = NULL, .id = 1,};
+struct completion inv_comp = { .list = NULL, .period = 1, .id = 1,};
+struct completion cmd_comp = { .list = NULL, .hide = 1,};
+
+int comp_num(struct completion *c) {
+ int num = 0;
+ for (; c && !c->hide; c = c->next) {
+ num += c->num;
+ }
+ return num;
+}
+
+char *comp_generator(const char *text, int state, struct completion *co)
+{
+ struct completion *c = co;
+ static int list_index;
+ int len;
+ char *name;
+ int i = 0, id;
+ int index = 0;
+ if (!state) {
+ list_index = 0;
+ }
+ len = strlen(text);
+ for (; c && (index != list_index);) {
+ for (i = 0; (index != list_index) && c->words[i]; i ++)
+ index ++;
+ if (index != list_index)
+ c = c->next;
+ }
+ for (;c; c = c->next) {
+ if (c->hide && !len)
+ continue;
+ id = (c->id)?atoi(text):0;
+ if (id) {
+ if (state)
+ continue;
+ }
+ for (; (name = c->words[i]); i ++) {
+ name = c->words[i];
+ list_index ++;
+ if (id == c->ids[i] || strncmp(name, text, len) == 0) {
+ int expand = 0;
+ char *s = malloc(strlen(name) + 16);
+ if (!s)
+ return NULL;
+ *s = 0;
+ if ( len == 0 && !id) {
+ if (comp_num(co) >1 && c->id) {
+ expand = 1;
+ sprintf(s, "%02d:", c->ids[i]);
+ }
+ }
+ strcat(s, name);
+ if (c->period) {
+ if (expand)
+ strcat(s, "(*)");
+ else if (c->period == 1)
+ strcat(s, ",");
+ } else
+ strcat(s, " ");
+ return s;
+ }
+ }
+ i = 0;
+ }
+ return NULL;
+}
+
+void getcompletion(char *list, struct completion *c)
+{
+ int i;
+ char *p;
+ char *s = list;
+ c->num = 0;
+ if (c->list)
+ free(c->list);
+ c->list = list;
+ for (i = 0; list && i < MAX_WORDS && *s; i++) {
+ while (isspace(*s))
+ s ++;
+ if (!*s)
+ break;
+ c->words[i] = s;
+ c->num ++;
+ s += strcspn(s, ",(");
+ c->ids[i] = -1;
+ if (*s == '(') {
+ p = s;
+ s ++;
+ c->ids[i] = atoi(s);
+ s += strcspn(s, ",)");
+ if (*s == ')')
+ s ++;
+ *p = 0;
+ }
+ if (*s == ',') {
+ *s = 0;
+ s ++;
+ }
+ }
+ c->words[i] = NULL;
+ return;
+}
+
+char *obj_generator(const char *text, int state)
+{
+ obj_comp.next = NULL;
+ return comp_generator(text, state, &obj_comp);
+}
+
+char *way_generator(const char *text, int state)
+{
+ return comp_generator(text, state, &way_comp);
+}
+
+char *inv_generator(const char *text, int state)
+{
+ inv_comp.next = NULL;
+ inv_comp.period = 1;
+ return comp_generator(text, state, &inv_comp);
+}
+
+char *objcmd_generator(const char *text, int state)
+{
+ obj_comp.next = &cmd_comp;
+ return comp_generator(text, state, &obj_comp);
+}
+
+char *objinv_generator(const char *text, int state)
+{
+ obj_comp.next = &inv_comp;
+ inv_comp.period = -1;
+ return comp_generator(text, state, &obj_comp);
+}
+
+
+char *search_word(char *text, char **words, int n, int len)
+{
+ int i;
+ char *t = strdup(text);
+ if (!t)
+ return NULL;
+ t[len] = 0;
+ while (isspace(*text))
+ text ++;
+ for (i = 0; i < n; i++) {
+ if (!strncmp(text, words[i], strlen(words[i]))) {
+ free(t);
+ return words[i];
+ }
+ }
+ free(t);
+ return NULL;
+}
+
+char **tquest_completion(char *text, int start, int end)
+{
+ char **matches;
+ rl_attempted_completion_over = 1;
+ matches = (char **) NULL;
+ /* If this word is at the start of the line, then it is a command
+ to complete. Otherwise it is the name of a file in the current
+ directory. */
+ //str = strdup(rl_line_buffer);
+ if (start == 0)
+ matches = rl_completion_matches(text, objcmd_generator);
+ else {
+ char *n = search_word(rl_line_buffer, cmd_comp.words, cmd_comp.num, rl_point);
+ if (!n)
+ return (matches);
+ else if (!strcmp(n, "go"))
+ matches = rl_completion_matches(text, way_generator);
+ else if (!strcmp(n, "use")) {
+ if (!strstr(rl_line_buffer,",")) {
+ matches = rl_completion_matches(text, inv_generator);
+ } else {
+ matches = rl_completion_matches(text, objinv_generator);
+ }
+ } else if (!strcmp(n, "act")) {
+ matches = rl_completion_matches(text, obj_generator);
+ } else if (!strcmp(n, "load") || !strcmp(n, "save")) {
+ rl_attempted_completion_over = 0;
+ }
+ }
+ return (matches);
+}
+
+/* Tell the GNU Readline library how to complete. We want to try to complete
+ on command names if this is the first word in the line, or on filenames
+ if not. */
+#ifdef HAVE_ICONV
+static char curcp[64];
+static char *fromcp;
+#endif
+void initialize_readline(void)
+{
+ /* Allow conditional parsing of the ~/.inputrc file. */
+ rl_readline_name = "instead";
+ rl_completion_append_character=0;
+ rl_basic_word_break_characters = " \t,";
+ rl_parse_and_bind(strdup("set show-all-if-ambiguous on"));
+ rl_parse_and_bind(strdup("Control-u: 'use '"));
+ rl_parse_and_bind(strdup("Control-a: 'act '"));
+ rl_parse_and_bind(strdup("Control-g: 'go '"));
+ /* Tell the completer that we want a crack first. */
+ rl_attempted_completion_function = (CPPFunction *) tquest_completion;
+#ifdef HAVE_ICONV
+ strncpy(curcp, nl_langinfo(CODESET), sizeof(curcp));
+ fromcp = getstring("return game.codepage;");
+#endif
+}
+
+wchar_t *string_towc(const char *str)
+{
+ wchar_t *pwstr=NULL;
+ size_t size;
+ if (!str)
+ return NULL;
+ pwstr = malloc((1 + strlen(str)) * sizeof(wchar_t));
+ size = mbstowcs(pwstr, str, strlen(str));
+ if (size == (size_t)-1) {
+ free(pwstr);
+ return NULL;
+ }
+ pwstr[size] = 0;
+ return pwstr;
+}
+
+char *string_fromwc(const wchar_t *str)
+{
+ char *pstr=NULL;
+ size_t mbs_size;
+ if (!str)
+ return NULL;
+ mbs_size = wcstombs(NULL, str, 0);
+ if (mbs_size == (size_t)-1)
+ return NULL;
+ pstr = malloc(mbs_size + 1);
+ pstr[ wcstombs(pstr, str, mbs_size) ] = 0;
+ return pstr;
+}
+#ifdef HAVE_ICONV
+#define CHAR_MAX_LEN 4
+static char *decode(iconv_t hiconv, const char *s)
+{
+ size_t s_size, chs_size, outsz, insz;
+ char *inbuf, *outbuf, *chs_buf;
+ if (!s || hiconv == (iconv_t)(-1))
+ return NULL;
+ s_size = strlen(s);
+ chs_size = s_size * CHAR_MAX_LEN;
+ if ((chs_buf = malloc(chs_size + CHAR_MAX_LEN))==NULL)
+ goto exitf;
+ outsz = chs_size;
+ outbuf = chs_buf;
+ insz = s_size;
+ inbuf = (char*)s;
+ while (insz) {
+ if (iconv(hiconv, &inbuf, &insz, &outbuf, &outsz)
+ == (size_t)(-1))
+ goto exitf;
+ }
+ *outbuf++ = 0;
+ return chs_buf;
+exitf:
+ if(chs_buf)
+ free(chs_buf);
+ return NULL;
+}
+
+char *fromgame(const char *s)
+{
+ iconv_t han;
+ char *str;
+ if (!s)
+ return NULL;
+ if (!fromcp)
+ goto out0;
+ han = iconv_open(curcp, fromcp);
+ if (han == (iconv_t)-1)
+ goto out0;
+ if (!(str = decode(han, s)))
+ goto out1;
+ iconv_close(han);
+ return str;
+out1:
+ iconv_close(han);
+out0:
+ return strdup(s);
+}
+
+char *togame(const char *s)
+{
+ iconv_t han;
+ char *str;
+ if (!s)
+ return NULL;
+ if (!fromcp)
+ goto out0;
+ han = iconv_open(fromcp, curcp);
+ if (han == (iconv_t)-1)
+ goto out0;
+ if (!(str = decode(han, s)))
+ goto out1;
+ iconv_close(han);
+ return str;
+out1:
+ iconv_close(han);
+out0:
+ return strdup(s);
+}
+#else
+char *fromgame(const char *s)
+{
+ if (!s)
+ return NULL;
+ return strdup(s);
+}
+char *togame(const char *s)
+{
+ if (!s)
+ return NULL;
+ return strdup(s);
+}
+#endif
+
+int width = 80;
+int height = 25;
+#define STDIN_FILENO 0
+
+int getch(void) {
+ struct termios oldt,
+ newt;
+ int ch;
+ tcgetattr( STDIN_FILENO, &oldt );
+ newt = oldt;
+ newt.c_lflag &= ~( ICANON | ECHO );
+ tcsetattr( STDIN_FILENO, TCSANOW, &newt );
+ ch = getchar();
+ tcsetattr( STDIN_FILENO, TCSANOW, &oldt );
+ return ch;
+}
+
+void out(char *str)
+{
+ int lines = 0;
+ int i;
+
+ wchar_t *ws, *wp, saved, *ows;
+ char *ms;
+ size_t sz = width, oldsz;
+ if (!str)
+ return;
+ ows = ws = string_towc(str);
+ if (!ws)
+ return;
+ wp = ws;
+ fprintf(stdout,"\n");
+ for (i = 0; i < width/2 - 6; i++)
+ fprintf(stdout, " ");
+ fprintf(stdout,"* * *\n\n");
+
+ while (*ws && *wp) {
+ wp += wcscspn(wp, L" ,\t\n");
+ if (*wp == ',')
+ wp ++;
+ saved = *wp;
+ *wp = 0;
+ oldsz = sz;
+ sz = wcslen(ws);
+ if (sz > width || saved == '\n') {
+ *wp = saved;
+ if (sz <= width)
+ oldsz = sz;
+ saved = ws[oldsz];
+ ws[oldsz] = 0;
+ lines ++;
+ if (lines >= (height)) {
+ printf("-- more --");
+ getch();
+ printf("\r \r");
+ lines = 0;
+ }
+ ms = string_fromwc(ws);
+ if (ms)
+ printf("%s\n", ms);
+ free(ms);
+ ws[oldsz] = saved;
+ if (saved == L' ' || saved == L'\t' || saved == L'\n')
+ oldsz ++;
+ ws += oldsz;
+ wp = ws;
+ sz = width;
+ continue;
+ }
+ *wp = saved;
+ if (saved)
+ wp ++;
+ }
+ if (wp != ws) {
+ lines ++;
+ if (lines > height) {
+ printf("-- more --");
+ getch();
+ printf("\r");
+ lines = 0;
+ }
+ ms = string_fromwc(ws);
+ if (ms)
+ printf("%s\n", ms);
+ free(ms);
+ }
+ free(ows);
+ free(str);
+}
+
+void execute_line(char *s)
+{
+ char buf[1024];
+ char *p = s;
+ while (*p) {
+ if (*p == '\\' || *p == '\'' || *p == '\"' || *p == '[' || *p == ']')
+ return;
+ p ++;
+ }
+ s = togame(s);
+ snprintf(buf, sizeof(buf), "return iface:cmd('%s')", s);
+ p = getstring(buf);
+ free(s);
+ out(p);
+}
+extern int luacall(char *cmd);
+
+void loop(void)
+{
+ char *line, *s;
+
+ initialize_readline(); /* Bind our completer. */
+ getcompletion(strdup("act,look,go,back,use,load,save,quit,help,obj,inv,way,ls"), &cmd_comp);
+ out(getstring("return (par('',fmt(game:ini()),iface:cmd('look')));"));
+// out(getstring("return fmt(me():look());"));
+ /* Loop reading and executing lines until the user quits. */
+ while (1) {
+ luacall("me():tag();");
+ getcompletion(getstring("return here():str();"), &obj_comp);
+ getcompletion(getstring("return me().obj:str();"), &inv_comp);
+ getcompletion(getstring("return here().way:str();"), &way_comp);
+ line = readline("-- > ");
+
+ if (!line)
+ break;
+
+ /* Remove leading and trailing whitespace from the line.
+ Then, if there is anything left, add it to the history list
+ and execute it. */
+ s = stripwhite(line);
+
+ if (*s) {
+ add_history(s);
+ }
+ if (!strcmp(s, "help")) {
+ printf("Usage: act, look, use, go, back, load, save, quit.\n");
+ } else if (!strcmp(s, "quit"))
+ break;
+ else {
+ execute_line(s);
+ }
+ free(line);
+ }
+ exit(0);
+}
+
+
diff --git a/src/instead/tutorial/main.lua b/src/instead/tutorial/main.lua
new file mode 100644
index 0000000..74b99f2
--- /dev/null
+++ b/src/instead/tutorial/main.lua
@@ -0,0 +1,185 @@
+game.codepage="UTF-8"
+game.dsc = [[Команды:^
+ look(или просто ввод), act <на что> (или просто на что), use <что> [на что], go <куда>,^
+ back, inv, way, obj, quit, save , load . Работает автодополнение по табуляции.^^]];
+
+main = room {
+ nam = 'туториал',
+ act = function()
+ return goto('r1');
+ end,
+ dsc = [[Добро пожаловать в режим обучения instead (readline версия).
+Ввод команд в игре осуществляется с клавиатуры. Каждая сцена игры представляет собой
+описание статической и динамической части. Для просмотра сцены вы можете набрать look
+и нажать ввод или просто нажать ввод. При наборе команд работает режим автодополнения по табуляции,
+например, вы можете набрать l и нажать tab. ^^
+
+Данный текст также является сценой, так что вы можете попробовать команду look прямо сейчас.
+
+Динамическая часть сцены состоит из объектов, персонажей и т.д. С динамической частью
+игрок может взаимодействовать с помощью команды act <объект>. При этом, так как это наиболее
+часто используемая команда, слово act можно пропускать. В данной сцене единственным объектом
+является объект "Дальше" -- который вы видите внизу текста. Итак, для продолжения обучения вы можете:
+нажать табуляцию (при этом выберется единственный объект сцены) или набрать act табуляция --
+и нажать ввод.
+]],
+ obj = {
+ vobj(1, 'Дальше', '{Дальше}'),
+ },
+};
+apple = obj {
+ nam = 'яблоко',
+ dsc = 'На полу лежит {яблоко}.',
+ tak = 'Вы взяли яблоко.',
+ inv = function(s)
+ s._seen = true;
+ if s._knife then
+ inv():del('apple');
+ return 'Яблоко почищено! Вы его съели.';
+ end
+ return 'Выглядит аппетитно!';
+ end,
+ used = function(s, w)
+ if w == 'knife' and not s._knife and here() == r4 then
+ s._knife = true;
+ return 'Вы чистите яблоко.';
+ end
+ end,
+};
+knife = obj {
+ nam = 'нож',
+ dsc = 'На полу лежит {нож}.',
+ tak = 'Вы взяли нож.',
+ inv = function(s)
+ s._seen = true;
+ return 'Острый нож.';
+ end,
+};
+
+r1 = room {
+ enter = function()
+ lifeon('r1');
+ end,
+ exit = function()
+ lifeoff('r1');
+ end,
+ life = function()
+ if have('apple') and have('knife') then
+ return goto('r2');
+ end
+ end,
+ nam = 'урок 1',
+ dsc = [[Продолжим урок. Сейчас вы находитесь в комнате. Возьмите оба предмета, которые вы видите в этой комнате.
+Напомним, что для этого вы можете нажать таб и выбрать предмет по первой букве или цифре, или начать с команды act.]],
+ obj = { 'apple', 'knife' },
+};
+
+r2 = room {
+ nam = 'урок 2',
+ enter = function()
+ lifeon('r2');
+ end,
+ exit = function()
+ lifeoff('r2');
+ end,
+ life = function()
+ if apple._seen and knife._seen then
+ return goto('r3');
+ end
+ end,
+ dsc = [[Отлично!! Теперь у вас появились предметы, которые вы можете использовать или изучать.
+Для этого используется команда use. Не забывайте про автодополнение по tab. Вы можете смотреть свой инвентарь
+с помощью команды inv или просто use и табуляция. Итак, посмотрите на ножик. Начните с команды use, потом нажмите табуляцию
+и выберете среди предметов нож. Затем, повторите эту операцию с яблоком.]],
+};
+
+tabl = obj {
+ nam = 'стол',
+ dsc = 'На этом уроке вы видите деревянный стол.',
+ act = function(s)
+ if s._knife then
+ s._seen = true;
+ return 'На столе стоит ваш автограф.';
+ end
+ return 'Обычный стол, из дуба.';
+ end,
+ used = function(s, w)
+ if w == 'knife' and not s._knife then
+ s._knife = true;
+ return 'Вы вырезаете что-то ножиком на столе.';
+ end
+ end,
+ obj = { 'vasa' },
+};
+
+vasa = obj {
+ nam = 'ваза',
+ dsc = 'На столе стоит {ваза}.';
+ act = 'Ваза как ваза.';
+}
+
+r3 = room {
+ nam = 'урок 3',
+ enter = function()
+ lifeon('r3');
+ end,
+ exit = function()
+ lifeoff('r3');
+ end,
+ life = function()
+ if tabl._seen then
+ return goto('r4');
+ end
+ end,
+ dsc = [[Хорошо! Как вы заметили, возле предметов инвентаря стоит символ (*). Вы можете действовать
+предметами инвентаря на другие предметы сцены или инвентаря. Попробуйте использовать нож на стол.
+Для этого наберите use, нажмите табуляцию и выберите нож, затем опять нажмите табуляцию и выберите стол. Затем
+посмотрите на стол командой act табуляция стол или просто нажав табуляцию и выбрав стол.]],
+ obj = { 'tabl' },
+};
+
+r4 = room {
+ nam = 'урок 4',
+ enter = function()
+ apple._knife = false;
+ lifeon('r4');
+ end,
+ exit = function()
+ lifeoff('r4');
+ end,
+ life = function()
+ if not have('apple') then
+ return goto('r5');
+ end
+ end,
+ dsc = [[Ладно, а теперь -- почистите яблоко. Для этого используйте команду use. Затем съешьте яблоко.]],
+};
+
+r5 = room {
+ nam = 'урок 5',
+ dsc = [[Хорошо. Изучаем команду go -- идти. Наберите go и нажмите табуляцию. Идите на урок 6.]],
+ exit = function(s, t)
+ if t ~= 'r6' then
+ return 'Я просил идти на урок 6...', false;
+ end
+ end,
+ way = { 'r1', 'r2', 'r3', 'r4', 'r6'},
+};
+
+r6 = room {
+ nam = 'урок 6',
+ dsc = [[Вы можете посмотреть все пути с помощью команды way или go табуляция. Идите на последний урок.]],
+ exit = function(s, t)
+ if t ~= 'theend' then
+ return 'Я просил идти на последний урок...', false;
+ end
+ end,
+ way = { 'r1', 'r2', 'r3', 'r4', 'r6', 'theend'},
+};
+
+theend = room {
+ nam = 'последний урок',
+ dsc = [[Вы можете сохранять игру: save имяфайла и считывать игру: load имяфайла. Для выхода наберите quit
+Вы можете нажимать control-u для use, control-a для act, control-g для go. Удачи!!!]],
+};
+
diff --git a/src/sdl-instead/COPYING b/src/sdl-instead/COPYING
new file mode 100644
index 0000000..d60c31a
--- /dev/null
+++ b/src/sdl-instead/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ , 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/src/sdl-instead/Makefile b/src/sdl-instead/Makefile
new file mode 100644
index 0000000..30e85f7
--- /dev/null
+++ b/src/sdl-instead/Makefile
@@ -0,0 +1,27 @@
+include ../../Rules.make
+
+CFLAGS += $(SDL_CFLAGS) $(LUA_CFLAGS) -DSTEAD_PATH=\"${STEADPATH}/\" -DGAMES_PATH=\"${GAMESPATH}/\" -DTHEMES_PATH=\"${THEMESPATH}/\" -DVERSION=$(VERSION)
+
+LDFLAGS += $(SDL_LFLAGS) $(LUA_LFLAGS)
+
+SRC := graphics.c input.c game.c main.c instead.c sound.c
+
+OBJ := $(patsubst %.c, %.o, $(SRC))
+
+all: sdl-instead
+PREFIX:=/usr/local
+
+$(OBJ): %.o : %.c gui.h
+ $(CC) -c $(<) $(I) $(CFLAGS)
+
+sdl-instead: $(OBJ)
+ $(CC) $(CFLAGS) $(LDFLAGS) $(^) -o $(@)
+# strip sdl-instead
+
+install:
+ install -d -m 0755 $(BIN)
+ install -m 0755 sdl-instead $(BIN)/sdl-instead
+
+clean:
+ rm -f *.o sdl-instead
+
diff --git a/src/sdl-instead/game.c b/src/sdl-instead/game.c
new file mode 100644
index 0000000..2187507
--- /dev/null
+++ b/src/sdl-instead/game.c
@@ -0,0 +1,1903 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "graphics.h"
+#include "sound.h"
+#include "game.h"
+#include "input.h"
+#include "instead.h"
+
+int opt_fs = 0;
+int opt_hl = 1;
+int opt_hz = 22050;
+int opt_vol = 127;
+int opt_autosave = 0;
+char *opt_game = NULL;
+
+char game_cwd[PATH_MAX];
+char *curgame;
+int cfg_parse(const char *path);
+char *game_cfg_path(void);
+
+int game_save(void);
+
+int cfg_load(void)
+{
+ char *p = game_cfg_path();
+ if (!p)
+ return -1;
+ if (access(p, R_OK))
+ return 0;
+ return cfg_parse(p);
+}
+
+int cfg_save(void)
+{
+ FILE *fp;
+ char *p = game_cfg_path();
+ if (!p)
+ return -1;
+ fp = fopen(p, "w");
+ if (!fp)
+ return -1;
+ fprintf(fp, "fs = %d\nhl = %d\nhz = %d\nvol = %d\nautosave = %d\ngame = %s", opt_fs, opt_hl, opt_hz, opt_vol, opt_autosave, curgame?curgame:"");
+ fclose(fp);
+ return 0;
+}
+
+void game_menu_box(int show, const char *txt);
+
+void game_cursor(int on);
+
+#ifndef THEMES_PATH
+#define THEMES_PATH "./themes"
+#endif
+
+struct theme {
+ int w;
+ int h;
+ color_t bgcol;
+ char *bg_name;
+ img_t bg;
+ char *use_name;
+ img_t use;
+ int pad;
+
+ int win_x;
+ int win_y;
+ int win_w;
+ int win_h;
+
+ char *font_name;
+ int font_size;
+ fnt_t font;
+
+ int max_scene_h;
+
+ char *a_up_name;
+ char *a_down_name;
+ img_t a_up;
+ img_t a_down;
+
+ color_t fgcol;
+ color_t lcol;
+ color_t acol;
+
+ int inv_x;
+ int inv_y;
+ int inv_w;
+ int inv_h;
+ color_t icol;
+ color_t ilcol;
+ color_t iacol;
+ char *inv_font_name;
+ int inv_font_size;
+ 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 lstyle;
+// int ilstyle;
+
+ color_t menu_bg;
+ color_t menu_fg;
+ color_t border_col;
+ color_t menu_link;
+ color_t menu_alink;
+ int menu_alpha;
+ int border_w;
+ char *menu_font_name;
+ int menu_font_size;
+ fnt_t menu_font;
+
+ char *menu_button_name;
+ img_t menu_button;
+ int menu_button_x;
+ int menu_button_y;
+} game_theme = {
+ .w = 800,
+ .h = 480,
+ .bg_name = NULL,
+ .bg = NULL,
+ .use_name = NULL,
+ .use = NULL,
+ .font_name = NULL,
+ .font = NULL,
+ .a_up_name = NULL,
+ .a_down_name = NULL,
+ .a_up = NULL,
+ .a_down = NULL,
+ .inv_font_name = NULL,
+ .inv_font = NULL,
+ .inv_a_up_name = NULL,
+ .inv_a_down_name = NULL,
+ .inv_a_up = NULL,
+ .inv_a_down = NULL,
+ .menu_font_name = NULL,
+ .menu_font = NULL,
+ .menu_button_name = NULL,
+ .menu_button = NULL,
+};
+
+#define FREE(v) do { if ((v)) free((v)); v = NULL; } while(0)
+
+void free_theme_strings()
+{
+ struct theme *t = &game_theme;
+ FREE(t->use_name);
+ FREE(t->bg_name);
+ FREE(t->inv_a_up_name);
+ FREE(t->inv_a_down_name);
+ FREE(t->a_down_name);
+ FREE(t->a_up_name);
+ FREE(t->font_name);
+ FREE(t->inv_font_name);
+ FREE(t->menu_font_name);
+ FREE(t->menu_button_name);
+}
+
+int game_theme_free(void)
+{
+ free_theme_strings();
+
+ if (game_theme.font)
+ fnt_free(game_theme.font);
+ if (game_theme.inv_font)
+ fnt_free(game_theme.inv_font);
+ if (game_theme.menu_font)
+ fnt_free(game_theme.menu_font);
+
+ if (game_theme.a_up)
+ gfx_free_image(game_theme.a_up);
+ if (game_theme.a_down)
+ gfx_free_image(game_theme.a_down);
+ if (game_theme.inv_a_up)
+ gfx_free_image(game_theme.inv_a_up);
+ if (game_theme.inv_a_down)
+ gfx_free_image(game_theme.inv_a_down);
+
+ if (game_theme.use)
+ gfx_free_image(game_theme.use);
+
+ if (game_theme.bg)
+ gfx_free_image(game_theme.bg);
+
+ if (game_theme.menu_button)
+ gfx_free_image(game_theme.menu_button);
+
+ game_theme.font = game_theme.inv_font = game_theme.menu_font = NULL;
+ game_theme.a_up = game_theme.a_down = game_theme.use = NULL;
+ game_theme.inv_a_up = game_theme.inv_a_down = NULL;
+ game_theme.menu_button = NULL;
+ game_theme.bg = NULL;
+// game_theme.slide = gfx_load_image("slide.png", 1);
+ return 0;
+}
+
+int game_theme_init(void)
+{
+ struct theme *t = &game_theme;
+
+ if (t->font_name) {
+ fnt_free(t->font);
+ if (!(t->font = fnt_load(t->font_name, t->font_size)))
+ goto err;
+ }
+
+ if (t->inv_font_name) {
+ fnt_free(t->inv_font);
+ if (!(t->inv_font = fnt_load(t->inv_font_name, t->inv_font_size)))
+ goto err;;
+ }
+
+
+ if (t->menu_font_name) {
+ fnt_free(t->menu_font);
+ if (!(t->menu_font = fnt_load(t->menu_font_name, t->menu_font_size)))
+ goto err;
+ }
+
+
+ if (t->a_up_name) {
+ gfx_free_image(t->a_up);
+ if (!(t->a_up = gfx_load_image(t->a_up_name, 1)))
+ goto err;
+ }
+
+ if (t->a_down_name) {
+ gfx_free_image(t->a_down);
+ if (!(t->a_down = gfx_load_image(t->a_down_name, 1)))
+ goto err;
+ }
+
+ if (t->inv_a_up_name) {
+ gfx_free_image(t->inv_a_up);
+ if (!(t->inv_a_up = gfx_load_image(t->inv_a_up_name, 1)))
+ 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, 1)))
+ goto err;
+ }
+
+ if (t->bg_name) {
+ gfx_free_image(t->bg);
+ t->bg = NULL;
+ if (t->bg_name[0] && !(t->bg = gfx_load_image(t->bg_name, 0)))
+ goto err;
+ }
+
+ if (t->use_name) {
+ gfx_free_image(t->use);
+ if (!(t->use = gfx_load_image(t->use_name, 1)))
+ goto err;
+ }
+
+ if (t->menu_button_name) {
+ gfx_free_image(t->menu_button);
+ if (!(t->menu_button = gfx_load_image(t->menu_button_name, 1)))
+ goto err;
+ }
+
+ free_theme_strings();
+
+ if (!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.\n");
+ return -1;
+ }
+ return 0;
+err:
+ game_theme_free();
+ return -1;
+}
+
+int theme_load(const char *name);
+
+int game_theme_load(const char *name)
+{
+ char cwd[PATH_MAX];
+ getcwd(cwd, sizeof(cwd));
+ if (chdir(THEMES_PATH) || chdir(name) || theme_load("theme.ini")) {
+ chdir(cwd);
+ return -1;
+ }
+ chdir(cwd);
+ return 0;
+}
+
+int game_default_theme(void)
+{
+ return game_theme_load("default");
+}
+
+typedef int (*parser_fn)(const char *v, void *data);
+
+int parse_string(const char *v, void *data)
+{
+ char **p = ((char **)data);
+ if (*p)
+ free(*p);
+ *p = strdup(v);
+ if (!*p)
+ return -1;
+ return 0;
+}
+
+int parse_int(const char *v, void *data)
+{
+ int *i = (int *)data;
+ char *eptr = NULL;
+ *i = strtol(v, &eptr, 0);
+ if (!eptr || *eptr)
+ return -1;
+ return 0;
+}
+
+int parse_color(const char *v, void *data)
+{
+ color_t *c = (color_t *)data;
+ return gfx_parse_color(v, c);
+}
+
+int parse_include(const char *v, void *data)
+{
+ int rc;
+ char cwd[PATH_MAX];
+ getcwd(cwd, sizeof(cwd));
+ chdir(game_cwd);
+ rc = game_theme_load(v);
+ chdir(cwd);
+ return rc;
+}
+
+struct parser {
+ const char *cmd;
+ parser_fn fn;
+ void *p;
+};
+
+struct parser cfg_parser[] = {
+ { "hz", parse_int, &opt_hz },
+ { "fs", parse_int, &opt_fs },
+ { "vol", parse_int, &opt_vol },
+ { "hl", parse_int, &opt_hl },
+ { "game", parse_string, &opt_game },
+ { "autosave", parse_int, &opt_autosave },
+ { NULL, },
+};
+
+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_string, &game_theme.bg_name },
+ { "scr.gfx.use", parse_string, &game_theme.use_name },
+ { "scr.gfx.pad", parse_int, &game_theme.pad },
+
+ { "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_string, &game_theme.font_name },
+ { "win.fnt.size", parse_int, &game_theme.font_size },
+ { "win.gfx.h", parse_int, &game_theme.max_scene_h },
+ { "win.gfx.up", parse_string, &game_theme.a_up_name },
+ { "win.gfx.down", parse_string, &game_theme.a_down_name },
+ { "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.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_string, &game_theme.inv_font_name },
+ { "inv.fnt.size", parse_int, &game_theme.inv_font_size },
+ { "inv.gfx.up", parse_string, &game_theme.inv_a_up_name },
+ { "inv.gfx.down", parse_string, &game_theme.inv_a_down_name },
+
+ { "menu.col.bg", parse_color, &game_theme.menu_bg },
+ { "menu.col.fg", parse_color, &game_theme.menu_fg },
+ { "menu.col.link", parse_color, &game_theme.menu_link },
+ { "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_string, &game_theme.menu_font_name },
+ { "menu.fnt.size", parse_int, &game_theme.menu_font_size },
+ { "menu.gfx.button", parse_string, &game_theme.menu_button_name },
+ { "menu.buttonx", parse_int, &game_theme.menu_button_x },
+ { "menu.buttony", parse_int, &game_theme.menu_button_y },
+ { "include", parse_include, NULL },
+ { NULL, },
+};
+
+char *strip(char *s)
+{
+ char *e;
+ while (isspace(*s))
+ s ++;
+ if (!*s)
+ return s;
+ e = s + strlen(s) - 1;
+ while (e != s && isspace(*e)) {
+ *e = 0;
+ e --;
+ }
+ return s;
+}
+
+int process_cmd(char *n, char *v, struct parser *cmd_parser)
+{
+ int i;
+ n = strip(n);
+ v = strip(v);
+ for (i = 0; cmd_parser[i].cmd; i++) {
+ if (!strcmp(cmd_parser[i].cmd, n)) {
+ return cmd_parser[i].fn(v, cmd_parser[i].p);
+ }
+ }
+ return -1;
+}
+
+int parse_ini(const char *path, struct parser *cmd_parser)
+{
+ int rc = 0;
+ int line_nr = 0;
+ FILE *fp;
+ char line[1024];
+ fp = fopen(path, "r");
+ if (!fp)
+ return -1;
+ while (fgets(line, sizeof(line), fp)) {
+ char *p = line;
+ char *val;
+ int len;
+ line_nr ++;
+ p += strspn(p, " \t");
+ if (*p == ';')
+ continue;
+ len = strcspn(p, "=");
+ if (p[len] != '=')
+ continue;
+ p[len] = 0;
+ val = p + len + 1;
+ len = strcspn(p, " \t");
+ p[len] = 0;
+// printf("%s\n", p);
+ val += strspn(val, " \t");
+ val[strcspn(val, "\n")] = 0;
+ if (process_cmd(p, val, cmd_parser)) {
+ rc = -1;
+ fprintf(stderr, "Can't process cmd '%s' on line %d : %s\n", p, line_nr, strerror(errno));
+ }
+ }
+ fclose(fp);
+ return rc;
+}
+
+int theme_parse(const char *path)
+{
+ if (parse_ini(path, cmd_parser)) {
+ game_theme_free();
+ return -1;
+ }
+ return 0;
+}
+
+int theme_load(const char *name)
+{
+ if (theme_parse(name))
+ return -1;
+ if (game_theme_init())
+ return -1;
+ return 0;
+}
+
+int cfg_parse(const char *path)
+{
+ return parse_ini(path, cfg_parser);
+}
+
+#ifndef GAMES_PATH
+#define GAMES_PATH "./games"
+#endif
+
+char *getpath(const char *d, const char *n)
+{
+ int i = strlen(d) + strlen(n) + 3;
+ char *p = malloc(i);
+ if (p) {
+ strcpy(p, d);
+ strcat(p, "/");
+ strcat(p, n);
+ strcat(p, "/");
+ }
+ return p;
+}
+
+#define MAIN_FILE "main.lua"
+
+int is_game(const char *n)
+{
+ int rc = 0;
+ char *p = getpath(GAMES_PATH, n);
+ char *pp;
+ if (!p)
+ return 0;
+ pp = malloc(strlen(p) + strlen(MAIN_FILE) + 1);
+ if (pp) {
+ strcpy(pp, p);
+ strcat(pp, MAIN_FILE);
+ if (!access(pp, R_OK))
+ rc = 1;
+ free(pp);
+ }
+ free(p);
+ return rc;
+}
+
+struct game {
+ char *path;
+ char *name;
+};
+
+struct game *games;
+int games_nr = 0;
+
+int game_select(const char *name)
+{
+ int i;
+ if (!name || !*name) {
+ if (games_nr == 1)
+ name = games[0].name;
+ else
+ return 0;
+ }
+ chdir(game_cwd);
+ for (i = 0; ipw_dir);
+ return save_path;
+
+}
+char *game_save_path(int cr)
+{
+ struct passwd *pw;
+ if (!curgame)
+ return NULL;
+ pw = getpwuid(getuid());
+ if (!pw)
+ return NULL;
+ snprintf(save_path, sizeof(save_path) - 1 , "%s/.instead/", pw->pw_dir);
+ if (cr && mkdir(save_path, S_IRWXU) && errno != EEXIST)
+ return NULL;
+ snprintf(save_path, sizeof(save_path) - 1 , "%s/.instead/saves", pw->pw_dir);
+ if (cr && mkdir(save_path, S_IRWXU) && errno != EEXIST)
+ return NULL;
+ snprintf(save_path, sizeof(save_path) - 1, "%s/.instead/saves/%s/", pw->pw_dir, curgame);
+ if (cr && mkdir(save_path, S_IRWXU) && errno != EEXIST)
+ return NULL;
+ snprintf(save_path, sizeof(save_path) - 1, "%s/.instead/saves/%s/autosave", pw->pw_dir, curgame);
+ return save_path;
+}
+
+int games_lookup(void)
+{
+ char *p;
+ int n = 0;
+ DIR *d;
+ struct dirent *de;
+ d = opendir(GAMES_PATH);
+ if (!d)
+ return -1;
+ while ((de = readdir(d))) {
+ if (de->d_type != DT_DIR)
+ continue;
+ if (!is_game(de->d_name))
+ continue;
+ n ++;
+ }
+ rewinddir(d);
+ if (!n)
+ return 0;
+ games = malloc(sizeof(struct game) * n);
+ while ((de = readdir(d)) && games_nr < n) {
+ if (de->d_type != DT_DIR)
+ continue;
+ if (!is_game(de->d_name))
+ continue;
+ p = getpath(GAMES_PATH, de->d_name);
+ games[games_nr].path = p;
+ games[games_nr].name = strdup(de->d_name);
+ games_nr ++;
+ }
+ closedir(d);
+ return 0;
+}
+
+
+static char *last_pict = NULL;
+static char *last_title = NULL;
+static char *last_music = NULL;
+static int mx, my;
+static img_t menubg = NULL;
+static img_t menu = NULL;
+static int cur_menu = 0;
+static int menu_shown = 0;
+enum {
+ menu_main = 0,
+ menu_about,
+ menu_settings,
+ menu_quit,
+ menu_askquit,
+ menu_saved,
+ menu_games,
+};
+int game_cmd(char *cmd);
+int change_vol(int d, int val);
+
+void game_clear(int x, int y, int w, int h)
+{
+ if (game_theme.bg)
+ gfx_draw_bg(game_theme.bg, x, y, w, h);
+ else
+ gfx_clear(x, y, w, h);
+
+ if (menu_shown) {
+ int xx = x - mx;
+ int yy = y - my;
+ gfx_draw_from(menubg, xx, yy, x, y, w, h);
+ gfx_draw_from(menu, xx, yy, x, y, w, h);
+ // gfx_update(mx, my, ww, hh);
+ return;
+ }
+}
+
+
+
+void game_clear(int x, int y, int w, int h);
+
+
+struct el {
+ int id;
+ int x;
+ int y;
+ int type;
+ int drawn;
+// int clone;
+ union {
+ layout_t lay;
+ textbox_t box;
+ img_t img;
+ void *p;
+ } p;
+};
+
+enum {
+ elt_box,
+ elt_layout,
+ elt_image,
+};
+
+enum {
+ el_menu = 0,
+ el_title,
+ el_ways,
+ el_inv,
+ el_scene,
+ el_sup,
+ el_sdown,
+// el_sslide,
+ el_iup,
+ el_idown,
+// el_islide,
+ el_spic,
+ el_menu_button,
+ el_max,
+};
+
+struct el objs[el_max];
+
+void el_set(int i, int t, int x, int y, void *p)
+{
+ objs[i].id = i;
+ objs[i].x = x;
+ objs[i].y = y;
+ objs[i].p.p = p;
+ objs[i].type = t;
+ objs[i].drawn = 0;
+// objs[i].clone = 0;
+}
+void el_set_clone(int i, int t, int x, int y, void *p)
+{
+ el_set(i, t, x, y, p);
+// objs[i].clone = 1;
+}
+
+struct el *el(int num)
+{
+ return &objs[num];
+}
+textbox_t el_box(int num)
+{
+ return objs[num].p.box;
+}
+
+layout_t el_layout(int num)
+{
+ return objs[num].p.lay;
+}
+
+img_t el_img(int num)
+{
+ return objs[num].p.img;
+}
+char *game_menu_gen(void);
+
+
+void el_draw(int n);
+int game_init(const char *name)
+{
+ char *s;
+ layout_t lay;
+ textbox_t box;
+ getcwd(game_cwd, sizeof(game_cwd));
+ cfg_load();
+ if (!name && opt_game)
+ name = opt_game;
+ if (gfx_init(game_theme.w, game_theme.h, opt_fs))
+ return -1;
+ snd_init(opt_hz);
+ change_vol(0, opt_vol);
+ if (game_default_theme())
+ return -1;
+ if (game_select(name)) {
+ name = NULL;
+ }
+ if (!access("theme.ini", R_OK)) {
+ if (theme_load("theme.ini"))
+ return -1;
+ }
+ gfx_bg(game_theme.bgcol);
+ game_clear(0, 0, game_theme.w, game_theme.h);
+// if (instead_init("cat.lua"))
+// return -1;
+// gfx_update(0, 0, game_theme.w, game_theme.h);
+ lay = txt_layout(game_theme.font, ALIGN_JUSTIFY, game_theme.win_w, game_theme.win_h);
+ if (!lay)
+ return -1;
+ box = txt_box(game_theme.win_w, game_theme.win_h);
+ if (!box)
+ return -1;
+ 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_link_style(lay, game_theme.lstyle);
+
+ txt_box_set(box, lay);
+ el_set(el_scene, elt_box, game_theme.win_x, 0, box);
+
+ lay = txt_layout(game_theme.inv_font, ALIGN_LEFT, game_theme.inv_w, game_theme.inv_h);
+ if (!lay)
+ return -1;
+ txt_layout_link_color(lay, game_theme.ilcol);
+ txt_layout_active_color(lay, game_theme.iacol);
+// txt_layout_link_style(lay, game_theme.ilstyle);
+ box = txt_box(game_theme.inv_w, game_theme.inv_h);
+ if (!box)
+ return -1;
+
+ txt_box_set(box, lay);
+ el_set(el_inv, elt_box, game_theme.inv_x, game_theme.inv_y, box);
+
+ lay = txt_layout(game_theme.font, ALIGN_CENTER, game_theme.win_w, 0);
+ if (!lay)
+ return -1;
+
+ 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);
+ if (!lay)
+ return -1;
+ el_set(el_ways, elt_layout, game_theme.win_x, 0, lay);
+
+ el_set(el_sdown, elt_image, 0, 0, game_theme.a_down);
+ el_set(el_sup, elt_image, 0, 0, game_theme.a_up);
+// el_set(el_sslide, elt_image, 0, 0, game_theme.slide);
+ el_set(el_idown, elt_image, 0, 0, game_theme.inv_a_down);
+ el_set(el_iup, elt_image, 0, 0, game_theme.inv_a_up);
+// el_set(el_islide, elt_image, 0, 0, game_theme.slide);
+
+ el_set(el_spic, elt_image, game_theme.win_x, game_theme.win_y, NULL);
+ el_set(el_menu, elt_layout, 0, 0, NULL);
+ el_set(el_menu_button, elt_image, game_theme.menu_button_x, game_theme.menu_button_y, game_theme.menu_button);
+
+ el_draw(el_menu_button);
+
+ s = game_save_path(0);
+
+ if (s && !access(s, R_OK)) {
+ char cmd[256];
+ snprintf(cmd, sizeof(cmd) - 1, "load %s", s);
+ game_cmd(cmd);
+ return 0;
+ }
+ if (!curgame) {
+ menu_shown = 1;
+ cur_menu = menu_games;
+ game_menu_box(menu_shown, game_menu_gen());
+ gfx_flip();
+ } else
+ game_cmd("look");
+ return 0;
+}
+
+void free_last(void)
+{
+ if (last_pict)
+ free(last_pict);
+ if (last_title)
+ free(last_title);
+ if (last_music)
+ free(last_music);
+ last_pict = last_title = last_music = NULL;
+}
+
+void game_done(void)
+{
+ int i;
+ if (opt_autosave)
+ game_save();
+ chdir(game_cwd);
+ cfg_save();
+ menu_shown = 0;
+ game_menu_box(0, NULL);
+ cur_menu = menu_main;
+ 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;
+ }
+ free_last();
+ if (menu)
+ gfx_free_image(menu);
+ if (menubg)
+ gfx_free_image(menubg);
+ menu = menubg = NULL;
+ game_theme_free();
+ instead_done();
+ snd_done();
+ gfx_done();
+ curgame = NULL;
+}
+
+void el_size(int i, int *w, int *h)
+{
+ int type;
+ type = el(i)->type;
+ if (type == elt_layout)
+ txt_layout_size(el_layout(i), w, h);
+ else if (type == elt_box)
+ txt_box_size(el_box(i), w, h);
+ else if (type == elt_image) {
+ if (w)
+ *w = gfx_img_w(el_img(i));
+ if (h)
+ *h = gfx_img_h(el_img(i));
+ }
+}
+
+int el_clear(int n)
+{
+ int x, y, w, h;
+ struct el *o;
+ o = el(n);
+ if (!o || !o->drawn)
+ return 0;
+ x = o->x;
+ y = o->y;
+ el_size(n, &w, &h);
+ o->drawn = 0;
+ game_clear(x, y, w, h);
+ return 1;
+}
+
+void el_update(int n)
+{
+ int x, y, w, h;
+ struct el *o;
+ o = el(n);
+// if (!o->drawn)
+// return;
+ x = o->x;
+ y = o->y;
+ el_size(n, &w, &h);
+ gfx_update(x, y, w, h);
+ return;
+}
+
+void box_update_scrollbar(int n)
+{
+ struct el *elup;
+ struct el *eldown;
+// struct el *elslide;
+ layout_t l;
+
+ int x1, y1;
+ int x2, y2;
+
+ 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_size(l, NULL, &hh);
+ off = txt_box_off(el_box(n));
+ if (n == el_scene) {
+ elup = el(el_sup);
+ eldown = el(el_sdown);
+// elslide = el(el_sslide);
+ } else if (n == el_inv) {
+ elup = el(el_iup);
+ eldown = el(el_idown);
+// elslide = el(el_islide);
+ }
+ if (!elup || !eldown)
+ return;
+
+ if (el_clear(elup->id)) {
+ if (elup->x != x1 || elup->y != y1)
+ el_update(elup->id);
+ }
+
+ if (el_clear(eldown->id)) {
+ if (eldown->x != x2 || eldown->y != y2)
+ el_update(eldown->id);
+ }
+
+ elup->x = x1;
+ elup->y = y1;
+ eldown->x = x2;
+ eldown->y = y2;
+
+ el_clear(elup->id);
+ el_clear(eldown->id);
+
+ if (hh - off >= h)
+ el_draw(eldown->id);
+ if (off)
+ el_draw(elup->id);
+ el_update(elup->id);
+ el_update(eldown->id);
+}
+
+void el_draw(int n)
+{
+ int x, y;
+ struct el *o;
+ o = el(n);
+ x = o->x;
+ y = o->y;
+ if (!o->p.p)
+ return;
+ if (o->type == elt_image)
+ gfx_draw(o->p.img, x, y);
+ else if (o->type == elt_layout)
+ txt_layout_draw(o->p.lay, x, y);
+ else if (o->type == elt_box) {
+ txt_box_draw(o->p.box, x, y);
+ box_update_scrollbar(o->id);
+ }
+ o->drawn = 1;
+ return;
+}
+
+img_t game_pict_scale(img_t img, int ww, int hh)
+{
+ img_t img2 = img;
+ int w, h;
+ float scale1, scale2, scale;
+ w = gfx_img_w(img);
+ h = gfx_img_h(img);
+ if (w <= ww && h <= hh)
+ return img;
+ scale1 = (float)ww / (float)w;
+ scale2 = (float)hh / (float)h;
+ scale = (scale1 100)
+ pc = 100;
+ while (vol_to_pcn(v) != pc)
+ v += (d<0)?-1:1;
+ } else {
+ v = val;
+ pc = vol_to_pcn(v);
+ }
+ if (!pc)
+ v = 0;
+ snd_volume_mus(v);
+ if (opc && !pc) {
+ snd_stop_mus(0);
+ if (last_music)
+ free(last_music);
+ last_music = NULL;
+ }
+ if (!opc && pc) {
+ music_player();
+ }
+ cur_vol = snd_volume_mus(-1);
+ opt_vol = cur_vol;
+ return 0;
+}
+
+int change_hz(int hz)
+{
+ if (!hz)
+ return -1;
+ snd_done();
+ if (last_music)
+ free(last_music);
+ last_music = NULL;
+ snd_init(hz);
+ snd_volume_mus(cur_vol);
+ music_player();
+ opt_hz = snd_hz();
+ return 0;
+}
+#define MENU_GAMES_MAX 4
+static int games_menu_from = 0;
+int game_save(void)
+{
+ char *s = game_save_path(1);
+ char cmd[256];
+ char *p;
+ if (s) {
+ snprintf(cmd, sizeof(cmd) - 1, "save %s", s);
+ p = instead_cmd(cmd);
+ if (p)
+ free(p);
+ return 0;
+ }
+ return -1;
+}
+int game_menu_act(const char *a)
+{
+ if (!strcmp(a, "/autosave")) {
+ opt_autosave ^= 1;
+ } else if (!strcmp(a, "/hl")) {
+ opt_hl ^= 1;
+ } else if (!strcmp(a, "/fs")) {
+ char *og = curgame;
+ opt_fs ^= 1;
+ game_save();
+ game_done();
+ game_init(og);
+ } else if (!strcmp(a, "/games_prev")) {
+ games_menu_from -= MENU_GAMES_MAX;
+ if (games_menu_from < 0)
+ games_menu_from = 0;
+ } else if (!strcmp(a, "/games_next")) {
+ if (games_menu_from + MENU_GAMES_MAX < games_nr)
+ games_menu_from += MENU_GAMES_MAX;
+ } else if (!strcmp(a, "/select")) {
+ cur_menu = menu_games;
+ } else if (!strcmp(a, "/save")) {
+ if (!game_save()) {
+ cur_menu = menu_saved;
+ }
+ }
+ else if (!strcmp(a, "/new")) {
+ if (!curgame)
+ return 0;
+ free_last();
+ game_select(curgame);
+// instead_done();
+// instead_init();
+// instead_load(MAIN_FILE);
+ menu_shown = 0;
+ game_menu_box(0, NULL);
+ game_cmd("look");
+ game_save();
+// game_done();
+// game_init();
+// game_cmd("look");
+ }
+ else if (!strcmp(a,"/main")) {
+ cur_menu = menu_main;
+ }
+ else if (!strcmp(a,"/ask_quit")) {
+ cur_menu = menu_askquit;
+ }
+ else if (!strcmp(a,"/about")) {
+ cur_menu = menu_about;
+ }
+ else if (!strcmp(a,"/mtoggle")) {
+ if (!old_vol) {
+ old_vol = snd_volume_mus(-1);
+ change_vol(0, 0);
+ } else {
+ change_vol(0, old_vol);
+ old_vol = 0;
+ }
+ }
+ else if (!strcmp(a,"/resume")) {
+ menu_shown = 0;
+ game_menu_box(0, NULL);
+ }
+ else if (!strcmp(a, "/settings")) {
+ cur_menu = menu_settings;
+ }
+ else if (!strcmp(a, "/vol--")) {
+ change_vol(-10, 0);
+ }
+ else if (!strcmp(a, "/vol++")) {
+ change_vol(+10, 0);
+ }
+ else if (!strcmp(a, "/vol-")) {
+ change_vol(-1, 0);
+ }
+ else if (!strcmp(a, "/vol+")) {
+ change_vol(+1, 0);
+ }
+ else if (!strcmp(a, "/hz-")) {
+ int hz = snd_hz();
+ if (hz == 44100)
+ hz = 22050;
+ else if (hz == 22050)
+ hz = 11025;
+ else
+ hz = 0;
+ change_hz(hz);
+ }
+ else if (!strcmp(a, "/hz+")) {
+ int hz = snd_hz();
+ if (hz == 11025)
+ hz = 22050;
+ else if (hz == 22050)
+ hz = 44100;
+ else
+ hz = 0;
+ change_hz(hz);
+ }
+ else if (!strcmp(a,"/quit")) {
+ return -1;
+ } else if (cur_menu == menu_games) {
+ char *p;
+ p = strdup(a);
+ if (p) {
+ char *og = curgame;
+ game_done();
+ if (game_init(p)) {
+ fprintf(stderr, "Can't init game:%s:%s\n", p, strerror(errno));
+ // exit(1);
+ game_done();
+ game_init(og);
+ }
+ free(p);
+ }
+ }
+ return 0;
+}
+#ifdef RUSSIAN
+#define MAIN_MENU "Вернуться в игру\nВыбор игры\nНовая игра\nСохранить игру\nИнформация\nНастройки\nВыход"
+#define ABOUT_MENU "IN S.T.E.A.D SDL - "VERSION"\n\nИнтерпретатор простых\nтекстовых приключений.\n\nКосых П.А. '2009\n\nНазад"
+
+#define BACK_MENU "Назад"
+#define ON "Да"
+#define OFF "Нет"
+
+#define SETTINGS_MENU "Громкость\n<<< %d%% >>>\n\n\
+Качество звука\n<< %dГц >>\n\nПодсветка ссылок: %s\n\nПолный экран: %s\n\n\
+Автосохранение: %s\n\n\
+Назад"
+
+#define QUIT_MENU "На самом деле выйти?\n\nДа | Нет"
+#define SELECT_GAME_MENU "Выбор игры\n\n"
+#define SAVED_MENU "Игра сохранена!\n\nОк"
+#define NOGAMES_MENU "Не найдена ни одна игра. \nПожалуйста, скопируйте хотя бы одну игру в каталог:\n'%s'"
+#else
+#define MAIN_MENU "Resume\nSelect Game\nNew\nSave\nAbout\nSettings\nQuit"
+#define ABOUT_MENU "Written by Peter Kosyh '2009\n\nBack"
+#define BACK_MENU "Back"
+
+#define ON "on"
+#define OFF "off"
+#define SELECT_GAME_MENU "Select game to play\n\n"
+#define SETTINGS_MENU "Volume\n<<< %d%% >>>\n\n\
+Quality\n<< %dHz >>Refs highlighting: %s\n\nFull Screen: %s\n\n\
+Autosave: %s\n\n\
+Back"
+
+#define QUIT_MENU "Really quit?\n\nYes | No"
+
+#define SAVED_MENU "Current Game saved!\n\nOk"
+#define NOGAMES_MENU "No games found. \nPlease, write any game in the this directory:\n'%s'"
+#endif
+
+char menu_buff[4096];
+void games_menu(void)
+{
+ int i;
+ *menu_buff = 0;
+ sprintf(menu_buff, SELECT_GAME_MENU);
+ for (i = games_menu_from; i < games_nr && i - games_menu_from < MENU_GAMES_MAX; i ++) {
+ char tmp[PATH_MAX];
+ if (curgame && !strcmp(games[i].name, curgame))
+ snprintf(tmp, sizeof(tmp), "%s\n", games[i].name);
+ else
+ snprintf(tmp, sizeof(tmp), "%s\n", games[i].name, games[i].name);
+ strcat(menu_buff, tmp);
+ }
+ if (!games_nr)
+ sprintf(menu_buff, NOGAMES_MENU, GAMES_PATH);
+ strcat(menu_buff,"\n");
+ if (games_menu_from)
+ strcat(menu_buff,"<< ");
+ strcat(menu_buff, BACK_MENU);
+ if (games_menu_from + MENU_GAMES_MAX < games_nr)
+ strcat(menu_buff," >>");
+}
+
+char *game_menu_gen(void)
+{
+ if (cur_menu == menu_main) {
+ snprintf(menu_buff, sizeof(menu_buff), MAIN_MENU);
+ } else if (cur_menu == menu_about) {
+ snprintf(menu_buff, sizeof(menu_buff), ABOUT_MENU);
+ } else if (cur_menu == menu_settings) {
+ snprintf(menu_buff, sizeof(menu_buff),
+ SETTINGS_MENU, vol_to_pcn(snd_volume_mus(-1)), snd_hz(), opt_hl?ON:OFF, opt_fs?ON:OFF, opt_autosave?ON:OFF);
+ } else if (cur_menu == menu_askquit) {
+ snprintf(menu_buff, sizeof(menu_buff), QUIT_MENU);
+ } else if (cur_menu == menu_saved) {
+ snprintf(menu_buff, sizeof(menu_buff),
+ SAVED_MENU);
+ } else if (cur_menu == menu_games) {
+ games_menu();
+ }
+ return menu_buff;
+}
+
+void game_menu_box(int show, const char *txt)
+{
+// img_t menu;
+ int w, h, mw, mh;
+ int x, y;
+ int b = game_theme.border_w;
+ int pad = game_theme.pad;
+ layout_t lay;
+ el(el_menu)->drawn = 0;
+ if (el_layout(el_menu)) {
+ txt_layout_free(el_layout(el_menu));
+ el(el_menu)->p.p = NULL;
+ }
+
+ if (menubg) {
+ gfx_draw(menubg, mx, my);
+ gfx_free_image(menubg);
+ menubg = NULL;
+ }
+ el_clear(el_menu_button);
+
+ if (!show)
+ el_draw(el_menu_button);
+
+ el_update(el_menu_button);
+
+ if (!show) {
+ gfx_flip();
+ return;
+ }
+ lay = txt_layout(game_theme.menu_font, ALIGN_CENTER, game_theme.win_w, 0);
+ 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_set(lay, (char*)txt);
+ txt_layout_real_size(lay, &w, &h);
+ if (menu) {
+ gfx_free_image(menu);
+ menu = NULL;
+ }
+ menu = gfx_new(w + (b + pad)*2, h + (b + pad)*2);
+ 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;
+ mx = x - b - pad;
+ my = y - b - pad;
+ mw = w + (b + pad) * 2;
+ mh = h + (b + pad) * 2;
+ menubg = gfx_grab_screen(mx, my, mw, mh);
+ gfx_draw(menu, mx, my);
+ el_set(el_menu, elt_layout, game_theme.win_x, y, lay);
+ el_draw(el_menu);
+ gfx_flip();
+}
+
+int check_new_place(char *title)
+{
+ int rc = 0;
+ if (!title && !last_title)
+ return 0;
+
+ if (!title && last_title) {
+ rc = 1;
+ } else if (!last_title || strcmp(title, last_title)) {
+ rc = 1;
+ }
+ if (last_title) {
+ free(last_title);
+ }
+ last_title = title;
+ return rc;
+}
+
+int check_new_pict(char *pict)
+{
+ int rc = 0;
+ if (!pict && !last_pict)
+ return 0;
+
+ if (!pict && last_pict) {
+ rc = 1;
+ } else if (!last_pict || strcmp(pict, last_pict)) {
+ rc = 1;
+ }
+ if (last_pict) {
+ free(last_pict);
+ }
+ last_pict = pict;
+ return rc;
+}
+
+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);
+}
+
+void music_player(void)
+{
+ char *mus;
+ if (!snd_volume_mus(-1))
+ return;
+ mus = instead_eval("return get_music()");
+ if (mus) {
+ if (!last_music && mus) {
+ last_music = mus;
+ snd_stop_mus(500);
+ snd_play_mus(mus, 0);
+ } else if (strcmp(last_music, mus)) {
+ free(last_music);
+ last_music = mus;
+ snd_stop_mus(500);
+ snd_play_mus(mus, 0);
+ } else
+ free(mus);
+ }
+}
+
+int game_cmd(char *cmd)
+{
+ int new_pict = 0, new_place = 0;
+ int title_h = 0, ways_h = 0, pict_h = 0;
+ char buf[256];
+ char *cmdstr;
+ char *invstr;
+ char *waystr;
+ char *title;
+ char *pict;
+ img_t oldscreen;
+
+ cmdstr = instead_cmd(cmd);
+ if (!cmdstr) {
+ return -1;
+ }
+ music_player();
+ title = instead_eval("return get_title();");
+ if (title) {
+ snprintf(buf, sizeof(buf), "%s", title);
+ txt_layout_set(el_layout(el_title), buf);
+ } else
+ txt_layout_set(el_layout(el_title), NULL);
+
+ new_place = check_new_place(title);
+
+ txt_layout_size(el_layout(el_title), NULL, &title_h);
+// title_h += 12; // todo
+ pict = instead_eval("return get_picture();");
+
+ new_pict = check_new_pict(pict);
+
+ if (pict) {
+ int w, h, x;
+ img_t img;
+
+ if (new_pict) {
+ img = gfx_load_image(pict, 1);
+ if (el_img(el_spic))
+ gfx_free_image(el_img(el_spic));
+ el(el_spic)->p.p = NULL;
+ img = game_pict_scale(img, game_theme.win_w, game_theme.max_scene_h);
+ } else
+ img = el_img(el_spic);
+
+ if (img) {
+ w = gfx_img_w(img);
+ h = gfx_img_h(img);
+ x = (game_theme.win_w - w)/2 + game_theme.win_x;
+ el_set(el_spic, elt_image, x, game_theme.win_y + title_h, img);
+ pict_h = h;
+ }
+ } else if (el_img(el_spic)) {
+ el_clear(el_spic);
+ gfx_free_image(el_img(el_spic));
+ el(el_spic)->p.p = NULL;
+ }
+
+ waystr = instead_cmd("way");
+ invstr = instead_cmd("inv");
+
+ if (waystr) {
+ waystr[strcspn(waystr,"\n")] = 0;
+ }
+
+ txt_layout_set(el_layout(el_ways), waystr);
+ if (waystr)
+ free(waystr);
+ txt_layout_size(el_layout(el_ways), NULL, &ways_h);
+ el(el_ways)->y = el(el_title)->y + title_h + pict_h;
+ txt_layout_set(txt_box_layout(el_box(el_scene)), cmdstr);
+ txt_box_set(el_box(el_scene), txt_box_layout(el_box(el_scene)));
+ free(cmdstr);
+
+ el(el_scene)->y = el(el_ways)->y + ways_h;
+ /* draw title and ways */
+ if (new_pict || new_place) {
+ img_t offscreen = gfx_new(game_theme.w, game_theme.h);
+ oldscreen = gfx_screen(offscreen);
+ gfx_draw(oldscreen, 0, 0);
+ }
+ if (new_pict || new_place) {
+ game_clear(game_theme.win_x, game_theme.win_y, game_theme.win_w, game_theme.win_h);
+// el_draw(el_title);
+ } else {
+ game_clear(game_theme.win_x, game_theme.win_y + pict_h + title_h,
+ game_theme.win_w, game_theme.win_h - pict_h - title_h);
+ }
+ el_clear(el_title);
+ el_draw(el_title);
+
+ el_draw(el_ways);
+ if (new_pict || new_place)
+ el_draw(el_spic);
+
+ txt_box_resize(el_box(el_scene), game_theme.win_w, game_theme.win_h - title_h - ways_h - pict_h);
+ el_draw(el_scene);
+
+ txt_layout_set(txt_box_layout(el_box(el_inv)), invstr);
+ txt_box_set(el_box(el_inv), txt_box_layout(el_box(el_inv)));
+ if (invstr)
+ free(invstr);
+
+ el_clear(el_inv);
+ el_draw(el_inv);
+// scene_scrollbar();
+
+ if (new_pict || new_place) {
+ img_t offscreen;
+ offscreen = gfx_screen(oldscreen);
+ gfx_change_screen(offscreen);
+ gfx_free_image(offscreen);
+ return 0;
+ }
+ gfx_flip();
+ return 0;
+}
+
+xref_t inv_xref = NULL;
+
+int disable_inv(void)
+{
+ if (inv_xref) {
+ xref_set_active(inv_xref, 0);
+ xref_update(inv_xref, el(el_inv)->x, el(el_inv)->y, game_clear);
+// txt_box_update_links(el_box(el_inv), el(el_inv)->x, el(el_inv)->y, game_clear);
+ inv_xref = NULL;
+ return 1;
+ }
+ return 0;
+}
+
+void enable_inv(xref_t xref)
+{
+ inv_xref = xref;
+ xref_set_active(xref, 1);
+ //txt_box_update_links(el_box(el_inv), el(el_inv)->x, el(el_inv)->y, game_clear);
+ xref_update(inv_xref, el(el_inv)->x, el(el_inv)->y, game_clear);
+}
+
+
+struct el *look_obj(int x, int y)
+{
+ int i;
+ for (i = 0; i < el_max; i++) {
+ int w, h;
+
+ if (el(i)->drawn && el(i)->id == el_menu) {
+ return el(i);
+ }
+ if (x < el(i)->x || y < el(i)->y || !el(i)->drawn)
+ continue;
+ el_size(i, &w, &h);
+ if (x >= el(i)->x && y >= el(i)->y && x <= el(i)->x + w && y <= el(i)->y + h)
+ return el(i);
+ }
+ return NULL;
+}
+
+xref_t look_xref(int x, int y, struct el **elem)
+{
+ struct el *o;
+ int type;
+ xref_t xref = NULL;
+ o = look_obj(x, y);
+ if (elem)
+ *elem = o;
+ if (!o)
+ return NULL;
+ type = o->type;
+ if (type == elt_layout)
+ xref = txt_layout_xref(o->p.lay, x - o->x, y - o->y);
+ else if (type == elt_box)
+ xref = txt_box_xref(o->p.box, x - o->x, y - o->y);
+ return xref;
+}
+
+static xref_t old_xref = NULL;
+static struct el *old_el = NULL;
+
+void menu_update(struct el *elem)
+{
+ gfx_draw(menubg, mx, my);
+ gfx_draw(menu, mx, my);
+ txt_layout_draw(elem->p.lay, elem->x, elem->y);
+ gfx_update(mx, my, gfx_img_w(menu), gfx_img_h(menu));
+// gfx_fill(x, y, w, h, game_theme.menu_bg);
+}
+
+
+int game_highlight(int x, int y, int on)
+{
+ struct el *elem = NULL;
+ static struct el *oel = NULL;
+ static xref_t hxref = NULL;
+ xref_t xref = NULL;
+ int up = 0;
+ if (!opt_hl)
+ return 0;
+ if (on) {
+ xref = look_xref(x, y, &elem);
+ if (xref) {
+ game_cursor(-1);
+ xref_set_active(xref, 1);
+ xref_update(xref, elem->x, elem->y, game_clear);
+ }
+ }
+
+ if (hxref != xref && oel) {
+ if (hxref != inv_xref) {
+ xref_set_active(hxref, 0);
+ game_cursor(-1);
+ xref_update(hxref, oel->x, oel->y, game_clear);
+ up = 1;
+ }
+ hxref = NULL;
+ }
+ hxref = xref;
+// if (!up || !elem)
+// return 0;
+// xref_update(hxref, elem->x, elem->y, game_clear);
+// game_cursor(2);
+// game_cursor(0);
+
+// if (elem->id == el_menu) {
+// menu_update(elem);
+// }
+// else if (elem->type == elt_layout)
+// txt_layout_update_links(elem->p.lay, elem->x, elem->y, game_clear);
+// else if (elem->type == elt_box)
+// txt_box_update_links(elem->p.box, elem->x, elem->y, game_clear);
+// el_update(elem->id);
+ oel = elem;
+ return 0;
+}
+
+void menu_toggle(void)
+{
+ game_cursor(0);
+ game_highlight(-1, -1, 0);
+ disable_inv();
+ menu_shown ^= 1;
+ if (!menu_shown)
+ cur_menu = menu_main;
+ game_menu_box(menu_shown, game_menu_gen());
+}
+
+int game_click(int x, int y, int action)
+{
+ struct el *elem = NULL;
+ char buf[256];
+ xref_t xref;
+
+ if (old_xref) {
+ xref = old_xref;
+ elem = old_el;
+ } else {
+ xref = look_xref(x, y, &elem);
+ }
+
+ if (!xref) {
+ if (action && elem) {
+ if (elem->id == el_menu_button) {
+ menu_toggle();
+ } else if (elem->id == el_sdown) {
+ txt_box_next(el_box(el_scene));
+ el_clear(el_scene);
+ el_draw(el_scene);
+ el_update(el_scene);
+ }
+ else if (elem->id == el_sup) {
+ txt_box_prev(el_box(el_scene));
+ el_clear(el_scene);
+ el_draw(el_scene);
+ el_update(el_scene);
+ }
+ else if (elem->id == el_idown) {
+ txt_box_next(el_box(el_inv));
+ el_clear(el_inv);
+ el_draw(el_inv);
+ el_update(el_inv);
+ }
+ else if (elem->id == el_iup) {
+ txt_box_prev(el_box(el_inv));
+ el_clear(el_inv);
+ el_draw(el_inv);
+ el_update(el_inv);
+ }
+ }
+ if (disable_inv()) {
+ el_update(el_inv);
+// gfx_flip();
+ }
+ return 0;
+ }
+
+ if (!action) {
+ xref_set_active(xref, 1);
+ xref_update(xref, elem->x, elem->y, game_clear);
+/*
+ if (elem->id == el_menu) {
+ menu_update(elem);
+ } else if (elem->type == elt_layout)
+ txt_layout_update_links(elem->p.lay, elem->x, elem->y, game_clear);
+ else if (elem->type == elt_box)
+ txt_box_update_links(elem->p.box, elem->x, elem->y, game_clear);
+ el_update(elem->id); */
+ old_xref = xref;
+ old_el = elem;
+ return 0;
+ }
+
+ old_el = NULL;
+ old_xref = NULL;
+
+ if (elem->id == el_menu) {
+// xref_set_active(xref, 0);
+// txt_layout_update_links(elem->p.lay, elem->x, elem->y, game_clear);
+ if (game_menu_act(xref_get_text(xref))) {
+ return -1;
+ }
+ game_menu_box(menu_shown, game_menu_gen());
+// gfx_flip();
+ return 1;
+ }
+
+ if (elem->id == el_ways ||
+ elem->id == el_title) {
+ strcpy(buf, xref_get_text(xref));
+ disable_inv();
+ game_cmd(buf);
+ return 1;
+ }
+
+ if (elem->id == el_scene) {
+ if (inv_xref) {
+ snprintf(buf,sizeof(buf), "use %s,%s", xref_get_text(inv_xref), xref_get_text(xref));
+ disable_inv();
+ } else
+ strcpy(buf, xref_get_text(xref));
+ game_cmd(buf);
+ return 1;
+ }
+
+ if (elem->id == el_inv) {
+ if (!inv_xref) {
+ enable_inv(xref);
+ el_update(el_inv);
+ return 0;
+ }
+ if (xref == inv_xref)
+ snprintf(buf,sizeof(buf), "use %s", xref_get_text(xref));
+ else
+ snprintf(buf,sizeof(buf), "use %s,%s", xref_get_text(inv_xref), xref_get_text(xref));
+ disable_inv();
+ game_cmd(buf);
+ return 1;
+ }
+ return 0;
+}
+
+void game_cursor(int on)
+{
+ static img_t grab = NULL;
+ static int xc, yc, w, h;
+ if (grab) {
+ gfx_draw(grab, xc, yc);
+ gfx_free_image(grab);
+ grab = NULL;
+ }
+ if (!on) {
+ gfx_update(xc, yc, gfx_img_w(game_theme.use), gfx_img_h(game_theme.use));
+ return;
+ }
+ if (on == -1)
+ return;
+ if (inv_xref) {
+ int ox = xc;
+ int oy = yc;
+ gfx_cursor(&xc, &yc, &w, &h);
+ xc += w/2;
+ yc += h/2;
+ grab = gfx_grab_screen(xc, yc, gfx_img_w(game_theme.use), gfx_img_h(game_theme.use));
+ gfx_draw(game_theme.use, xc, yc);
+ gfx_update(xc, yc, gfx_img_w(game_theme.use), gfx_img_h(game_theme.use));
+ gfx_update(ox, oy, gfx_img_w(game_theme.use), gfx_img_h(game_theme.use));
+ }
+}
+
+int game_loop(void)
+{
+ static int x = 0, y = 0;
+ struct inp_event ev;
+ while (1) {
+ if (input(&ev, 1) == -1) /* close */
+ break;
+ if (ev.type == KEY_DOWN && ev.sym && !strcmp(ev.sym,"escape")) {
+ menu_toggle();
+ } else if (ev.type == MOUSE_DOWN) {
+ game_cursor(0);
+ game_highlight(-1, -1, 0);
+ game_click(ev.x, ev.y, 0);
+ x = ev.x;
+ y = ev.y;
+ } else if (ev.type == MOUSE_UP) {
+ game_cursor(0);
+ game_highlight(-1, -1, 0);
+ if (game_click(x, y, 1) == -1)
+ break;
+ } else if (ev.type == MOUSE_WHEEL_UP && !menu_shown) {
+ int xm, ym;
+ struct el *o;
+ gfx_cursor(&xm, &ym, NULL, NULL);
+ o = look_obj(xm, ym);
+ if (o && (o->id == el_scene || o->id == el_inv)) {
+ game_cursor(0);
+ game_highlight(-1, -1, 0);
+ txt_box_prev_line(el_box(o->id));
+ el_clear(o->id);
+ el_draw(o->id);
+ el_update(o->id);
+ }
+ } else if (ev.type == MOUSE_WHEEL_DOWN && !menu_shown) {
+ int xm, ym;
+ struct el *o;
+ gfx_cursor(&xm, &ym, NULL, NULL);
+ o = look_obj(xm, ym);
+ if (o && (o->id == el_scene || o->id == el_inv)) {
+ game_cursor(0);
+ game_highlight(-1, -1, 0);
+ txt_box_next_line(el_box(o->id));
+ el_clear(o->id);
+ el_draw(o->id);
+ el_update(o->id);
+ }
+ } else if (ev.type == MOUSE_MOTION) {
+ // game_highlight(ev.x, ev.y, 1);
+ }
+ game_highlight(ev.x, ev.y, 1);
+ game_cursor(1);
+ }
+ return 0;
+}
+
diff --git a/src/sdl-instead/game.h b/src/sdl-instead/game.h
new file mode 100644
index 0000000..020e016
--- /dev/null
+++ b/src/sdl-instead/game.h
@@ -0,0 +1,9 @@
+#ifndef __GAME_H__
+#define __GAME_H__
+extern int game_load_theme(const char *path);
+extern int game_init(const char *game);
+extern void game_done(void);
+extern int game_loop(void);
+extern int games_lookup(void);
+#endif
+
diff --git a/src/sdl-instead/graphics.c b/src/sdl-instead/graphics.c
new file mode 100644
index 0000000..7fb0e85
--- /dev/null
+++ b/src/sdl-instead/graphics.c
@@ -0,0 +1,2282 @@
+#include
+#include
+#include
+#include
+#include /* for usleep */
+#include "graphics.h"
+#include "math.h"
+
+static SDL_Surface *screen;
+
+static struct {
+ const char *name;
+ unsigned long val;
+} cnames[] = {
+ {"aliceblue", 0xf0f8ff},
+ {"antiquewhite", 0xfaebd7},
+ {"aqua", 0x00ffff},
+ {"aquamarine", 0x7fffd4},
+ {"azure", 0xf0ffff},
+ {"beige", 0xf5f5dc},
+ {"bisque", 0xffe4c4},
+ {"black", 0x000000},
+ {"blanchedalmond", 0xffebcd},
+ {"blue", 0x0000ff},
+ {"blueviolet", 0x8a2be2},
+ {"brown", 0xa52a2a},
+ {"burlywood", 0xdeb887},
+ {"cadetblue", 0x5f9ea0},
+ {"chartreuse", 0x7fff00},
+ {"chocolate", 0xd2691e},
+ {"coral", 0xff7f50},
+ {"cornflowerblue", 0x6495ed},
+ {"cornsilk", 0xfff8dc},
+ {"crimson", 0xdc143c},
+ {"cyan", 0x00ffff},
+ {"darkblue", 0x00008b},
+ {"darkcyan", 0x008b8b},
+ {"darkgoldenrod", 0xb8860b},
+ {"darkgray", 0xa9a9a9},
+ {"darkgreen", 0x006400},
+ {"darkkhaki", 0xbdb76b},
+ {"darkmagenta", 0x8b008b},
+ {"darkolivegreen", 0x556b2f},
+ {"darkorange", 0xff8c00},
+ {"darkorchid", 0x9932cc},
+ {"darkred", 0x8b0000},
+ {"darksalmon", 0xe9967a},
+ {"darkseagreen", 0x8fbc8f},
+ {"darkslateblue", 0x483d8b},
+ {"darkslategray", 0x2f4f4f},
+ {"darkturquoise", 0x00ced1},
+ {"darkviolet", 0x9400d3},
+ {"deeppink", 0xff1493},
+ {"deepskyblue", 0x00bfff},
+ {"dimgray", 0x696969},
+ {"dodgerblue", 0x1e90ff},
+ {"feldspar", 0xd19275},
+ {"firebrick", 0xb22222},
+ {"floralwhite", 0xfffaf0},
+ {"forestgreen", 0x228b22},
+ {"fuchsia", 0xff00ff},
+ {"gainsboro", 0xdcdcdc},
+ {"ghostwhite", 0xf8f8ff},
+ {"gold", 0xffd700},
+ {"goldenrod", 0xdaa520},
+ {"gray", 0x808080},
+ {"green", 0x008000},
+ {"greenyellow", 0xadff2f},
+ {"honeydew", 0xf0fff0},
+ {"hotpink", 0xff69b4},
+ {"indianred ", 0xcd5c5c},
+ {"indigo ", 0x4b0082},
+ {"ivory", 0xfffff0},
+ {"khaki", 0xf0e68c},
+ {"lavender", 0xe6e6fa},
+ {"lavenderblush", 0xfff0f5},
+ {"lawngreen", 0x7cfc00},
+ {"lemonchiffon", 0xfffacd},
+ {"lightblue", 0xadd8e6},
+ {"lightcoral", 0xf08080},
+ {"lightcyan", 0xe0ffff},
+ {"lightgoldenrodyellow", 0xfafad2},
+ {"lightgrey", 0xd3d3d3},
+ {"lightgreen", 0x90ee90},
+ {"lightpink", 0xffb6c1},
+ {"lightsalmon", 0xffa07a},
+ {"lightseagreen", 0x20b2aa},
+ {"lightskyblue", 0x87cefa},
+ {"lightslateblue", 0x8470ff},
+ {"lightslategray", 0x778899},
+ {"lightsteelblue", 0xb0c4de},
+ {"lightyellow", 0xffffe0},
+ {"lime", 0x00ff00},
+ {"limegreen", 0x32cd32},
+ {"linen", 0xfaf0e6},
+ {"magenta", 0xff00ff},
+ {"maroon", 0x800000},
+ {"mediumaquamarine", 0x66cdaa},
+ {"mediumblue", 0x0000cd},
+ {"mediumorchid", 0xba55d3},
+ {"mediumpurple", 0x9370d8},
+ {"mediumseagreen", 0x3cb371},
+ {"mediumslateblue", 0x7b68ee},
+ {"mediumspringgreen", 0x00fa9a},
+ {"mediumturquoise", 0x48d1cc},
+ {"mediumvioletred", 0xc71585},
+ {"midnightblue", 0x191970},
+ {"mintcream", 0xf5fffa},
+ {"mistyrose", 0xffe4e1},
+ {"moccasin", 0xffe4b5},
+ {"navajowhite", 0xffdead},
+ {"navy", 0x000080},
+ {"oldlace", 0xfdf5e6},
+ {"olive", 0x808000},
+ {"olivedrab", 0x6b8e23},
+ {"orange", 0xffa500},
+ {"orangered", 0xff4500},
+ {"orchid", 0xda70d6},
+ {"palegoldenrod", 0xeee8aa},
+ {"palegreen", 0x98fb98},
+ {"paleturquoise", 0xafeeee},
+ {"palevioletred", 0xd87093},
+ {"papayawhip", 0xffefd5},
+ {"peachpuff", 0xffdab9},
+ {"peru", 0xcd853f},
+ {"pink", 0xffc0cb},
+ {"plum", 0xdda0dd},
+ {"powderblue", 0xb0e0e6},
+ {"purple", 0x800080},
+ {"red", 0xff0000},
+ {"rosybrown", 0xbc8f8f},
+ {"royalblue", 0x4169e1},
+ {"saddlebrown", 0x8b4513},
+ {"salmon", 0xfa8072},
+ {"sandybrown", 0xf4a460},
+ {"seagreen", 0x2e8b57},
+ {"seashell", 0xfff5ee},
+ {"sienna", 0xa0522d},
+ {"silver", 0xc0c0c0},
+ {"skyblue", 0x87ceeb},
+ {"slateblue", 0x6a5acd},
+ {"slategray", 0x708090},
+ {"snow", 0xfffafa},
+ {"springgreen", 0x00ff7f},
+ {"steelblue", 0x4682b4},
+ {"tan", 0xd2b48c},
+ {"teal", 0x008080},
+ {"thistle", 0xd8bfd8},
+ {"tomato", 0xff6347},
+ {"turquoise", 0x40e0d0},
+ {"violet", 0xee82ee},
+ {"violetred", 0xd02090},
+ {"wheat", 0xf5deb3},
+ {"white", 0xffffff},
+ {"whitesmoke", 0xf5f5f5},
+ {"yellow", 0xffff00},
+ {"yellowgreen", 0x9acd32},
+ {NULL, 0x0},
+};
+
+int gfx_parse_color (
+ const char *spec,
+ color_t *def)
+{
+ int n, i;
+ int r, g, b;
+ char c;
+
+ if (!spec)
+ return -1;
+
+ n = strlen (spec);
+
+ if (*spec == '#') {
+ /*
+ * RGB
+ */
+ spec++;
+ n--;
+ if (n != 3 && n != 6 && n != 9 && n != 12)
+ return -1;
+ n /= 3;
+ g = b = 0;
+ do {
+ r = g;
+ g = b;
+ b = 0;
+ for (i = n; --i >= 0; ) {
+ c = *spec++;
+ b <<= 4;
+ if (c >= '0' && c <= '9')
+ b |= c - '0';
+ else if (c >= 'A' && c <= 'F')
+ b |= c - ('A' - 10);
+ else if (c >= 'a' && c <= 'f')
+ b |= c - ('a' - 10);
+ else return (0);
+ }
+ } while (*spec != '\0');
+ n <<= 2;
+// n = 16 - n;
+ if (def) {
+ def->r = r;
+ def->g = g;
+ def->b = b;
+ }
+ return 0;
+ }
+
+ for (i=0; cnames[i].name; i++) {
+ if (!strcmp(cnames[i].name, spec)) {
+ if (def) {
+ def->r = (cnames[i].val & 0xff0000) >> 16;
+ def->g = (cnames[i].val & 0x00ff00) >> 8;
+ def->b = (cnames[i].val & 0x0000ff);
+ }
+ return 0;
+ }
+ }
+ return -1;
+}
+
+void gfx_free_image(img_t p)
+{
+ if (!p)
+ return;
+ SDL_FreeSurface((SDL_Surface *)p);
+}
+
+int gfx_img_w(img_t pixmap)
+{
+ if (!pixmap)
+ return 0;
+ return ((SDL_Surface *)pixmap)->w;
+}
+
+int gfx_img_h(img_t pixmap)
+{
+ if (!pixmap)
+ return 0;
+ return ((SDL_Surface *)pixmap)->h;
+}
+
+void gfx_noclip(void)
+{
+ SDL_SetClipRect(screen, NULL);
+}
+
+void gfx_clip(int x, int y, int w, int h)
+{
+ SDL_Rect src;
+ src.x = x;
+ src.y = y;
+ src.w = w;
+ src.h = h;
+ SDL_SetClipRect(screen, &src);
+}
+
+img_t gfx_new(int w, int h)
+{
+ SDL_Surface *dst;
+ dst = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h,
+ screen->format->BitsPerPixel,
+ screen->format->Rmask,
+ screen->format->Gmask,
+ screen->format->Bmask,
+ screen->format->Amask);
+ return dst;
+}
+
+void gfx_img_fill(img_t img, int x, int y, int w, int h, color_t col)
+{
+ SDL_Rect dest;
+ dest.x = x;
+ dest.y = y;
+ dest.w = w;
+ dest.h = h;
+ SDL_FillRect(img, &dest, SDL_MapRGB(((SDL_Surface*)img)->format, col.r, col.g, col.b));
+}
+void gfx_fill(int x, int y, int w, int h, color_t col)
+{
+ gfx_img_fill(screen, x, y, w, h, col);
+}
+
+img_t gfx_screen(img_t nscreen)
+{
+ img_t img;
+ if (nscreen) {
+ img = screen;
+ screen = nscreen;
+ return img;
+ }
+ return screen;
+}
+
+img_t gfx_grab_screen(int x, int y, int w, int h)
+{
+ SDL_Rect dst, src;
+ SDL_Surface *img = SDL_CreateRGBSurface(SDL_HWSURFACE, w, h, 16, 0xF800, 0x7E0, 0x1F, 0);
+ if (!img)
+ return NULL;
+ src.x = x;
+ src.y = y;
+ src.w = w;
+ src.h = h;
+ dst.x = 0;
+ dst.y = 0;
+ dst.w = w;
+ dst.h = h;
+ SDL_BlitSurface(screen, &src, img, &dst);
+ return img;
+}
+
+img_t gfx_alpha_img(img_t src, int alpha)
+{
+ Uint32 *ptr;
+ Uint32 col;
+ int size;
+
+ SDL_Surface *img = SDL_DisplayFormatAlpha((SDL_Surface*)src);
+ if (!img)
+ return NULL;
+ ptr = (Uint32*)img->pixels;
+ size = img->w * img->h;
+ while (size --) {
+ Uint8 r, g, b, a;
+ col = *ptr;
+ SDL_GetRGBA(col, img->format, &r, &g, &b, &a);
+ col = SDL_MapRGBA(img->format, r, g, b, a * alpha / 255);
+ *ptr = col;
+ ptr ++;
+ }
+ return img;
+}
+
+void gfx_set_alpha(img_t src, int alpha)
+{
+// SDL_Surface *img = SDL_DisplayFormat((SDL_Surface*)src);
+// if (!img)
+// return NULL;
+ SDL_SetAlpha((SDL_Surface *)src, SDL_SRCALPHA | SDL_RLEACCEL, alpha);
+// return img;
+}
+
+img_t gfx_combine(img_t src, img_t dst)
+{
+ img_t new;
+ new = SDL_DisplayFormatAlpha(dst);
+ if (!new)
+ return NULL;
+ SDL_BlitSurface((SDL_Surface *)src, NULL, (SDL_Surface *)new, NULL);
+ return new;
+}
+
+img_t gfx_load_image(char *filename, int transparent)
+{
+
+ SDL_Surface *img, *img2;
+ img = IMG_Load(filename);
+ if (!img) {
+ fprintf(stderr, "File not found: '%s'\n", filename);
+ return NULL;
+ }
+ if (transparent && transparent != 2) {
+ SDL_SetColorKey(img, SDL_RLEACCEL, img->format->colorkey);
+ return img;
+ }
+ // Create hardware surface
+ img2 = SDL_CreateRGBSurface(SDL_HWSURFACE | (transparent)?SDL_SRCCOLORKEY:0,
+ img->w, img->h, 16, 0xF800, 0x7E0, 0x1F, 0);
+ if (!img2) {
+ SDL_FreeSurface(img);
+ fprintf(stderr, "Error creating surface!\n");
+ return NULL;
+ }
+
+ if (transparent)
+ SDL_SetColorKey(img2, SDL_SRCCOLORKEY | SDL_RLEACCEL, 0xF81F);
+
+ SDL_SetAlpha(img2, 0, 0);
+ SDL_BlitSurface(img, NULL, img2, NULL);
+ SDL_FreeSurface(img);
+ return img2;
+}
+
+void gfx_draw_bg(img_t p, int x, int y, int width, int height)
+{
+ SDL_Surface *pixbuf = (SDL_Surface *)p;
+ SDL_Rect dest, src;
+ src.x = x;
+ src.y = y;
+ src.w = width;
+ src.h = height;
+ dest.x = x;
+ dest.y = y;
+ dest.w = width;
+ dest.h = height;
+ SDL_BlitSurface(pixbuf, &src, screen, &dest);
+}
+
+void gfx_draw_from(img_t p, int x, int y, int xx, int yy, int width, int height)
+{
+ SDL_Surface *pixbuf = (SDL_Surface *)p;
+ SDL_Rect dest, src;
+ src.x = x;
+ src.y = y;
+ src.w = width;
+ src.h = height;
+ dest.x = xx;
+ dest.y = yy;
+ dest.w = width;
+ dest.h = height;
+ SDL_BlitSurface(pixbuf, &src, screen, &dest);
+}
+void gfx_draw(img_t p, int x, int y)
+{
+ SDL_Surface *pixbuf = (SDL_Surface *)p;
+ SDL_Rect dest;
+ dest.x = x;
+ dest.y = y;
+ dest.w = pixbuf->w;
+ dest.h = pixbuf->h;
+ SDL_BlitSurface(pixbuf, NULL, screen, &dest);
+}
+
+void gfx_draw_wh(img_t p, int x, int y, int w, int h)
+{
+ SDL_Surface *pixbuf = (SDL_Surface *)p;
+ SDL_Rect dest, src;
+ src.x = 0;
+ src.y = 0;
+ src.w = w;
+ src.h = h;
+ dest.x = x;
+ dest.y = y;
+ dest.w = w;
+ dest.h = h;
+ SDL_BlitSurface(pixbuf, &src, screen, &dest);
+}
+static SDL_Color bgcol = { .r = 0, .g = 0, .b = 0 };
+
+void gfx_bg(color_t col)
+{
+ bgcol.r = col.r;
+ bgcol.g = col.g;
+ bgcol.b = col.b;
+}
+
+void gfx_clear(int x, int y, int w, int h)
+{
+ SDL_Rect dest;
+ dest.x = x;
+ dest.y = y;
+ dest.w = w;
+ dest.h = h;
+ SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format, bgcol.r, bgcol.g, bgcol.b));
+}
+
+int gfx_width;
+int gfx_height;
+int gfx_init(int width, int height, int fs)
+{
+ gfx_width = width;
+ gfx_height = height;
+
+ if (TTF_Init()) {
+ fprintf(stderr, "Can't init TTF subsystem.\n");
+ return -1;
+ }
+
+ // Initialize SDL
+ if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_AUDIO) < 0) {
+ fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
+ return -1;
+ }
+ screen = SDL_SetVideoMode(gfx_width, gfx_height, 32, SDL_DOUBLEBUF | SDL_HWSURFACE | ((fs)?SDL_FULLSCREEN:0));
+ SDL_WM_SetCaption("IN S.T.E.A.D SDL - "VERSION, NULL);
+// icon = IMG_Load( GAMEDATADIR"icon/lines.png" );
+// if (icon) {
+// SDL_WM_SetIcon( icon, NULL );
+// }
+ if (screen == NULL) {
+ fprintf(stderr, "Unable to set 800x480 video: %s\n", SDL_GetError());
+ return -1;
+ }
+ gfx_clear(0, 0, gfx_width, gfx_height);
+ return 0;
+}
+void gfx_flip(void)
+{
+ SDL_Flip(screen);
+}
+
+void gfx_update(int x, int y, int w, int h) {
+// SDL_Flip(screen);
+ if (x < 0) {
+ x = 0;
+ w += x;
+ }
+ if (y < 0) {
+ y = 0;
+ h += y;
+ }
+ if (w < 0 || h < 0)
+ return;
+ if (x >= gfx_width || y >= gfx_height)
+ return;
+ if (x + w > gfx_width) {
+ w = gfx_width - x;
+ }
+ if (y + h > gfx_height) {
+ h = gfx_height - y;
+ }
+ SDL_UpdateRect(screen, x, y, w, h);
+}
+
+void gfx_done(void)
+{
+ TTF_Quit();
+ SDL_Quit();
+}
+
+/* code from sge */
+#ifndef PI
+ #define PI 3.1414926535
+#endif
+
+void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
+{
+ Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
+
+ /* Gack - slow, but endian correct */
+ *(pix+surface->format->Rshift/8) = color>>surface->format->Rshift;
+ *(pix+surface->format->Gshift/8) = color>>surface->format->Gshift;
+ *(pix+surface->format->Bshift/8) = color>>surface->format->Bshift;
+ *(pix+surface->format->Ashift/8) = color>>surface->format->Ashift;
+}
+void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
+{
+ *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
+}
+
+void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
+{
+ switch ( dest->format->BytesPerPixel ) {
+ case 1:
+ *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
+ break;
+ case 2:
+ *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
+ break;
+ case 3:
+ _PutPixel24(dest,x,y,color);
+ break;
+ case 4:
+ *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
+ break;
+ }
+}
+
+Uint32 sge_GetPixel(SDL_Surface *surface, Sint16 x, Sint16 y)
+{
+ if(x<0 || x>=surface->w || y<0 || y>=surface->h)
+ return 0;
+
+ switch (surface->format->BytesPerPixel) {
+ case 1: { /* Assuming 8-bpp */
+ return *((Uint8 *)surface->pixels + y*surface->pitch + x);
+ }
+ break;
+
+ case 2: { /* Probably 15-bpp or 16-bpp */
+ return *((Uint16 *)surface->pixels + y*surface->pitch/2 + x);
+ }
+ break;
+
+ case 3: { /* Slow 24-bpp mode, usually not used */
+ Uint8 *pix;
+ int shift;
+ Uint32 color=0;
+
+ pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
+ shift = surface->format->Rshift;
+ color = *(pix+shift/8)<format->Gshift;
+ color|= *(pix+shift/8)<format->Bshift;
+ color|= *(pix+shift/8)<format->Ashift;
+ color|= *(pix+shift/8)<pixels + y*surface->pitch/4 + x);
+ }
+ break;
+ }
+ return 0;
+}
+
+/*
+* Macro to get clipping
+*/
+#if SDL_VERSIONNUM(SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL) >= \
+ SDL_VERSIONNUM(1, 1, 5)
+ #define sge_clip_xmin(pnt) pnt->clip_rect.x
+ #define sge_clip_xmax(pnt) pnt->clip_rect.x + pnt->clip_rect.w-1
+ #define sge_clip_ymin(pnt) pnt->clip_rect.y
+ #define sge_clip_ymax(pnt) pnt->clip_rect.y + pnt->clip_rect.h-1
+#else
+ #define sge_clip_xmin(pnt) pnt->clip_minx
+ #define sge_clip_xmax(pnt) pnt->clip_maxx
+ #define sge_clip_ymin(pnt) pnt->clip_miny
+ #define sge_clip_ymax(pnt) pnt->clip_maxy
+#endif
+
+#define SWAP(x,y,temp) temp=x;x=y;y=temp
+//==================================================================================
+// Helper function to sge_transform()
+// Returns the bounding box
+//==================================================================================
+void _calcRect(SDL_Surface *src, SDL_Surface *dst, float theta, float xscale, float yscale, Uint16 px, Uint16 py, Uint16 qx, Uint16 qy, Sint16 *xmin, Sint16 *ymin, Sint16 *xmax, Sint16 *ymax)
+{
+ int i;
+ Sint16 x, y, rx, ry;
+ Sint32 istx, ictx, isty, icty;
+ // Clip to src surface
+ Sint16 sxmin = sge_clip_xmin(src);
+ Sint16 sxmax = sge_clip_xmax(src);
+ Sint16 symin = sge_clip_ymin(src);
+ Sint16 symax = sge_clip_ymax(src);
+ Sint16 sx[]={sxmin, sxmax, sxmin, sxmax};
+ Sint16 sy[]={symin, symax, symax, symin};
+
+ // We don't really need fixed-point here
+ // but why not?
+ istx = (Sint32)((sin(theta)*xscale) * 8192.0); /* Inverse transform */
+ ictx = (Sint32)((cos(theta)*xscale) * 8192.2);
+ isty = (Sint32)((sin(theta)*yscale) * 8192.0);
+ icty = (Sint32)((cos(theta)*yscale) * 8192.2);
+
+ //Calculate the four corner points
+ for(i=0; i<4; i++){
+ rx = sx[i] - px;
+ ry = sy[i] - py;
+
+ x = (Sint16)(((ictx*rx - isty*ry) >> 13) + qx);
+ y = (Sint16)(((icty*ry + istx*rx) >> 13) + qy);
+
+
+ if(i==0){
+ *xmax = *xmin = x;
+ *ymax = *ymin = y;
+ }else{
+ if(x>*xmax)
+ *xmax=x;
+ else if(x<*xmin)
+ *xmin=x;
+
+ if(y>*ymax)
+ *ymax=y;
+ else if(y<*ymin)
+ *ymin=y;
+ }
+ }
+
+ //Better safe than sorry...
+ *xmin -= 1;
+ *ymin -= 1;
+ *xmax += 1;
+ *ymax += 1;
+
+ //Clip to dst surface
+ if( !dst )
+ return;
+ if( *xmin < sge_clip_xmin(dst) )
+ *xmin = sge_clip_xmin(dst);
+ if( *xmax > sge_clip_xmax(dst) )
+ *xmax = sge_clip_xmax(dst);
+ if( *ymin < sge_clip_ymin(dst) )
+ *ymin = sge_clip_ymin(dst);
+ if( *ymax > sge_clip_ymax(dst) )
+ *ymax = sge_clip_ymax(dst);
+}
+
+#define TRANSFORM_GENERIC_AA \
+ Uint8 R, G, B, A, R1, G1, B1, A1=0, R2, G2, B2, A2=0, R3, G3, B3, A3=0, R4, G4, B4, A4=0; \
+ Sint32 wx, wy, p1, p2, p3, p4;\
+\
+ Sint32 const one = 2048; /* 1 in Fixed-point */ \
+ Sint32 const two = 2*2048; /* 2 in Fixed-point */ \
+\
+ for (y=ymin; y> 13); /* Convert from fixed-point */ \
+ ry=(Sint16)(sy >> 13); \
+\
+ /* Make sure the source pixel is actually in the source image. */ \
+ if( (rx>=sxmin) && (rx+1<=sxmax) && (ry>=symin) && (ry+1<=symax) ){ \
+ wx = (sx & 0x00001FFF) >> 2; /* (float(x) - int(x)) / 4 */ \
+ wy = (sy & 0x00001FFF) >> 2;\
+\
+ p4 = wx+wy;\
+ p3 = one-wx+wy;\
+ p2 = wx+one-wy;\
+ p1 = two-wx-wy;\
+\
+ SDL_GetRGBA(sge_GetPixel(src,rx, ry), src->format, &R1, &G1, &B1, &A1);\
+ SDL_GetRGBA(sge_GetPixel(src,rx+1,ry), src->format, &R2, &G2, &B2, &A2);\
+ SDL_GetRGBA(sge_GetPixel(src,rx, ry+1), src->format, &R3, &G3, &B3, &A3);\
+ SDL_GetRGBA(sge_GetPixel(src,rx+1,ry+1), src->format, &R4, &G4, &B4, &A4);\
+\
+ /* Calculate the average */\
+ R = (p1*R1 + p2*R2 + p3*R3 + p4*R4)>>13;\
+ G = (p1*G1 + p2*G2 + p3*G3 + p4*G4)>>13;\
+ B = (p1*B1 + p2*B2 + p3*B3 + p4*B4)>>13;\
+ A = (p1*A1 + p2*A2 + p3*A3 + p4*A4)>>13;\
+\
+ _PutPixelX(dst,x,y,SDL_MapRGBA(dst->format, R, G, B, A)); \
+ \
+ } \
+ sx += ctx; /* Incremental transformations */ \
+ sy -= sty; \
+ } \
+ }
+
+Uint8 _sge_lock=1;
+
+SDL_Rect sge_transformAA(SDL_Surface *src, SDL_Surface *dst, float angle, float xscale, float yscale ,Uint16 px, Uint16 py, Uint16 qx, Uint16 qy, Uint8 flags)
+{
+ Sint32 dy, sx, sy;
+ Sint16 x, y, rx, ry;
+ SDL_Rect r;
+ r.x = r.y = r.w = r.h = 0;
+
+ float theta = (float)(angle*PI/180.0); /* Convert to radians. */
+
+
+ // Here we use 18.13 fixed point integer math
+ // Sint32 should have 31 usable bits and one for sign
+ // 2^13 = 8192
+
+ // Check scales
+ Sint32 maxint = (Sint32)(pow(2, sizeof(Sint32)*8 - 1 - 13)); // 2^(31-13)
+
+ if( xscale == 0 || yscale == 0)
+ return r;
+
+ if( 8192.0/xscale > maxint )
+ xscale = (float)(8192.0/maxint);
+ else if( 8192.0/xscale < -maxint )
+ xscale = (float)(-8192.0/maxint);
+
+ if( 8192.0/yscale > maxint )
+ yscale = (float)(8192.0/maxint);
+ else if( 8192.0/yscale < -maxint )
+ yscale = (float)(-8192.0/maxint);
+
+
+ // Fixed-point equivalents
+ Sint32 const stx = (Sint32)((sin(theta)/xscale) * 8192.0);
+ Sint32 const ctx = (Sint32)((cos(theta)/xscale) * 8192.0);
+ Sint32 const sty = (Sint32)((sin(theta)/yscale) * 8192.0);
+ Sint32 const cty = (Sint32)((cos(theta)/yscale) * 8192.0);
+ Sint32 const mx = (Sint32)(px*8192.0);
+ Sint32 const my = (Sint32)(py*8192.0);
+
+ // Compute a bounding rectangle
+ Sint16 xmin=0, xmax=dst->w, ymin=0, ymax=dst->h;
+ _calcRect(src, dst, theta, xscale, yscale, px, py, qx, qy, &xmin,&ymin, &xmax,&ymax);
+
+ // Clip to src surface
+ Sint16 sxmin = sge_clip_xmin(src);
+ Sint16 sxmax = sge_clip_xmax(src);
+ Sint16 symin = sge_clip_ymin(src);
+ Sint16 symax = sge_clip_ymax(src);
+
+ // Some terms in the transform are constant
+ Sint32 const dx = xmin - qx;
+ Sint32 const ctdx = ctx*dx;
+ Sint32 const stdx = sty*dx;
+
+ // Lock surfaces... hopfully less than two needs locking!
+ if ( SDL_MUSTLOCK(src) && _sge_lock )
+ if ( SDL_LockSurface(src) < 0 )
+ return r;
+ if ( SDL_MUSTLOCK(dst) && _sge_lock ){
+ if ( SDL_LockSurface(dst) < 0 ){
+ if ( SDL_MUSTLOCK(src) && _sge_lock )
+ SDL_UnlockSurface(src);
+ return r;
+ }
+ }
+
+
+ TRANSFORM_GENERIC_AA
+
+
+ // Unlock surfaces
+ if ( SDL_MUSTLOCK(src) && _sge_lock )
+ SDL_UnlockSurface(src);
+ if ( SDL_MUSTLOCK(dst) && _sge_lock )
+ SDL_UnlockSurface(dst);
+
+ //Return the bounding rectangle
+ r.x=xmin; r.y=ymin; r.w=xmax-xmin; r.h=ymax-ymin;
+ return r;
+}
+
+
+SDL_Rect sge_transform(SDL_Surface *src, SDL_Surface *dst, float angle, float xscale, float yscale, Uint16 px, Uint16 py, Uint16 qx, Uint16 qy, Uint8 flags)
+{
+ return sge_transformAA(src, dst, angle, xscale, yscale, px, py, qx, qy, flags);
+}
+
+SDL_Surface *sge_transform_surface(SDL_Surface *src, Uint32 bcol, float angle, float xscale, float yscale, Uint8 flags)
+{
+ float theta = (float)(angle*PI/180.0); /* Convert to radians. */
+
+ // Compute a bounding rectangle
+ Sint16 xmin=0, xmax=0, ymin=0, ymax=0;
+ _calcRect(src, NULL, theta, xscale, yscale, 0, 0, 0, 0, &xmin,&ymin, &xmax,&ymax);
+
+ Sint16 w = xmax-xmin+1;
+ Sint16 h = ymax-ymin+1;
+
+ Sint16 qx = -xmin;
+ Sint16 qy = -ymin;
+
+ SDL_Surface *dest;
+ dest = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, src->format->BitsPerPixel, src->format->Rmask, src->format->Gmask, src->format->Bmask, src->format->Amask);
+ if(!dest)
+ return NULL;
+
+// sge_ClearSurface(dest,bcol); //Set background color
+
+ sge_transform(src, dest, angle, xscale, yscale, 0, 0, qx, qy, flags);
+
+ return dest;
+}
+
+img_t gfx_scale(img_t src, float xscale, float yscale)
+{
+ return (img_t)sge_transform_surface((SDL_Surface *)src, 0, 0, xscale, yscale, 0);
+}
+
+fnt_t fnt_load(const char *fname, int size)
+{
+ TTF_Font *fn;
+ fn = TTF_OpenFont(fname, size);
+ return (fnt_t) fn;
+}
+
+void fnt_free(fnt_t fnt)
+{
+ if (!fnt)
+ return;
+ TTF_CloseFont((TTF_Font *)fnt);
+}
+
+void txt_draw(fnt_t fnt, const char *txt, int x, int y, color_t col)
+{
+ SDL_Color fgcol = { .r = col.r, .g = col.g, .b = col.b };
+ SDL_Surface *s = TTF_RenderUTF8_Blended((TTF_Font *)fnt,
+ txt, fgcol);
+ gfx_draw(s, x, y);
+}
+
+void txt_size(fnt_t fnt, const char *txt, int *w, int *h)
+{
+ int ww, hh;
+ TTF_SizeUTF8((TTF_Font *)fnt, txt, &ww, &hh);
+ if (w)
+ *w = ww;
+ if (h)
+ *h = hh;
+}
+
+struct word;
+struct line;
+struct xref;
+
+struct word {
+ int style;
+ int x;
+ int w;
+ int unbrake;
+ char *word;
+ img_t img;
+ struct word *next; /* in line */
+ struct line *line;
+ struct xref *xref;
+};
+
+struct word *word_new(const char *str)
+{
+ struct word *w;
+ w = malloc(sizeof(struct word));
+ if (!w)
+ return NULL;
+ w->word = strdup(str);
+ w->next = NULL;
+ w->x = 0;
+ w->w = 0;
+ w->line = NULL;
+ w->xref = NULL;
+ w->style = 0;
+ w->img = NULL;
+ w->unbrake = 0;
+ return w;
+}
+
+void word_free(struct word *word)
+{
+ if (!word)
+ return;
+// if (word->img)
+// gfx_free_image(word->img);
+ if (word->word)
+ free(word->word);
+ free(word);
+}
+
+struct line {
+ int y;
+ int h;
+ int w;
+ int num;
+ int align;
+ struct word *words;
+ struct line *next;
+ struct line *prev;
+ struct layout *layout;
+};
+
+struct line *line_new(void)
+{
+ struct line *l;
+ l = malloc(sizeof(struct line));
+ if (!l)
+ return NULL;
+ l->words = NULL;
+ l->next = NULL;
+ l->prev = NULL;
+ l->w = 0;
+ l->y = 0;
+ l->h = 0;
+ l->num = 0;
+ l->layout = NULL;
+ l->align = 0;
+ return l;
+}
+
+void line_justify(struct line *line, int width)
+{
+ int x = 0;
+ struct word *w;
+ int sp, spm, lw = 0;
+ int lnum = 0;
+ if (!line || line->num <= 1 /*|| width <= line->w*/)
+ return;
+ w = line->words;
+ while (w) {
+ lw += w->w;
+ if (!w->unbrake)
+ lnum ++;
+ w = w->next;
+ }
+ if (lnum <=1 )
+ return;
+ w = line->words;
+ 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 --;
+ }
+ w = w->next;
+ }
+}
+
+void line_right(struct line *line, int width)
+{
+ struct word *w;
+ int sp, lw = 0;
+ if (!line || line->num == 0)
+ return;
+ w = line->words;
+ while (w) {
+ lw += w->w;
+ w = w->next;
+ }
+ w = line->words;
+ sp = width - lw;
+ while (w) {
+ w->x += sp;
+ w = w->next;
+ }
+}
+void line_center(struct line *line, int width)
+{
+ struct word *w;
+ int sp;
+ if (!line || line->num == 0)
+ return;
+ sp = (width - line->w)/2;
+ w = line->words;
+ while (w) {
+ w->x += sp;
+ w = w->next;
+ }
+}
+
+void line_align(struct line *line, int width, int style, int nl)
+{
+ if (style == ALIGN_JUSTIFY) {
+ if (nl)
+ return;
+ return line_justify(line, width);
+ }
+ if (style == ALIGN_CENTER)
+ return line_center(line, width);
+ if (style == ALIGN_LEFT)
+ return;
+ if (style == ALIGN_RIGHT)
+ return line_right(line, width);
+}
+
+void line_free(struct line *line)
+{
+ struct word *w;
+ if (!line)
+ return;
+ w = line->words;
+ while (w) {
+ struct word *ow = w;
+ w = w->next;
+ word_free(ow);
+ }
+ free(line);
+}
+
+void line_add_word(struct line *l, struct word *word)
+{
+ struct word *w = l->words;
+ l->num ++;
+ word->line = l;
+ if (!l->words) {
+ l->words = word;
+ return;
+ }
+ while (w->next)
+ w = w->next;
+ w->next = word;
+ return;
+}
+
+struct image;
+struct image {
+ struct image *next;
+ char *name;
+ img_t image;
+};
+
+struct image *image_new(const char *name, img_t img)
+{
+ struct image *g = malloc(sizeof(struct image));
+ if (!g)
+ return NULL;
+ g->image = img;
+ g->name = strdup(name);
+ g->next = NULL;
+ return g;
+}
+
+void image_free(struct image *image)
+{
+ if (!image)
+ return;
+ if (image->name)
+ free(image->name);
+// gfx_free_image(image->image);
+ free(image);
+}
+
+struct textbox;
+struct layout {
+ fnt_t fn;
+ color_t col;
+ color_t lcol;
+ color_t acol;
+ struct image *images;
+ struct xref *xrefs;
+ struct line *lines;
+ struct textbox *box;
+ int w;
+ int h;
+ int align;
+ int style;
+ int lstyle;
+};
+
+struct word_list {
+ struct word_list *next;
+ struct word *word;
+};
+
+struct xref {
+ struct xref *next;
+ struct word **words;
+ struct layout *layout;
+ char *link;
+ int num;
+ int active;
+};
+struct textbox {
+ struct layout *lay;
+ struct line *line;
+ int off;
+ int w;
+ int h;
+};
+
+struct xref *xref_new(char *link)
+{
+ struct xref *p;
+ p = malloc(sizeof(struct xref));
+ if (!p)
+ return NULL;
+ if (link)
+ p->link = strdup(link);
+ else
+ p->link = NULL;
+ p->num = 0;
+ p->layout = NULL;
+ p->next = NULL;
+ p->active = 0;
+ p->words = NULL;
+ return p;
+}
+
+void xref_add_word(struct xref *xref, struct word *word)
+{
+ xref->words = realloc(xref->words, (xref->num + 1) * sizeof(struct word*));
+ xref->words[xref->num ++] = word;
+ word->xref = xref;
+}
+
+void xref_free(struct xref *xref)
+{
+ if (xref->link)
+ free(xref->link);
+ if (xref->words)
+ free(xref->words);
+ free(xref);
+}
+
+void layout_add_line(struct layout *layout, struct line *line)
+{
+ struct line *l = layout->lines;
+ line->layout = layout;
+ if (line->w > layout->w)
+ layout->w = line->w;
+ if (!l) {
+ layout->lines = line;
+ line->prev = NULL;
+ return;
+ }
+ while (l->next)
+ l = l->next;
+ l->next = line;
+ line->prev = l;
+ return;
+}
+
+void layout_add_image(struct layout *layout, struct image *image)
+{
+ struct image *g = layout->images;
+ if (!g) {
+ layout->images = image;
+ return;
+ }
+ while (g->next)
+ g = g->next;
+ g->next = image;
+ return;
+}
+
+img_t layout_lookup_image(struct layout *layout, char *name)
+{
+ struct image *g = layout->images;
+ for (g = layout->images; g; g = g->next) {
+ if (!strcmp(g->name, name))
+ return g->image;
+ }
+ return NULL;
+}
+
+void layout_add_xref(struct layout *layout, struct xref *xref)
+{
+ struct xref *x = layout->xrefs;
+ xref->layout = layout;
+ if (!x) {
+ layout->xrefs = xref;
+ return;
+ }
+ while (x->next)
+ x = x->next;
+ x->next = xref;
+ return;
+}
+
+struct layout *layout_new(fnt_t fn, int w, int h)
+{
+ struct layout *l;
+ l = malloc(sizeof(struct layout));
+ if (!l)
+ return NULL;
+ l->lines = NULL;
+ l->images = NULL;
+ l->w = w;
+ l->h = h;
+ l->fn = fn;
+ l->align = ALIGN_JUSTIFY;
+ l->style = 0;
+ l->lstyle = 0;
+ l->xrefs = NULL;
+ l->col = gfx_col(0, 0, 0);
+ l->lcol = gfx_col(0, 0, 255);
+ l->acol = gfx_col(255, 0, 0);
+ l->box = NULL;
+ return l;
+}
+void txt_layout_size(layout_t lay, int *w, int *h)
+{
+ struct layout *layout = (struct layout *)lay;
+ if (w)
+ *w = layout->w;
+ if (h)
+ *h = layout->h;
+}
+
+int txt_layout_add_img(layout_t lay, const char *name, img_t img)
+{
+ struct layout *layout = (struct layout *)lay;
+ struct image *image;
+ image = image_new(name, img);
+ if (!image)
+ return -1;
+ layout_add_image(layout, image);
+ return 0;
+}
+
+void _txt_layout_free(layout_t lay)
+{
+ struct layout *layout = (struct layout *)lay;
+ struct line *l;
+ struct image *g;
+ struct xref *x;
+ if (!layout)
+ return;
+ l = layout->lines;
+ while (l) {
+ struct line *ol = l;
+ l = l->next;
+ line_free(ol);
+ }
+ x = layout->xrefs;
+ while (x) {
+ struct xref *ox = x;
+ x = x->next;
+ xref_free(ox);
+ }
+ g = layout->images;
+ while (g) {
+ struct image *og = g;
+ g = g->next;
+ image_free(og);
+ }
+ layout->images = NULL;
+ layout->xrefs = NULL;
+ layout->lines = NULL;
+}
+
+void txt_layout_free(layout_t lay)
+{
+ _txt_layout_free(lay);
+ free(lay);
+}
+
+#define TOKEN_NONE 0
+#define TOKEN_A 1
+#define TOKEN_B 2
+#define TOKEN_I 4
+#define TOKEN_U 8
+#define TOKEN_C 0x10
+#define TOKEN_R 0x20
+#define TOKEN_J 0x40
+#define TOKEN_L 0x80
+#define TOKEN_CLOSE 0x2000
+#define TOKEN(x) (x & 0xff)
+
+int get_token(const char *ptr, char **eptr, char **val, int *sp)
+{
+ char *ep, *p;
+ int closing = 0;
+ *eptr = NULL;
+ p = (char*)ptr;
+ ptr += strspn(ptr, " \t");
+ if (sp) {
+ *sp = 0;
+ if (p != ptr)
+ *sp = 1;
+ }
+ if (val)
+ *val = NULL;
+ if (!*ptr)
+ return 0;
+ if (*ptr != '<')
+ return 0;
+ ptr ++;
+ if (*ptr == '/') {
+ closing = 1;
+ if (!ptr[1] || ptr[2] != '>')
+ return 0;
+ ptr ++;
+ }
+ switch (*ptr) {
+ case 'a':
+ if (closing) {
+ *eptr = (char*)ptr + 2;
+ return TOKEN_A | TOKEN_CLOSE;
+ }
+ if (ptr[1] != ':') {
+ return 0;
+ }
+ ptr += 2;
+ ep = (char*)ptr + strcspn(ptr, ">");
+ if (*ep != '>') {
+ return 0;
+ }
+ if (val) {
+ p = malloc(ep - ptr + 1);
+ if (!p)
+ return 0;
+ memcpy(p, ptr, ep - ptr);
+ p[ep - ptr] = 0;
+ *val = p;
+ }
+ *eptr = ep + 1;
+ return TOKEN_A;
+ case 'b':
+ if (closing) {
+ *eptr = (char*)ptr + 2;
+ return TOKEN_B | TOKEN_CLOSE;
+ }
+ if (ptr[1] == '>') {
+ *eptr = (char*)ptr + 2;
+ return TOKEN_B;
+ }
+ break;
+ case 'i':
+ if (closing) {
+ *eptr = (char*)ptr + 2;
+ return TOKEN_I | TOKEN_CLOSE;
+ }
+ if (ptr[1] == '>') {
+ *eptr = (char*)ptr + 2;
+ return TOKEN_I;
+ }
+ break;
+ case 'u':
+ if (closing) {
+ *eptr = (char*)ptr + 2;
+ return TOKEN_U | TOKEN_CLOSE;
+ }
+ if (ptr[1] == '>') {
+ *eptr = (char*)ptr + 2;
+ return TOKEN_U;
+ }
+ break;
+ case 'c':
+ if (closing) {
+ *eptr = (char*)ptr + 2;
+ return TOKEN_C | TOKEN_CLOSE;
+ }
+ if (ptr[1] == '>') {
+ *eptr = (char*)ptr + 2;
+ return TOKEN_C;
+ }
+ break;
+ case 'r':
+ if (closing) {
+ *eptr = (char*)ptr + 2;
+ return TOKEN_R | TOKEN_CLOSE;
+ }
+ if (ptr[1] == '>') {
+ *eptr = (char*)ptr + 2;
+ return TOKEN_R;
+ }
+ break;
+ case 'j':
+ if (closing) {
+ *eptr = (char*)ptr + 2;
+ return TOKEN_J | TOKEN_CLOSE;
+ }
+ if (ptr[1] == '>') {
+ *eptr = (char*)ptr + 2;
+ return TOKEN_J;
+ }
+ break;
+ case 'l':
+ if (closing) {
+ *eptr = (char*)ptr + 2;
+ return TOKEN_L | TOKEN_CLOSE;
+ }
+ if (ptr[1] == '>') {
+ *eptr = (char*)ptr + 2;
+ return TOKEN_L;
+ }
+ break;
+ }
+ return 0;
+}
+
+static const char *lookup_token_or_sp(const char *ptr)
+{
+ char *eptr;
+ const char *p = ptr;
+ while (*p) {
+ p += strcspn(p, " <\n\t");
+ if (*p != '<' )
+ return p;
+ if (!get_token(p, &eptr, NULL, NULL)) {
+ p ++;
+ continue;
+ }
+ return p;
+ }
+ return ptr;
+}
+
+static char *get_word(const char *ptr, char **eptr, int *sp)
+{
+ const char *ep;
+ char *o;
+ size_t sz;
+ *eptr = NULL;
+ o = (char*)ptr;
+ ptr += strspn(ptr, " \t");
+ if (sp) {
+ *sp = 0;
+ if (o != ptr)
+ *sp = 1;
+ }
+ if (!*ptr)
+ return NULL;
+ ep = lookup_token_or_sp(ptr);
+// ep += strcspn(ep, " \t\n");
+ sz = ep - ptr;
+ o = malloc(sz + 1);
+ memcpy(o, ptr, sz);
+ o[sz] = 0;
+ *eptr = (char*)ep;
+ return o;
+}
+
+void layout_debug(struct layout *layout)
+{
+ struct line *line;
+ struct word *word;
+ line = layout->lines;
+ while (line) {
+ printf("%d of %d)", line->y, line->num);
+ word = line->words;
+ while (word) {
+ printf("%d)%s ", word->x, word->word);
+ word = word->next;
+ }
+ printf("\n");
+ line = line->next;
+ }
+}
+
+void txt_layout_color(layout_t lay, color_t fg)
+{
+ struct layout *layout = (struct layout*)lay;
+ layout->col = fg;
+}
+void txt_layout_link_color(layout_t lay, color_t link)
+{
+ struct layout *layout = (struct layout*)lay;
+ layout->lcol = link;
+}
+void txt_layout_active_color(layout_t lay, color_t link)
+{
+ struct layout *layout = (struct layout*)lay;
+ layout->acol = link;
+}
+void txt_layout_link_style(layout_t lay, int style)
+{
+ struct layout *layout = (struct layout*)lay;
+ layout->lstyle = style;
+}
+
+void xref_update(xref_t pxref, int x, int y, clear_fn clear)
+{
+ int i;
+ struct xref *xref = (struct xref*)pxref;
+ struct layout *layout;
+ struct word *word;
+ SDL_Color col;
+ if (!xref)
+ return;
+
+ layout = xref->layout;
+ if (layout->box) {
+ gfx_clip(x, y, layout->box->w, layout->box->h);
+ y -= (layout->box)->off;
+ }
+
+ for (i = 0; i < xref->num; i ++) {
+ SDL_Surface *s;
+ int yy;
+ SDL_Color fgcol = { .r = layout->col.r, .g = layout->col.g, .b = layout->col.b };
+ SDL_Color lcol = { .r = layout->lcol.r, .g = layout->lcol.g, .b = layout->lcol.b };
+ SDL_Color acol = { .r = layout->acol.r, .g = layout->acol.g, .b = layout->acol.b };
+
+ struct line *line;
+ word = xref->words[i];
+ line = word->line;
+
+ if (clear) {
+ if (word->img)
+ clear(x + word->x, y + line->y, gfx_img_w(word->img), gfx_img_h(word->img));
+ else
+ clear(x + word->x, y + line->y, word->w, line->h);
+ }
+ if (word->img) {
+ gfx_draw(word->img, x + word->x, y + line->y);
+ gfx_update(x + word->x, y + line->y, gfx_img_w(word->img), gfx_img_h(word->img));
+ continue;
+ }
+ if (!word->style)
+ TTF_SetFontStyle((TTF_Font *)(layout->fn), layout->lstyle);
+ else
+ TTF_SetFontStyle((TTF_Font *)(layout->fn), word->style);
+ if (!word->xref)
+ col = fgcol;
+ else if (word->xref->active)
+ col = acol;
+ else
+ col = lcol;
+ s = TTF_RenderUTF8_Blended((TTF_Font *)(layout->fn), word->word, col);
+ yy = (line->h - TTF_FontHeight((TTF_Font *)(layout->fn))) / 2; // TODO
+ gfx_draw(s, x + word->x, y + line->y + yy);
+ gfx_update(x + word->x, y + line->y, word->w, line->h);
+ SDL_FreeSurface(s);
+ }
+ gfx_noclip();
+}
+
+
+void txt_layout_draw_ex(layout_t lay, struct line *line, int x, int y, int off, int height, clear_fn clear)
+{
+ struct layout *layout = (struct layout*)lay;
+// struct line *line;
+ struct word *word;
+// line = layout->lines;
+ SDL_Color col;
+ SDL_Color fgcol = { .r = layout->col.r, .g = layout->col.g, .b = layout->col.b };
+ SDL_Color lcol = { .r = layout->lcol.r, .g = layout->lcol.g, .b = layout->lcol.b };
+ SDL_Color acol = { .r = layout->acol.r, .g = layout->acol.g, .b = layout->acol.b };
+// gfx_clip(x, y, layout->w, layout->h);
+ 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;
+
+ if (clear) {
+ if (word->img)
+ clear(x + word->x, y + line->y, gfx_img_w(word->img), gfx_img_h(word->img));
+ else
+ clear(x + word->x, y + line->y, word->w, line->h);
+ }
+ SDL_Surface *s;
+ if (word->img) {
+ gfx_draw(word->img, x + word->x, y + line->y);
+ continue;
+ }
+ if (word->xref && !word->style)
+ TTF_SetFontStyle((TTF_Font *)(layout->fn), layout->lstyle);
+ else
+ TTF_SetFontStyle((TTF_Font *)(layout->fn), word->style);
+ if (!word->xref)
+ col = fgcol;
+ else if (word->xref->active)
+ col = acol;
+ else
+ col = lcol;
+ s = TTF_RenderUTF8_Blended((TTF_Font *)(layout->fn),
+ word->word, col);
+ yy = (line->h - TTF_FontHeight((TTF_Font *)(layout->fn))) / 2; // TODO
+ gfx_draw(s, x + word->x, y + line->y + yy);
+ SDL_FreeSurface(s);
+ }
+ }
+// gfx_noclip();
+}
+
+void txt_layout_draw(layout_t lay, int x, int y)
+{
+ struct layout *layout = (struct layout*)lay;
+ txt_layout_draw_ex(lay, NULL, x, y, 0, layout->h, 0);
+}
+
+
+textbox_t txt_box(int w, int h)
+{
+ struct textbox *box;
+ box = malloc(sizeof(struct textbox));
+ if (!box)
+ return NULL;
+ box->lay = NULL; //(struct layout*)lay;
+ box->w = w;
+ box->h = h;
+ box->off = 0;
+ box->line = NULL; //(box->lay)->lines;
+ return box;
+}
+
+
+void txt_box_norm(textbox_t tbox)
+{
+ struct textbox *box = (struct textbox *)tbox;
+ struct line *line;
+ if (!box->lay)
+ return;
+ for (line = box->lay->lines; line; line = line->next) {
+ if (box->off < line->h) {
+ box->line = line;
+ break;
+ }
+ box->off -= line->h;
+ }
+ box->line = box->lay->lines;
+}
+
+layout_t txt_box_layout(textbox_t tbox)
+{
+ struct textbox *box = (struct textbox *)tbox;
+ return box->lay;
+}
+
+void txt_box_set(textbox_t tbox, layout_t lay)
+{
+ struct textbox *box = (struct textbox *)tbox;
+ box->lay = (struct layout*)lay;
+ box->off = 0;
+ if (lay)
+ box->lay->box = box;
+ txt_box_norm(tbox);
+}
+
+void txt_box_resize(textbox_t tbox, int w, int h)
+{
+ struct textbox *box = (struct textbox *)tbox;
+ box->w = w;
+ box->h = h;
+ txt_box_norm(tbox);
+}
+
+void txt_box_size(textbox_t tbox, int *w, int *h)
+{
+ struct textbox *box = (struct textbox *)tbox;
+ if (w)
+ *w = box->w;
+ if (h)
+ *h = box->h;
+}
+
+void txt_box_scroll(textbox_t tbox, int disp)
+{
+ int ld;
+ struct textbox *box = (struct textbox *)tbox;
+ struct line *line = box->line;
+ if (!line)
+ return;
+ ld = box->off - line->y + disp;
+ while (line && ld > line->h) {
+ ld -= line->h;
+ line = line->next;
+ }
+ if (line) {
+ box->line = line;
+ box->off = line->y + ld;
+ }
+// line = line->next;
+// if (line) {
+// box->off += (line->y - box->off);
+// box->line = line;
+// }
+}
+
+void txt_box_next_line(textbox_t tbox)
+{
+ struct textbox *box = (struct textbox *)tbox;
+ struct line *line = box->line;
+ if (!line)
+ return;
+// txt_box_norm(tbox);
+ if (box->lay->h - box->off < box->h)
+ return;
+ line = line->next;
+ if (line) {
+ box->off = line->y;
+ box->line = line;
+ }
+}
+
+void txt_box_prev_line(textbox_t tbox)
+{
+ struct textbox *box = (struct textbox *)tbox;
+ struct line *line = box->line;
+ if (!line)
+ return;
+ line = line->prev;
+ if (line) {
+ box->line = line;
+ box->off = line->y;
+ } else
+ box->off = 0;
+}
+
+int txt_box_off(textbox_t tbox)
+{
+ struct textbox *box = (struct textbox *)tbox;
+ return box->off;
+}
+
+void txt_box_next(textbox_t tbox)
+{
+ struct textbox *box = (struct textbox *)tbox;
+ struct line *line = box->line;
+ if (!line)
+ return;
+ for (; line; line = line->next) {
+ if ((line->y + line->h - box->off) >= box->h)
+ break;
+ }
+ if (line) {
+ box->off += (line->y - box->off);
+ box->line = line;
+ }
+}
+
+void txt_box_prev(textbox_t tbox)
+{
+ struct textbox *box = (struct textbox *)tbox;
+ struct layout *lay = box->lay;
+ struct line *line = box->line;
+ if (!line)
+ return;
+ for (; line; line = line->prev) {
+ if ((box->off - line->y) >= box->h)
+ break;
+ }
+ if (!line) {
+ box->off = 0;
+ box->line = lay->lines;
+ return;
+ }
+ box->off = line->y;
+ box->line = line;
+}
+
+xref_t txt_box_xref(textbox_t tbox, int x, int y)
+{
+ struct textbox *box = (struct textbox*)tbox;
+ struct xref *xref = NULL;
+ struct word *word = NULL;
+ struct line *line;
+ y += box->off;
+ if (x < 0)
+ return NULL;
+ if (y < 0)
+ return NULL;
+ if (x >= box->w)
+ return NULL;
+ for (line = box->line; line; line = line->next) {
+ if (y < line->y)
+ break;
+ if (y > line->y + line->h)
+ continue;
+ for (word = line->words; word; word = word->next) {
+ if (x < word->x)
+ continue;
+ xref = word->xref;
+ if (!xref)
+ continue;
+ if (x < word->x + word->w)
+ break;
+ if (word->next && word->next->xref == xref && x < word->next->x + word->next->w)
+ break;
+ }
+ }
+ if (word && xref) {
+ return xref;
+ }
+ return NULL;
+}
+
+void txt_box_free(textbox_t tbox)
+{
+ free(tbox);
+}
+
+img_t txt_box_render(textbox_t tbox)
+{
+ SDL_Surface *old_screen;
+ img_t dst;
+ struct textbox *box = (struct textbox *)tbox;
+ dst = gfx_new(box->w, box->h);
+ if (!dst)
+ return NULL;
+ old_screen = screen;
+ screen = (SDL_Surface*)dst;
+ gfx_clear(0, 0, box->w, box->h);
+// gfx_clip(0, 0, box->w, box->h);
+// printf("line: %d\n", box->line->y);
+ txt_layout_draw_ex(box->lay, box->line, 0, - box->off, box->off, box->h, NULL);
+// gfx_noclip();
+ screen = old_screen;
+ return dst;
+}
+
+void txt_box_draw(textbox_t tbox, int x, int y)
+{
+ struct textbox *box = (struct textbox *)tbox;
+ gfx_clip(x, y, box->w, box->h);
+// printf("line: %d\n", box->line->y);
+ txt_layout_draw_ex(box->lay, box->line, x, y - box->off, box->off, box->h, NULL);
+ gfx_noclip();
+}
+
+void txt_box_update_links(textbox_t tbox, int x, int y, clear_fn clear)
+{
+ struct textbox *box = (struct textbox *)tbox;
+ gfx_clip(x, y, box->w, box->h);
+// printf("line: %d\n", box->line->y);
+ txt_layout_draw_ex(box->lay, box->line, x, y - box->off, box->off, box->h, clear);
+ gfx_noclip();
+}
+
+
+void txt_layout_update_links(layout_t layout, int x, int y, clear_fn clear)
+{
+ struct layout *lay = (struct layout *)layout;
+// gfx_clip(x, y, box->w, box->h);
+// printf("line: %d\n", box->line->y);
+ txt_layout_draw_ex(lay, lay->lines, x, y, 0, lay->h, clear);
+// gfx_noclip();
+}
+img_t get_img(struct layout *layout, char *p)
+{
+ int len;
+ img_t img;
+ if (p[0] != '<' || p[1] != 'g' || p[2] != ':')
+ return NULL;
+ p += 3;
+ len = strcspn(p, ">");
+ if (p[len] != '>')
+ return NULL;
+ p[len] = 0;
+ img = layout_lookup_image(layout, p);
+ p[len] = '>';
+ return img;
+}
+
+char *process_token(char *ptr, struct layout *layout, struct line *line, struct xref **xref, int *sp)
+{
+
+ int token;
+ char *val = NULL;
+ int bit = 0;
+ int al = 0;
+ char *eptr;
+
+ token = get_token(ptr, &eptr, &val, sp);
+ if (!token)
+ return NULL;
+ if (TOKEN(token) == TOKEN_B)
+ bit = TTF_STYLE_BOLD;
+ else if (TOKEN(token) == TOKEN_I)
+ bit = TTF_STYLE_ITALIC;
+ else if (TOKEN(token) == TOKEN_U)
+ bit = TTF_STYLE_UNDERLINE;
+
+ if (bit) {
+ if (token & TOKEN_CLOSE)
+ layout->style &= ~bit;
+ else
+ layout->style |= bit;
+ goto out;
+ }
+
+ if (TOKEN(token) == TOKEN_L)
+ al = ALIGN_LEFT;
+ else if (TOKEN(token) == TOKEN_R)
+ al = ALIGN_RIGHT;
+ else if (TOKEN(token) == TOKEN_C)
+ al = ALIGN_CENTER;
+ else if (TOKEN(token) == TOKEN_J)
+ al = ALIGN_JUSTIFY;
+
+ if (al) {
+ line->align = al;
+ goto out;
+ }
+
+ if (TOKEN(token) == TOKEN_A) {
+ if (token & TOKEN_CLOSE) {
+ if (*xref)
+ layout_add_xref(layout, *xref);
+ *xref = NULL;
+ } else {
+ if (*xref) {
+ eptr = NULL;
+ goto out;
+ }
+ *xref = xref_new(val);
+ }
+ }
+out:
+ if (val)
+ free(val);
+
+ return eptr;
+// TTF_SetFontStyle((TTF_Font *)(layout->fn), style);
+}
+
+int get_unbrakable_len(struct layout *layout, const char *ptr)
+{
+ int w = 0;
+ int ww = 0;
+ char *p, *eptr;
+ while (*ptr) {
+ int sp, sp2 = 0;
+ while(get_token(ptr, &eptr, NULL, &sp)) {
+ if (sp)
+ sp2 ++;
+ ptr = eptr;
+ }
+ if (sp2)
+ return w;
+ p = get_word(ptr, &eptr, &sp);
+ if (!p)
+ return w;
+ if (sp) {
+ free(p);
+ return w;
+ }
+ TTF_SizeUTF8((TTF_Font *)(layout->fn), p, &ww, NULL);
+ ptr = eptr;
+ if (!*p)
+ ptr ++;
+ w += ww;
+ free(p);
+ }
+ return ww;
+}
+
+void _txt_layout_add(layout_t lay, char *txt)
+{
+ int sp = 0;
+ int saved_style;
+ struct line *line, *lastline = NULL;
+ struct layout *layout = (struct layout*)lay;
+ char *p, *eptr;
+ char *ptr = txt;
+ struct xref *xref = NULL;
+ int w, h, nl = 0;
+ int spw;
+ img_t img = NULL;
+ if (!layout)
+ return;
+ saved_style = TTF_GetFontStyle((TTF_Font *)(layout->fn));
+
+ TTF_SetFontStyle((TTF_Font *)(layout->fn), 0);
+ TTF_SizeUTF8((TTF_Font *)(layout->fn), " ", &spw, &h);
+
+ for (line = layout->lines; line; line = line->next)
+ lastline = line;
+
+ if (!lastline) {
+ line = line_new();
+ if (!line)
+ goto err;
+ line->h = h;
+ line->align = layout->align;
+ } else {
+ line = lastline;
+ }
+
+ while (ptr && *ptr) {
+ struct word *word;
+ int sp2, addlen;
+
+ eptr = process_token(ptr, layout, line, &xref, &sp2);
+ if (eptr) {
+ ptr = eptr;
+ TTF_SetFontStyle((TTF_Font *)(layout->fn), layout->style);
+ if (!ptr || !*ptr)
+ break;
+ if (sp2)
+ sp = 2;
+ continue;
+ }
+ if (sp == 2) {
+ p = get_word(ptr, &eptr, NULL);
+ sp = 1;
+ } else
+ p = get_word(ptr, &eptr, &sp);
+ addlen = get_unbrakable_len(layout, eptr);
+ img = get_img(layout, p);
+ if (img) {
+ w = gfx_img_w(img);
+ h = gfx_img_h(img);
+ } else {
+// fprintf(stderr,"AAA:'%s'\n", p);
+ TTF_SizeUTF8((TTF_Font *)(layout->fn), p, &w, &h);
+ }
+ nl = !*p;
+ if ((line->num && (line->w + ((line->w)?spw:0) + w + addlen) >= layout->w) || nl) {
+// if ((line->num && (line->w + ((sp)?spw:0) + w) >= layout->w) || nl) {
+ struct line *ol = line;
+ if ((layout->h) && (line->y + line->h) >= layout->h)
+ break;
+ if (line != lastline) {
+ layout_add_line(layout, line);
+ }
+ line_align(line, layout->w, line->align, nl);
+
+ line = line_new();
+ if (!line) {
+ free(p);
+ goto err;
+ }
+ line->align = layout->align;
+ line->h = h;
+ line->y = ol->y + ol->h;
+ if (nl) {
+ ptr = eptr + 1;
+// line->y += TTF_FontLineSkip((TTF_Font*)(layout->fn));
+ }
+ free(p);
+// ptr = eptr;
+ continue;
+ }
+ if (h > line->h)
+ line->h = h;
+ word = word_new(p);
+ if (!word) {
+ line_free(line);
+ goto err;
+ }
+ if (!sp && line->num)
+ word->unbrake = 1;
+ word->style = layout->style;
+
+ if (line->w && !word->unbrake)
+ line->w += spw;
+
+ word->w = w;
+ word->x = line->w;
+
+ word->img = img;
+
+// if (line->w)
+// w += spw;
+
+ line_add_word(line, word);
+
+ if (xref)
+ xref_add_word(xref, word);
+
+ line->w += w;
+
+ if (nl)
+ eptr ++;
+ ptr = eptr;
+ free(p);
+ }
+ if (layout->h == 0)
+ layout->h = line->y + line->h;
+
+// if (line->num) {
+ if (line != lastline)
+ layout_add_line(layout, line);
+ line_align(line, layout->w, line->align, nl);
+// } else
+// line_free(line);
+ if (xref)
+ layout_add_xref(layout, xref);
+// layout->align = align;
+// layout_debug(layout);
+// fnt_draw_layout(layout, 300, 100, gfx_col(255,255,255));
+ TTF_SetFontStyle((TTF_Font *)(layout->fn), saved_style);
+ return;
+err:
+ txt_layout_free(layout);
+ TTF_SetFontStyle((TTF_Font *)(layout->fn), saved_style);
+ return;
+}
+
+void txt_layout_add(layout_t lay, char *txt)
+{
+ struct layout *layout = (struct layout*)lay;
+ if (layout)
+ layout->h = 0;
+ _txt_layout_add(lay, txt);
+}
+
+xref_t txt_layout_xref(layout_t lay, int x, int y)
+{
+ struct layout *layout = (struct layout*)lay;
+ struct xref *xref;
+ struct word *word;
+ struct line *line;
+ int i;
+ if (x < 0 || y < 0)
+ return NULL;
+ for (xref = layout->xrefs; xref; xref = xref->next) {
+ for (i = 0; i < xref->num; i ++) {
+ word = xref->words[i];
+ line = word->line;
+ if (y < line->y || y > line->y + line->h)
+ continue;
+ if (x < word->x)
+ continue;
+ if (x <= word->x + word->w)
+ return xref;
+ if (word->next && word->next->xref == xref && x < word->next->x + word->next->w)
+ return xref;
+ }
+ }
+ return NULL;
+}
+
+layout_t xref_layout(xref_t x)
+{
+ struct xref *xref = (struct xref*)x;
+ if (!xref)
+ return NULL;
+ return xref->layout;
+}
+
+char *xref_get_text(xref_t x)
+{
+ struct xref *xref = (struct xref*)x;
+ if (!xref)
+ return NULL;
+ return xref->link;
+}
+
+void xref_set_active(xref_t x, int val)
+{
+ struct xref *xref = (struct xref*)x;
+ if (!xref)
+ return;
+ xref->active = val;
+}
+
+
+layout_t txt_layout(fnt_t fn, int align, int width, int height)
+{
+ struct layout *layout;
+ layout = layout_new(fn, width, height);
+ if (!layout)
+ return NULL;
+ layout->align = align;
+// _txt_layout_add(layout, txt);
+ return layout;
+}
+
+void txt_layout_set(layout_t lay, char *txt)
+{
+ struct layout *layout = (struct layout*)lay;
+ if (!layout)
+ return;
+ layout->h = 0;
+ _txt_layout_free(lay);
+ _txt_layout_add(lay, txt);
+}
+
+
+void txt_layout_real_size(layout_t lay, int *pw, int *ph)
+{
+ int w = 0;
+ int h = 0;
+ struct line *line;
+ struct layout *layout = (struct layout*)lay;
+ if (!layout)
+ return;
+ for (line = layout->lines; line; line = line->next) {
+ if (line->w > w)
+ w = line->w;
+ if (line->y + line->h > h)
+ h = line->y + line->h;
+ }
+ if (pw)
+ *pw = w;
+ if (ph)
+ *ph = h;
+}
+
+void gfx_cursor(int *xp, int *yp, int *w, int *h)
+{
+ int x, y;
+ SDL_Cursor *c = SDL_GetCursor();
+ if (!c)
+ return;
+ SDL_GetMouseState(&x, &y);
+ if (w)
+ *w = c->area.w - c->hot_x;
+ if (h)
+ *h = c->area.h - c->hot_y;
+ if (xp)
+ *xp = x;
+ if (yp)
+ *yp = y;
+}
+
+#define ALPHA_STEPS 5
+volatile int step_nr = -1;
+SDL_mutex *sem;
+
+static Uint32 update(Uint32 interval, void *aux)
+{
+ img_t img = (img_t) aux;
+ gfx_set_alpha(img, (255 * (step_nr + 1)) / ALPHA_STEPS);
+ gfx_draw(img, 0, 0);
+ gfx_flip();
+ step_nr ++;
+ if (step_nr == ALPHA_STEPS) {
+ step_nr = -1;
+ return 0;
+ }
+ return interval;
+}
+
+void gfx_change_screen(img_t src)
+{
+ sem = SDL_CreateMutex();
+ step_nr = 0;
+ SDL_AddTimer(60, update, src);
+ while (step_nr != -1) {
+ usleep(100);
+ }
+ SDL_DestroyMutex(sem);
+}
+
diff --git a/src/sdl-instead/graphics.h b/src/sdl-instead/graphics.h
new file mode 100644
index 0000000..67d4701
--- /dev/null
+++ b/src/sdl-instead/graphics.h
@@ -0,0 +1,105 @@
+#ifndef __GRAPHICS_H__
+#define __GRAPHICS_H__
+typedef void* img_t;
+typedef void* fnt_t;
+typedef void* layout_t;
+typedef void* textbox_t;
+typedef void* xref_t;
+typedef struct {
+ int r;
+ int g;
+ int b;
+} color_t;
+#define ALIGN_LEFT 1
+#define ALIGN_RIGHT 2
+#define ALIGN_CENTER 4
+#define ALIGN_JUSTIFY 8
+
+#define STYLE_NORMAL 0x00
+#define STYLE_BOLD 0x01
+#define STYLE_ITALIC 0x02
+#define STYLE_UNDERLINE 0x04
+
+static inline color_t gfx_col(int r, int g, int b)
+{
+ color_t col;
+ col.r = r;
+ col.g = g;
+ col.b = b;
+ return col;
+}
+extern int gfx_parse_color (const char *spec, color_t *def);
+extern void gfx_flip(void);
+extern img_t gfx_screen(img_t nscreen);
+extern void gfx_bg(color_t col);
+extern void gfx_noclip(void);
+extern void gfx_clip(int x, int y, int w, int h);
+extern int gfx_width;
+extern int gfx_height;
+extern int gfx_init(int w, int h, int fs);
+extern void gfx_update(int x, int y, int w, int h);
+extern void gfx_done(void);
+extern void gfx_clear(int x, int y, int w, int h);
+extern void gfx_draw(img_t pixmap, int x, int y);
+extern void gfx_draw_wh(img_t p, int x, int y, int w, int h);
+extern img_t gfx_grab_screen(int x, int y, int w, int h);
+extern img_t gfx_new(int w, int h);
+extern img_t gfx_load_image(char *filename, int transparent);
+extern void gfx_free_image(img_t pixmap);
+extern int gfx_img_w(img_t pixmap);
+extern int gfx_img_h(img_t pixmap);
+extern img_t gfx_combine(img_t src, img_t dst);
+extern void gfx_set_alpha(img_t src, int alpha);
+extern img_t gfx_alpha_img(img_t src, int alpha);
+extern img_t gfx_scale(img_t src, float xscale, float yscale);
+extern void gfx_draw_bg(img_t p, int x, int y, int width, int height);
+extern void gfx_draw_from(img_t p, int x, int y, int xx, int yy, int width, int height);
+extern void gfx_cursor(int *xp, int *yp, int *w, int *h);
+extern void gfx_change_screen(img_t src);
+extern void gfx_img_fill(img_t img, int x, int y, int w, int h, color_t col);
+extern void gfx_fill(int x, int y, int w, int h, color_t col);
+
+extern fnt_t fnt_load(const char *fname, int size);
+extern void fnt_free(fnt_t);
+
+extern void txt_draw(fnt_t fnt, const char *txt, int x, int y, color_t col);
+extern void txt_size(fnt_t fnt, const char *txt, int *w, int *h);
+//extern layout_t txt_layout(fnt_t fn, char *txt, int width, int height);
+extern layout_t txt_layout(fnt_t fn, int align, int width, int height);
+extern void txt_layout_add(layout_t lay, char *txt);
+extern void txt_layout_set(layout_t lay, char *txt);
+extern void txt_layout_draw(layout_t lay, int x, int y);
+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 void txt_layout_link_color(layout_t lay, color_t link);
+extern void txt_layout_active_color(layout_t lay, color_t link);
+extern void txt_layout_link_style(layout_t lay, int style);
+extern int txt_layout_add_img(layout_t lay, const char *name, img_t img);
+extern void txt_layout_size(layout_t lay, int *w, int *h);
+extern textbox_t txt_box(int w, int h);
+extern layout_t txt_box_layout(textbox_t tbox);
+extern void txt_box_set(textbox_t tbox, layout_t lay);
+extern void txt_box_free(textbox_t tbox);
+extern void txt_box_draw(textbox_t tbox, int x, int y);
+extern void txt_box_next(textbox_t tbox);
+extern void txt_box_prev(textbox_t tbox);
+extern void txt_box_next_line(textbox_t tbox);
+extern void txt_box_prev_line(textbox_t tbox);
+extern xref_t txt_box_xref(textbox_t tbox, int x, int y);
+extern int txt_box_off(textbox_t tbox);
+extern void txt_box_size(textbox_t tbox, int *w, int *h);
+extern void txt_box_resize(textbox_t tbox, int w, int h);
+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 img_t txt_box_render(textbox_t tbox);
+
+extern char *xref_get_text(xref_t x);
+extern void xref_set_active(xref_t x, int val);
+extern layout_t xref_layout(xref_t x);
+extern void xref_update(xref_t xref, int x, int y, clear_fn clear);
+#endif
+
diff --git a/src/sdl-instead/gui.h b/src/sdl-instead/gui.h
new file mode 100644
index 0000000..6184beb
--- /dev/null
+++ b/src/sdl-instead/gui.h
@@ -0,0 +1,39 @@
+char *instead_gui_lua = "game.hinting = true;\n\
+game.showlast = true;\n\
+iface.xref = function(self, str, obj)\n\
+-- return '@'..str..'{'..obj..'}';\n\
+ local o = ref(here():srch(obj));\n\
+ local cmd=''\n\
+ if not o then \n\
+ o = ref(ways():srch(obj));\n\
+ if o then\n\
+ cmd = 'go ';\n\
+ end\n\
+ end\n\
+ if not o then\n\
+ o = ref(inv():srch(obj));\n\
+ end\n\
+ if not o or not o.id then\n\
+ return str;\n\
+-- error ('Xref to nowhere:'..str);\n\
+ end\n\
+ return cat('',str,'');\n\
+end;\n\
+iface.title = function(self, str)\n\
+ return nil\n\
+end;\n\
+\n\
+iface.inv = function(self, str)\n\
+ if str then\n\
+ return string.gsub(str,',','^');\n\
+ end\n\
+ return str\n\
+end;\n\
+\n\
+iface.ways = function(self, str)\n\
+ if str then\n\
+ return ''..string.gsub(str,',',' | ')..'';\n\
+ end\n\
+ return str\n\
+end;";
+
diff --git a/src/sdl-instead/input.c b/src/sdl-instead/input.c
new file mode 100644
index 0000000..fe58e77
--- /dev/null
+++ b/src/sdl-instead/input.c
@@ -0,0 +1,54 @@
+#include
+#include "input.h"
+int input(struct inp_event *inp, int wait)
+{
+ int rc;
+ SDL_Event event;
+ if (wait)
+ rc = SDL_WaitEvent(&event);
+ else
+ rc = SDL_PollEvent(&event);
+ if (!rc)
+ return 0;
+ inp->sym = NULL;
+ inp->type = 0;
+ switch(event.type){
+ case SDL_QUIT:
+ return -1;
+ case SDL_KEYDOWN: //A key has been pressed
+ inp->type = KEY_DOWN;
+ inp->code = event.key.keysym.scancode;
+ inp->sym = SDL_GetKeyName(event.key.keysym.sym);
+ break;
+ case SDL_KEYUP:
+ inp->type = KEY_UP;
+ inp->code = event.key.keysym.scancode;
+ inp->sym = SDL_GetKeyName(event.key.keysym.sym);
+ break;
+ case SDL_MOUSEMOTION:
+ inp->type = MOUSE_MOTION;
+ inp->x = event.button.x;
+ inp->y = event.button.y;
+ break;
+ case SDL_MOUSEBUTTONUP:
+ inp->type = MOUSE_UP;
+ inp->x = event.button.x;
+ inp->y = event.button.y;
+ if (event.button.button == 4)
+ inp->type = 0;
+ else if (event.button.button == 5)
+ inp->type = 0;
+ break;
+ case SDL_MOUSEBUTTONDOWN:
+ inp->type = MOUSE_DOWN;
+ inp->x = event.button.x;
+ inp->y = event.button.y;
+ if (event.button.button == 4)
+ inp->type = MOUSE_WHEEL_UP;
+ else if (event.button.button == 5)
+ inp->type = MOUSE_WHEEL_DOWN;
+ break;
+ }
+ return 1;
+}
+
diff --git a/src/sdl-instead/input.h b/src/sdl-instead/input.h
new file mode 100644
index 0000000..4388380
--- /dev/null
+++ b/src/sdl-instead/input.h
@@ -0,0 +1,22 @@
+#ifndef __INPUT_H__
+#define __INPUT_H__
+
+#define KEY_DOWN 1
+#define KEY_UP 2
+#define MOUSE_DOWN 3
+#define MOUSE_UP 4
+#define MOUSE_WHEEL_UP 5
+#define MOUSE_WHEEL_DOWN 6
+#define MOUSE_MOTION 7
+
+struct inp_event {
+ int type;
+ int code;
+ char *sym;
+ int x;
+ int y;
+};
+
+int input(struct inp_event *ev, int wait);
+
+#endif
diff --git a/src/sdl-instead/instead.c b/src/sdl-instead/instead.c
new file mode 100644
index 0000000..8a37615
--- /dev/null
+++ b/src/sdl-instead/instead.c
@@ -0,0 +1,214 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "gui.h"
+#ifdef HAVE_ICONV
+#include
+#endif
+/* the Lua interpreter */
+
+char *fromgame(const char *s);
+char *togame(const char *s);
+lua_State *L = NULL;
+
+char *getstring(char *cmd)
+{
+ char *s;
+ if (!L)
+ return NULL;
+ if (luaL_dostring(L, cmd)) {
+ fprintf(stderr,"Error: %s\n", lua_tostring(L, -1));
+ exit(1);
+ }
+ s = (char*)lua_tostring(L, -1);
+ if (s)
+ s = fromgame(s);
+ return s;
+}
+
+char *instead_eval(char *s)
+{
+ char *p;
+// s = togame(s);
+ p = getstring(s);
+// free(s);
+ return p;
+}
+
+char *instead_cmd(char *s)
+{
+ char buf[1024];
+ char *p = s;
+ while (*p) {
+ if (*p == '\\' || *p == '\'' || *p == '\"' || *p == '[' || *p == ']')
+ return NULL;
+ p ++;
+ }
+ s = togame(s);
+ snprintf(buf, sizeof(buf), "return iface:cmd('%s')", s);
+ free(s);
+ p = getstring(buf);
+ return p;
+}
+
+int luacall(char *cmd)
+{
+ int rc;
+ if (!L)
+ return -1;
+ if (luaL_dostring(L, cmd)) {
+ fprintf(stderr,"Error: %s\n", lua_tostring(L, -1));
+ exit(1);
+ }
+ rc = lua_tonumber(L, -1);
+ return rc;
+}
+
+#ifdef HAVE_ICONV
+static char *curcp = "UTF-8";
+static char *fromcp = NULL;
+#endif
+
+#ifdef HAVE_ICONV
+#define CHAR_MAX_LEN 4
+static char *decode(iconv_t hiconv, const char *s)
+{
+ size_t s_size, chs_size, outsz, insz;
+ char *inbuf, *outbuf, *chs_buf;
+ if (!s || hiconv == (iconv_t)(-1))
+ return NULL;
+ s_size = strlen(s) + 1;
+ chs_size = s_size * CHAR_MAX_LEN;
+ if ((chs_buf = malloc(chs_size + CHAR_MAX_LEN))==NULL)
+ goto exitf;
+ outsz = chs_size;
+ outbuf = chs_buf;
+ insz = s_size;
+ inbuf = (char*)s;
+ while (insz) {
+ if (iconv(hiconv, &inbuf, &insz, &outbuf, &outsz)
+ == (size_t)(-1))
+ goto exitf;
+ }
+ *outbuf++ = 0;
+ return chs_buf;
+exitf:
+ if(chs_buf)
+ free(chs_buf);
+ return NULL;
+}
+
+char *fromgame(const char *s)
+{
+ iconv_t han;
+ char *str;
+ if (!s)
+ return NULL;
+ if (!fromcp)
+ goto out0;
+ han = iconv_open(curcp, fromcp);
+ if (han == (iconv_t)-1)
+ goto out0;
+ if (!(str = decode(han, s)))
+ goto out1;
+ iconv_close(han);
+ return str;
+out1:
+ iconv_close(han);
+out0:
+ return strdup(s);
+}
+
+char *togame(const char *s)
+{
+ iconv_t han;
+ char *str;
+ if (!s)
+ return NULL;
+ if (!fromcp)
+ goto out0;
+ han = iconv_open(fromcp, curcp);
+ if (han == (iconv_t)-1)
+ goto out0;
+ if (!(str = decode(han, s)))
+ goto out1;
+ iconv_close(han);
+ return str;
+out1:
+ iconv_close(han);
+out0:
+ return strdup(s);
+}
+#else
+char *fromgame(const char *s)
+{
+ if (!s)
+ return NULL;
+ return strdup(s);
+}
+char *togame(const char *s)
+{
+ if (!s)
+ return NULL;
+ return strdup(s);
+}
+#endif
+
+int instead_load(char *game)
+{
+ if (luaL_loadfile(L, game) || lua_pcall(L, 0, 0, 0)) {
+ fprintf(stderr,"Error:%s\n", lua_tostring(L, -1));
+ return -1;
+ }
+#ifdef HAVE_ICONV
+ if (fromcp)
+ free(fromcp);
+ fromcp = getstring("return game.codepage;");
+#endif
+ return 0;
+}
+
+int instead_init(void)
+{
+ setlocale(LC_ALL,"");
+// strcpy(curcp, "UTF-8");
+ /* initialize Lua */
+ L = lua_open();
+ luaL_openlibs(L);
+ if (luaL_loadfile(L,STEAD_PATH"stead.lua") || lua_pcall(L, 0, 0, 0)) {
+ fprintf(stderr,"Error:%s\n", lua_tostring(L, -1));
+ return -1;
+ }
+ if (luacall(instead_gui_lua)) {
+ fprintf(stderr,"Error while registering lua gui functions\n");
+ return -1;
+
+ }
+#if 0
+ if (luaL_loadfile(L,"gui.lua") || lua_pcall(L, 0, 0, 0)) {
+ fprintf(stderr,"Error:%s\n", lua_tostring(L, -1));
+ return -1;
+ }
+#endif
+ /* cleanup Lua */
+ return 0;
+}
+
+void instead_done(void)
+{
+#ifdef HAVE_ICONV
+ if (fromcp)
+ free(fromcp);
+#endif
+ if (L)
+ lua_close(L);
+ L = NULL;
+ fromcp = NULL;
+}
+
diff --git a/src/sdl-instead/instead.h b/src/sdl-instead/instead.h
new file mode 100644
index 0000000..8b62135
--- /dev/null
+++ b/src/sdl-instead/instead.h
@@ -0,0 +1,10 @@
+#ifndef __INSTEAD_H__
+#define __INSTEAD_H__
+
+extern int instead_init(void);
+extern int instead_load(char *game);
+extern void instead_done(void);
+extern char *instead_cmd(char *s);
+extern char *instead_eval(char *s);
+
+#endif
diff --git a/src/sdl-instead/main.c b/src/sdl-instead/main.c
new file mode 100644
index 0000000..9b29b41
--- /dev/null
+++ b/src/sdl-instead/main.c
@@ -0,0 +1,20 @@
+#include
+#include "graphics.h"
+#include "game.h"
+#include
+#include
+
+int main(int argc, char **argv)
+{
+ if (games_lookup()) {
+ fprintf(stderr, "No games found.\n");
+ // exit(1);
+ }
+
+ if (game_init(NULL)) {
+ exit(1);
+ }
+ game_loop();
+ game_done();
+ return 0;
+}
diff --git a/src/sdl-instead/sound.c b/src/sdl-instead/sound.c
new file mode 100644
index 0000000..ec10ad1
--- /dev/null
+++ b/src/sdl-instead/sound.c
@@ -0,0 +1,133 @@
+#include "sound.h"
+#include
+#include
+
+#include
+#include
+
+Mix_Music *music = NULL;
+
+int audio_rate = 22050;
+Uint16 audio_format = MIX_DEFAULT_FORMAT;
+int audio_channels = 2;
+int audio_buffers = 8192;
+
+static Mix_Music *mus;
+static char *next_mus = NULL;
+static int next_fadein = 0;
+static SDL_TimerID timer_id = NULL;
+
+static Uint32 callback(Uint32 interval, void *aux)
+{
+ if (!snd_playing_mus()) {
+ if (mus)
+ snd_free_mus(mus);
+ mus = NULL;
+ if (next_mus) {
+ snd_play_mus(next_mus, next_fadein);
+ free(next_mus);
+ next_mus = NULL;
+ }
+ timer_id = NULL;
+ return 0;
+ }
+ return interval;
+}
+
+int snd_hz(void)
+{
+ int freq = 0;
+ Mix_QuerySpec(&freq, NULL, NULL);
+ return freq;
+}
+
+int snd_init(int hz)
+{
+ if (!hz)
+ hz = audio_rate;
+ else
+ audio_rate = hz;
+ if (Mix_OpenAudio(hz, audio_format, audio_channels, audio_buffers)) {
+ fprintf(stderr, "Unable to open audio!\n");
+ return -1;
+ }
+ return 0;
+}
+
+int snd_volume_mus(int vol)
+{
+ Mix_Volume(-1, vol);
+ return Mix_VolumeMusic(vol);
+}
+
+Mix_Music *snd_load_mus(const char *fname)
+{
+ Mix_Music *mus;
+ mus = Mix_LoadMUS(fname);
+ return mus;
+}
+
+
+int snd_play_mus(char *fname, int ms)
+{
+ if (snd_playing_mus()) {
+ if (next_mus) {
+ free(next_mus);
+ }
+ next_mus = strdup(fname);
+ next_fadein = ms;
+ if (!timer_id)
+ timer_id = SDL_AddTimer(200, callback, NULL);
+ return 1;
+ }
+ if (mus)
+ snd_free_mus(mus);
+
+ mus = snd_load_mus(fname);
+ if (!mus)
+ return 0;
+
+ if (ms)
+ Mix_FadeInMusic((Mix_Music*)mus, -1, ms);
+ else
+ Mix_PlayMusic((Mix_Music*)mus, -1);
+ snd_volume_mus(snd_volume_mus(-1)); // hack?
+ return 0;
+}
+
+void snd_stop_mus(int ms)
+{
+ if (ms)
+ Mix_FadeOutMusic(ms);
+ else
+ Mix_HaltMusic();
+}
+
+int snd_playing_mus(void)
+{
+ if (Mix_PlayingMusic() | Mix_FadingMusic())
+ return 1;
+ return 0;
+}
+
+void snd_free_mus(mus_t mus)
+{
+ Mix_HaltMusic();
+ Mix_FreeMusic((Mix_Music*) mus);
+}
+
+void snd_done(void)
+{
+ Mix_HaltMusic();
+ if (timer_id)
+ SDL_RemoveTimer(timer_id);
+ timer_id = NULL;
+ if (mus)
+ Mix_FreeMusic((Mix_Music*) mus);
+ mus = NULL;
+ if (next_mus)
+ free(next_mus);
+ next_mus = NULL;
+ Mix_CloseAudio();
+}
+
diff --git a/src/sdl-instead/sound.h b/src/sdl-instead/sound.h
new file mode 100644
index 0000000..c005f76
--- /dev/null
+++ b/src/sdl-instead/sound.h
@@ -0,0 +1,21 @@
+#ifndef __SOUND_H__
+#define __SOUND_H__
+
+#define SND_CLICK 0
+#define SND_BONUS 1
+#define SND_HISCORE 2
+#define SND_GAMEOVER 3
+#define SND_BOOM 4
+#define SND_FADEOUT 5
+#define SND_PAINT 6
+typedef void* mus_t;
+//extern mus_t snd_load_mus(const char *path);
+extern void snd_free_mus(mus_t mus);
+extern int snd_init(int hz);
+extern int snd_hz(void);
+extern int snd_play_mus(char *music, int ms);
+extern int snd_playing_mus();
+extern void snd_stop_mus(int ms);
+extern int snd_volume_mus(int vol);
+extern void snd_done(void);
+#endif
diff --git a/stead/COPYING b/stead/COPYING
new file mode 100644
index 0000000..d60c31a
--- /dev/null
+++ b/stead/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ , 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/stead/Makefile b/stead/Makefile
new file mode 100644
index 0000000..300234d
--- /dev/null
+++ b/stead/Makefile
@@ -0,0 +1,8 @@
+include ../Rules.make
+clean:
+all: stead.lua
+
+install:
+ install -m 0755 -d $(STEADPATH)
+ install -m 0644 stead.lua $(STEADPATH)/stead.lua
+
diff --git a/stead/stead.lua b/stead/stead.lua
new file mode 100644
index 0000000..a1a4b0e
--- /dev/null
+++ b/stead/stead.lua
@@ -0,0 +1,1434 @@
+-- brake strings by space
+function par(space,...)
+ local i, res
+ for i = 1, table.maxn(arg) do
+ if type(arg[i]) == 'string' then
+ if res == nil then
+ res = ""
+ else
+ res = res..space;
+ end
+ res = res..arg[i];
+ end
+ end
+ return res;
+end
+
+-- add to not nill string any string
+function cat(v,...)
+ local i, res
+ if not v then
+ return nil
+ end
+ res = v;
+ for i = 1, table.maxn(arg) do
+ if type(arg[i]) == 'string' then
+ res = res..arg[i];
+ end
+ end
+ return res;
+end
+
+
+function p(...)
+ io.write(fmt(unpack(arg)))
+end
+
+
+function fmt(...)
+ local i, res
+ if arg == nil then
+ return false
+ end
+ for i=1,table.maxn(arg) do
+ if type(arg[i]) == 'string' then
+ local s = string.gsub(arg[i],'[\t ]+',' ');
+ s = string.gsub(s, '[\n]+', ' ');
+ s = string.gsub(s,'%^','\n');
+ res = par('',res,s);
+ end
+ end
+ return res
+end
+
+function isPlayer(v)
+ if type(v) ~= 'table' then
+ return false
+ end
+ if v.player_type then
+ return true
+ end
+ return false
+end
+
+function isRoom(v)
+ if type(v) ~= 'table' then
+ return false
+ end
+ if v.location_type then
+ return true
+ end
+ return false
+end
+
+function isPhrase(v)
+ if type(v) ~= 'table' then
+ return false
+ end
+ if v.phrase_type then
+ return true
+ end
+ return false
+end
+
+function isDialog(v)
+ if type(v) ~= 'table' then
+ return false
+ end
+ if v.dialog_type then
+ return true
+ end
+ return false
+end
+
+function isDisabled(v)
+ if type(v) ~= 'table' then
+ return false
+ end
+ if v._disabled then
+ return true
+ end
+ return false
+end
+
+function isRemoved(v)
+ if type(v) ~= 'table' then
+ return false
+ end
+ if v._disabled == -1 then
+ return true
+ end
+ return false
+end
+
+function isObject(v)
+ if type(v) ~= 'table' then
+ return false
+ end
+ if v.object_type then
+ return true
+ end
+ return false
+end
+
+function obj_xref(self,str)
+ function xrefrep(str)
+ local s = string.gsub(str,'[{}]','');
+ return iface:xref(s, self);
+ end
+ if not str then
+ return
+ end
+ if not isObject(self) then
+ return str;
+ end
+ local s = string.gsub(str,'{[^}]+}',xrefrep);
+ return s;
+end
+
+function obj_look(self)
+ local i, vv
+ local v = call(self,'dsc');
+ if isDisabled(self) then
+ return
+ end
+ if game.hinting then
+ v = obj_xref(self, v);
+ elseif v then
+ v = string.gsub(v, '[{}]','');
+ end
+ for i=1, table.maxn(self.obj) do
+ local o = ref(self.obj[i]);
+ vv = obj_look(o);
+ v = par(' ',v, vv);
+ end
+ return v;
+-- iface:xref(v,self.nam);
+end
+
+
+function obj_remove(self)
+ self._disabled = -1;
+end
+
+function obj_disable(self)
+ self._disabled = true;
+end
+
+function obj_enable(self)
+-- if self._disabled == nil then
+-- return
+-- end
+ self._disabled = false;
+end
+
+function obj_save(self, name, h, need)
+ local dsc;
+ if need then
+ h:write(name.." = obj {nam = '"..tostring(self.nam).."'}\n");
+ end
+ savemembers(h, self, name, need);
+end
+
+function obj_str(self)
+ local i, v, vv;
+ if not isObject(self) then
+ return
+ end
+ if isDisabled(self) then
+ return
+ end
+ for i = 1,table.maxn(self.obj) do
+ local o = ref(self.obj[i]);
+ if not isDisabled(o) and isObject(o) then
+ vv = call(o, 'nam');
+ vv = iface:xref(vv, o);
+-- vv = cat(vv,'(',tostring(ref(self[i]).id),')');
+ v = par(',', v, vv, obj_str(o));
+-- obj_str(o);
+ end
+ end
+ return v;
+end
+
+function obj(v)
+ if v.nam == nil then
+ error "No object name in constructor.";
+ end
+ if v.look == nil then
+ v.look = obj_look;
+ end
+ v.object_type = true;
+ if v.enable == nil then
+ v.enable = obj_enable;
+ end
+ if v.disable == nil then
+ v.disable = obj_disable;
+ end
+ if v.remove == nil then
+ v.remove = obj_remove;
+ end
+ if v.obj == nil then
+ v.obj = {};
+ end
+ if v.srch == nil then
+ v.srch = obj_search;
+ end
+ if v.str == nil then
+ v.str = obj_str;
+ end
+ v.obj = list(v.obj);
+ if v.save == nil then
+ v.save = obj_save;
+ end
+ return v
+end
+
+function ref(n) -- ref object by name
+ if type(n) == 'string' then
+ local f = loadstring('return '..n);
+ if f then
+ return f();
+ end
+ return nil;
+ end
+ if type(n) == 'table' then
+ return n;
+ end
+ if type(n) == 'function' then
+ return ref(n());
+ end
+ -- error "Ref to unknown object."
+ return nil
+end
+
+function list_check(self)
+ local i;
+ for i = 1,table.maxn(self) do
+ local o = ref(self[i]);
+ if not o then
+ return false
+ end
+ if not isObject(o) then
+ return false
+ end
+ end
+ return true;
+end
+
+function list_str(self)
+ local i, v, vv;
+ for i = 1,table.maxn(self) do
+ local o = ref(self[i]);
+ if not isDisabled(o) then
+ vv = call(o, 'nam');
+ vv = iface:xref(vv, o);
+-- vv = cat(vv,'(',tostring(ref(self[i]).id),')');
+ v = par(',', v, vv);
+ end
+ end
+ return v;
+end
+
+
+function list_add(self, name)
+-- if type(name) ~= 'string' then
+-- error "No string adding to list."
+-- end
+ if list_find(self, name) then
+ return nil
+ end
+ self.__modifyed__ = true
+ table.insert(self, name);
+ return true
+end
+
+function list_find(self, name)
+ local n
+-- if type(name) ~= 'string' then
+-- error "No string finding in list."
+-- end
+ for n=1,table.maxn(self) do
+ if ref(self[n]) == ref(name) then
+ return n;
+ end
+ end
+ return nil
+end
+
+function list_save(self, name, h, need)
+ local k,v;
+ if self.__modifyed__ then
+ h:write(name.." = list({});\n");
+ need = true;
+ end
+ savemembers(h, self, name, need);
+end
+
+function list_name(self, name)
+ local n
+-- if type(name) ~= 'string' then
+-- error "No string finding in list."
+-- end
+ for n=1,table.maxn(self) do
+ local o = ref(self[n]);
+ local nam = call(o,'nam') ;
+ if not isDisabled(o) and name == tostring(nam) then
+ return n;
+ end
+ end
+ return nil
+end
+function list_id(self, id)
+ local n
+ for n=1,table.maxn(self) do
+ local o = ref(self[n]);
+ if not isDisabled(o) and id == o.id then
+ return n;
+ end
+ end
+end
+
+function list_search(self, n)
+ local i;
+ i = list_find(self, n);
+ if not i then
+ i = list_name(self, n);
+ end
+ if not i and tonumber(n) then
+ i = list_id(self, tonumber(n));
+ if not i then
+ return nil
+ end
+ end
+ if isDisabled(self[i]) then
+ return nil;
+ end
+ return self[i], i;
+end
+
+function list_del(self, name)
+ local v,n
+ v, n = list_search(self, name);
+ if n == nil then
+ return nil;
+ end
+ self.__modifyed__ = true
+ return table.remove(self, n);
+end
+
+function list(v)
+ v.add = list_add;
+ v.del = list_del;
+ v.look = list_find;
+ v.name = list_name;
+ v.byid = list_id;
+ v.srch = list_search;
+ v.str = list_str;
+ v.check = list_check;
+ v.save = list_save;
+ return v;
+end
+
+function call(v, n, ...)
+ if type(v) ~= 'table' then
+ error ("Call on non table object:"..n);
+ end
+ if v[n] == nil then
+ return nil,nil;
+ end
+ if type(v[n]) == 'string' then
+ return v[n],true;
+ end
+ if type(v[n]) == 'function' then
+ return v[n](v, unpack(arg));
+ end
+ error ("Method not string nor function:"..tostring(n));
+end
+
+function room_scene(self)
+ local v;
+ v = iface:title(call(self,'nam'));
+ v = par('^^', v, call(self,'dsc')); --obj_look(self));
+ return cat(v,' ');
+end
+
+function room_look(self)
+ local i, vv;
+ for i = 1,table.maxn(self.obj) do
+ local o = ref(self.obj[i]);
+ vv = par(' ',vv, obj_look(o));
+ end
+ return cat(vv,' ');
+end
+
+function obj_search(v, n)
+ local i;
+ local o;
+ if isDisabled(v) then
+ return
+ end
+ o = v.obj:srch(n);
+ if o then
+ return o, v;
+ end
+ for i=1, table.maxn(v.obj) do
+ o = ref(v.obj[i]);
+ local r,rr = obj_search(o, n);
+ if r then
+ return r, rr;
+ end
+ end
+ return;
+end
+
+function room(v) --constructor
+ if v.nam == nil then
+ error "No room name in constructor.";
+ end
+ if v.scene == nil then
+ v.scene = room_scene;
+ end
+ if v.look == nil then
+ v.look = room_look;
+ end
+ v.location_type = true;
+ if v.way == nil then
+ v.way = { };
+ end
+ v.way = list(v.way);
+ v = obj(v);
+ return v;
+end
+
+function dialog_enter(self)
+ local i
+-- self._last = nil;
+ if not dialog_rescan(self) then
+ return nil, false
+ end
+ return nil, true
+end
+
+function dialog_scene(self)
+ local i,n,v
+ v = iface:title(call(self,'nam'));
+ v = par('^^', v, call(self, 'dsc')); --obj_look(self));
+-- if self._last then
+-- v = par('^^', v, self._last);
+-- else
+-- v = par('^^', v, call(self, 'dsc'));
+-- end
+ return v;
+end
+
+function dialog_look(self)
+ local i,n,v
+ n=1
+ for i=1,table.maxn(self.obj) do
+ local ph = ref(self.obj[i]);
+ if not isDisabled(ph) then
+ if game.hinting then
+ v = par('^', v, n..' - '..iface:xref(call(ph,'dsc'),ph));
+ else
+ v = par('^', v, n..' - '..string.gsub(call(ph,'dsc'),'[{}]',''));
+ end
+ n = n + 1
+ end
+ end
+ return v;
+end
+
+function dialog_rescan(self)
+ local i,k
+ k = 1
+
+ for i=1,table.maxn(self.obj) do
+ local ph = ref(self.obj[i]);
+ if isPhrase(ph) and not isDisabled(ph) then
+ ph.nam = tostring(k);
+ k = k + 1;
+ end
+ end
+ if k == 1 then
+ return false
+ end
+ return true
+-- self._last = call(ph, 'ans');
+-- return self._last;
+end
+
+
+function dialog_phrase(self, num)
+ if not tonumber(num) then
+ return nil
+ end
+ return ref(self.obj[tonumber(num)]);
+end
+
+function ponoff(self, on, ...)
+ local i, ph
+ for i=1,table.maxn(arg) do
+ ph = dialog_phrase(self, arg[i]);
+ if ph ~= nil then
+ if not isRemoved(ph) then
+ if on then
+ ph:enable();
+ else
+ ph:disable();
+ end
+-- ph.__changed__ = true;
+ end
+ end
+ end
+end
+
+function dialog_prem(self, ...)
+ local i, ph
+ for i=1,table.maxn(arg) do
+ ph = dialog_phrase(self, arg[i]);
+ if ph ~= nil then
+ ph:remove();
+-- ph.__changed__=true
+ end
+ end
+end
+
+function dialog_pon(self,...)
+ return ponoff(self, true, unpack(arg));
+end
+
+function dialog_poff(self,...)
+ return ponoff(self, false, unpack(arg));
+end
+
+function dlg(v) --constructor
+ v.dialog_type = true;
+ if v.ini == nil then
+ v.ini = dialog_enter;
+ end
+ if v.enter == nil then
+ v.enter = dialog_enter;
+ end
+ if v.look == nil then
+ v.look = dialog_look;
+ end
+ if v.scene == nil then
+ v.scene = dialog_scene;
+ end
+ if v.pon == nil then
+ v.pon = dialog_pon;
+ end
+ if v.poff == nil then
+ v.poff = dialog_poff;
+ end
+ if v.prem == nil then
+ v.prem = dialog_prem;
+ end
+ v = room(v);
+ return v;
+end
+
+function phrase_action(self)
+ local ph = self;
+ local r = here();
+ local ret;
+ if isDisabled(ph) then
+ return nil, false
+ end
+-- here it is
+ ph:disable(); -- /* disable it!!! */
+
+ if type(ph.do_act) == 'string' then
+ local f = loadstring(ph.do_act);
+ if f ~= nil then
+ ret = f();
+ else
+ error ("Error while eval phrase action");
+ end
+ elseif type(ph.do_act) == 'function' then
+ ret = ph.do_act(self, nam);
+ end
+ r._last = call(ph, 'ans');
+ if isDialog(here()) and not dialog_rescan(here()) then
+ ret = par(' ', ret, me():back());
+ end
+ return par("^^",r._last, ret);
+-- if dialog_getn(self, 1) == nil then
+-- me():back();
+-- end
+-- self._last = call(ph, 'ans');
+-- return self._last;
+end
+
+function phrase_save(self, name, h, need)
+ savemembers(h, self, name, need);
+end
+
+function phrase(o) --constructor
+ local ret = o;
+-- if not tonumber(num) then
+-- error "phrase not numbered.";
+-- end
+ ret.nam = ''; -- for start
+-- ret.key = tostring(num);
+ ret.phrase_type = true;
+ ret.act = phrase_action;
+ ret.save = phrase_save;
+ ret = obj(ret);
+ return ret;
+end
+
+function _phr(ask, answ, act)
+ local p = phrase ( { dsc = ask, ans = answ, do_act = act });
+ p:disable();
+ return p;
+end
+
+function phr(ask, answ, act)
+ local p = phrase ( { dsc = ask, ans = answ, do_act = act });
+ p:enable();
+ return p;
+end
+
+function player_inv(self)
+ return iface:inv(cat(self.obj:str()));
+end
+
+function player_ways(self)
+ return iface:ways(cat(ref(self.where).way:str()));
+end
+
+function player_objs(self)
+ return iface:objs(cat(ref(self.where):str()));
+end
+
+function player_look(self)
+ --return par('',ref(self.where):scene(), ref(self.where):look());
+ return ref(self.where):scene();
+end
+
+function obj_tag(self, id)
+ local k,v
+
+ if isDisabled(self) then
+ return id
+ end
+
+ for k,v in ipairs(self.obj) do
+ if ref(v) and not isDisabled(ref(v)) then
+ id = id + 1;
+ ref(v).id = id;
+ id = obj_tag(ref(v), id);
+ end
+ end
+ return id;
+end
+
+function player_tagall(self)
+ local id = 0;
+ local k, v;
+
+ id = obj_tag(here(), id);
+
+ for k,v in ipairs(inv()) do
+ if ref(v) and not isDisabled(ref(v)) then
+ id = id + 1;
+ ref(v).id = id;
+ end
+ end
+ for k,v in ipairs(ways()) do
+ if isRoom(ref(v)) then
+ id = id + 1;
+ ref(v).id = id;
+ end
+ end
+end
+
+--function player_do(self, what, ...)
+-- local v,r = call(ref(self.where),'act', what, unpack(arg));
+-- if v == nil then
+-- return nil, false
+-- end
+-- return v;
+--end
+
+function player_action(self, what, ...)
+ local v,r,obj
+ obj = ref(self.where):srch(what);
+ if not obj then
+ return nil; --player_do(self, what, unpack(arg));
+ end
+ v, r = player_take(self, what);
+ if not v then
+ v, r = call(ref(obj), 'act', unpack(arg));
+ if not v then
+ v, r = call(ref(game), 'act', obj, unpack(arg));
+ end
+ end
+ return v;
+end
+
+function player_take(self, what)
+ local v,r,obj,w
+ obj,w = ref(self.where):srch(what);
+ if not obj then
+ return nil, false;
+ end
+ v,r = call(ref(obj), 'tak');
+ if v and r ~= false then
+ ref(w).obj:del(obj);
+ self.obj:add(obj);
+ ref(obj)._taken = true
+ end
+ return v;
+-- return cat(v,'^^');
+end
+
+function player_use(self, what, onwhat)
+ local obj, obj2, v, vv, r;
+ obj = self.obj:srch(what);
+ if not obj then
+ return nil, false;
+ end
+ if onwhat == nil then
+ v, r = call(ref(obj),'inv');
+ if not v then
+ v, r = call(game, 'inv', obj);
+ end
+ return cat(v, ' '), r;
+ end
+ obj2 = ref(self.where):srch(onwhat);
+ if not obj2 then
+ obj2 = self.obj:srch(onwhat);
+ end
+ if not obj2 or obj2 == obj then
+ return nil, false;
+ end
+ v, r = call(ref(obj), 'use', obj2);
+ if r ~= false then
+ vv = call(ref(obj2), 'used', obj);
+ end
+ if not v and not vv then
+ v, r = call(game, 'use', obj, obj2);
+ end
+ return cat(par(' ', v, vv),' ');
+end
+
+function player_back(self)
+ local where = ref(self.where);
+ if where == nil then
+ return nil,false
+ end
+ return go(self, where.__from__, true);
+end
+
+function go(self, where, back)
+ local need_scene = false;
+ if where == nil then
+ return nil,false
+ end
+ if not isRoom(ref(where)) then
+ error ("Trying to go nowhere."..where);
+ end
+ if not isRoom(ref(self.where)) then
+ error "Trying to go from nowhere."
+ end
+ local v, r;
+-- if not isDialog(ref(self.where)) then
+ v,r = call(ref(self.where), 'exit', where);
+ if r == false then
+ return v
+ end
+-- end
+ local res = v;
+ v = nil;
+ if not back or not isDialog(ref(self.where)) or isDialog(ref(where)) then
+ v, r = call(ref(where), 'enter', self.where);
+ if r == false then
+ return v
+ end
+ need_scene = true;
+ end
+ res = par('^^',res,v);
+ if not back then
+ ref(where).__from__ = self.where;
+ end
+ if need_scene then
+ self.where = where;
+ return par('^^',res,ref(where):scene());
+ end
+ self.where = where;
+ return res;
+end
+
+
+function player_goto(self, where)
+ return go(self, where, false);
+end
+function player_go(self, where)
+ local w = ref(self.where).way:srch(where);
+ if not w then
+ return nil,false
+ end
+ return go(self, w, false);
+end
+
+function player_save(self, name, h)
+ h:write(tostring(name)..'.where = "'..self.where..'";\n');
+ savemembers(h, self, name, false);
+end
+
+function player(v)
+ if v.nam == nil then
+ error "No player name in constructor.";
+ end
+ if v.obj == nil then
+ v.obj = { };
+ end
+ if v.where == nil then
+ v.where = 'main';
+ end
+ if v.tag == nil then
+ v.tag = player_tagall;
+ end
+ if v.goto == nil then
+ v.goto = player_goto;
+ end
+ if v.go == nil then
+ v.go = player_go;
+ end
+ if v.ways == nil then
+ v.ways = player_ways;
+ end
+ if v.back == nil then
+ v.back = player_back;
+ end
+ if v.look == nil then
+ v.look = player_look;
+ end
+ if v.inv == nil then
+ v.inv = player_inv;
+ end
+ if v.use == nil then
+ v.use = player_use;
+ end
+ if v.action == nil then
+ v.action = player_action;
+ end
+ if v.save == nil then
+ v.save = player_save;
+ end
+ if v.objs == nil then
+ v.objs = player_objs;
+ end
+ v.obj = list(v.obj); -- inventory
+ v.player_type = true;
+ return v;
+end
+
+function game_life(self)
+ local i, v;
+ for i=1, table.maxn(self.lifes) do
+ if not isDisabled(ref(self.lifes[i])) then
+ v = par(' ',v,call(ref(self.lifes[i]),'life'));
+ end
+ end
+ return v;
+end
+
+function check_room(k, v)
+ if not v.nam then
+ error ("No name in "..k);
+ end
+ if v.obj == nil then
+ error("no obj in room:"..k);
+ end
+ if v.way == nil then
+ error("no way in room:"..k);
+ end
+ if not v.obj:check() then
+ error ("error in room (obj): "..k);
+ end
+ if not v.way:check() then
+ error ("error in room (way): "..k);
+ end
+end
+
+function do_ini(self)
+ local v,vv
+ local function call_ini(k, v)
+ v = call(v, 'ini');
+ v = cat(v, "^^");
+ end
+ math.randomseed(tonumber(os.date("%m%d%H%M%S")))
+ for_each_object(call_ini);
+-- for_each_room(call_ini);
+ for_each_room(check_room);
+ me():tag();
+ if not self.showlast then
+ self._lastdisp = nil;
+ end
+ return par('',v, self._lastdisp); --par('^^',v);
+end
+
+function game_ini(self)
+ local v,vv
+ v = do_ini(self);
+ vv = iface:title(call(self,'nam'));
+ vv = par('^^', vv, call(self,'dsc'));
+ return par("^^", vv, v);
+end
+
+function game(v)
+ if v.nam == nil then
+ error "No game name in constructor.";
+ end
+ if v.pl == nil then
+ v.pl = 'player';
+ end
+ if v.ini == nil then
+ v.ini = game_ini;
+ end
+ if v.save == nil then
+ v.save = game_save;
+ end
+ if v.load == nil then
+ v.load = game_load;
+ end
+ if v.life == nil then
+ v.life = game_life;
+ end
+ if v.step == nil then
+ v.step = game_step;
+ end
+ if v.lifes == nil then
+ v.lifes = {};
+ end
+ v.lifes = list(v.lifes);
+ v._time = 0;
+ v._running = true;
+ v.game_type = true;
+ return v;
+end
+
+function for_each_room(f,...)
+ local k,v
+ for k,v in pairs(_G) do
+ if isRoom(v) then
+ f(k,v, unpack(arg));
+ end
+ end
+end
+
+function for_each_object(f,...)
+ local k,v
+ for k,v in pairs(_G) do
+ if isObject(v) then
+ f(k,v, unpack(arg));
+ end
+ end
+end
+
+function for_each_player(f,...)
+ local k,v
+ for k,v in pairs(_G) do
+ if isPlayer(v) then
+ f(k,v, unpack(arg));
+ end
+ end
+end
+
+
+function clearvar (v)
+ local r,f
+ if type(v) ~= "table" then
+ return
+ end
+ v.__visited__ = nil
+ for r,f in pairs(v) do
+ clearvar(r, f)
+ end
+end
+
+function savemembers(h, self, name, need)
+ local k,v
+ for k,v in pairs(self) do
+ local need2
+ if k ~= "__visited__" then
+ need2 = false
+ if string.find(k, '_') == 1 then
+ need2 = true;
+ end
+
+ if type(k) == 'string' then
+ savevar(h, v, name.."."..k, need or need2);
+ else
+ savevar(h, v, name.."["..k.."]", need or need2)
+ end
+ end
+ end
+end
+
+function savevar (h, v, n, need)
+ local r,f
+ if v == nil or type(v)=="userdata" or
+ type(v)=="function" then
+ return
+ end
+
+ if string.find(n, '_') == 1 then
+ need = true;
+ end
+
+ if type(v) == "string" then
+ if not need then
+ return
+ end
+ h:write(string.format("%s=%q\n",n,v))
+ return;
+ end
+
+ if type(v) == "table" then
+ if v.__visited__ ~= nil then
+ return
+ end
+ if type(v.save) == 'function' then
+ v:save(n, h, need);
+ return;
+ end
+ v.__visited__ = n;
+
+ if need then
+ h:write(n.." = {};\n");
+ end
+ savemembers(h, v, n, need);
+ return;
+ end
+
+ if not need then
+ return
+ end
+ h:write(n, " = ",tostring(v))
+ h:write("\n")
+end
+
+
+function save_object(key, value, h)
+ savevar(h, value, key, false);
+ return true;
+end
+
+function game_save(self, name, file)
+ local h;
+ if file ~= nil then
+ file:write(name..".pl = '"..self.pl.."'\n");
+ savemembers(file, self, name, false);
+ return nil, true
+ end
+ if name == nil then
+ return nil, false
+ end
+ h = io.open(name,"w");
+ if not h then
+ return nil, false
+ end
+-- for_each_room(save_object, h);
+ for_each_object(save_object, h);
+ for_each_player(save_object, h);
+ save_object('game', self, h);
+ h:flush();
+ h:close();
+ return nil;
+end
+
+function game_load(self, name)
+ if name == nil then
+ return nil, false
+ end
+ local f, err = loadfile(name);
+ if f then
+ local i,r = f();
+ if r then
+ return nil, false
+ end
+ return do_ini(self);
+ end
+ return nil, false
+end
+
+function game_life(self)
+ local i,v
+ for i=1,table.maxn(self.lifes) do
+ vv = call(ref(self.lifes[i]),'life');
+ v = par(' ',v, vv);
+ end
+ return v;
+end
+
+function game_step(self)
+ self._time = self._time + 1;
+ return game_life(self);
+end
+
+version = "0.4.3";
+
+game = game {
+ nam = "INSTEAD -- Simple Text Adventure interpreter v"..version.." '2008 by Peter Kosyh",
+ dsc = [[
+Commands:^
+ look(or just enter), act (or just what), use [on what], go ,^
+ back, inv, way, obj, quit, save , load .]],
+ pl ='pl',
+ showlast = true,
+};
+function strip(s)
+ local s = tostring(s);
+ s = string.gsub(s, '^[ \t]*', '');
+ s = string.gsub(s, '[ \t]*$', '');
+ return s;
+end
+iface = {
+ xref = function(self, str, obj)
+-- return "@"..str.."{"..obj.."}";
+ local o = ref(here():srch(obj));
+ if not o then
+ o = ref(ways():srch(obj));
+ end
+ if not o then
+ o = ref(inv():srch(obj));
+ end
+ if not o or not o.id then
+ return str;
+-- error ("Xref to nowhere:"..str);
+ end
+ return cat(str,"("..tostring(o.id)..")");
+-- return str;
+ end,
+ title = function(self, str)
+ return "["..str.."]";
+ end,
+ objs = function(self, str)
+ return str;
+ end,
+ ways = function(self, str)
+ return str;
+ end,
+ inv = function(self, str)
+ return str;
+ end,
+ text = function(self, str)
+ if str then
+ print(str);
+ end
+ end,
+ cmd = function(self, inp)
+ local r, v, vv, i, k , cmd, n;
+ local scene = false;
+ local st = false;
+ i,k = string.find(inp,'[a-zA-Z0-9_]+', k);
+ if not i or not k then
+ cmd = inp
+ else
+ cmd = string.sub(inp, i, k);
+ end
+ a = { };
+ n = 1;
+ while i do
+ k = k + 1;
+ i,k = string.find(inp,'[^,]+', k);
+ if not i then
+ break
+ end
+ a[n] = strip(string.sub(inp, i, k));
+ n = n + 1;
+ end
+ v = false
+-- me():tag();
+ if cmd == 'look' or cmd == '' then
+ r,v = me():look();
+ st = true;
+ elseif cmd == 'obj' then
+ r,v = me():objs();
+ elseif cmd == 'inv' then
+ r,v = me():inv();
+ elseif cmd == 'way' then
+ r,v = me():ways();
+ elseif cmd == 'ls' then
+ r = par('^^', me():objs(), me():inv(), me():ways());
+ v = nil;
+ elseif cmd == 'go' then
+ r,v = me():go(unpack(a));
+ st = true;
+ elseif cmd == 'back' then
+ r,v = me():go(from());
+ st = true;
+ elseif cmd == 'act' then
+ r,v = me():action(unpack(a));
+ st = true;
+ elseif cmd == 'use' then
+ r,v = me():use(unpack(a));
+ st = true;
+ elseif cmd == 'save' then
+ r, v = game:save(unpack(a));
+ elseif cmd == 'load' then
+ r, v = game:load(unpack(a));
+ if v ~= false and game.showlast then
+ return r;
+ end
+ else
+ r,v = me():action(strip(inp));
+ st = true;
+ end
+-- self:text(r);
+ if st and v ~= false then
+ me():tag();
+ vv = par(" ",vv, game:step());
+ vv = par("^^",here():look(), vv);
+ end
+ if v == false then
+ return fmt(par("^^", vv, "Error.^"));
+ end
+ vv = fmt(cat(par("^^",r,vv),'^'));
+ if st then
+ game._lastdisp = vv
+ end
+ return vv;
+ end,
+ shell = function(self)
+ local inp, i, k, cmd, a, n;
+ me():tag();
+ while game._running do
+ inp = io.read("*l");
+ if inp == 'quit' then
+ break;
+ end
+ self:text(self:cmd(inp));
+ end
+ end
+};
+
+pl = player {
+ nam = "Incognito",
+ where = 'main',
+ obj = { }
+};
+
+function me()
+ return ref(game.pl);
+end
+
+function here()
+ return ref(me().where);
+end
+
+function from()
+ return ref(ref(me().where).__from__);
+end
+
+function time()
+ return game._time;
+end
+
+function inv()
+ return me().obj;
+end
+
+function objs()
+ return here().obj;
+end
+
+function ways()
+ return here().way;
+end
+
+function xref(str, obj)
+ return iface:xref(str, obj);
+end
+function pon(...)
+ if not isDialog(here()) then
+ return
+ end
+ dialog_pon(here(), unpack(arg));
+end
+function poff(...)
+ if not isDialog(here()) then
+ return
+ end
+ dialog_poff(here(), unpack(arg));
+end
+function prem(...)
+ if not isDialog(here()) then
+ return
+ end
+ dialog_prem(here(), unpack(arg));
+end
+
+function lifeon(what)
+ game.lifes:add(what);
+end
+
+function lifeoff(what)
+ game.lifes:del(what);
+end
+
+function vobj_save(self, name, h, need)
+ local dsc;
+ if type(self.dsc) ~= 'string' then
+ dsc = 'nil';
+ else
+ dsc = "[["..self.dsc.."]]";
+ end
+ if need then
+ h:write(name.." = vobj("..tostring(self.key)..",[["..self.nam.."]],"..dsc..");\n");
+ end
+ savemembers(h, self, name,false);
+end
+
+function vobj_act(self, ...)
+ local o, r = here():srch(self.nam);
+ return call(ref(r),'act', self.key, unpack(arg));
+end
+
+function vobj_used(self, ...)
+ local o, r = here():srch(self.nam);
+ return call(ref(r),'used', self.key, unpack(arg));
+end
+
+function vobj(key, name, dsc)
+ local o = { key = key, nam = name, dsc = dsc, act = vobj_act, used = vobj_used, save = vobj_save, obj = list({}), };
+ if not tonumber(key) then
+ error ("vobj key must be number!");
+ end
+-- o.object_type = true;
+ o = obj(o);
+ return o;
+end
+function goto(what)
+ local v=me():goto(what);
+ me():tag();
+ return v;
+end
+function back()
+ return me():back();
+end
+function rnd(m)
+ return math.random(m);
+end
+
+function taken(obj)
+ if isObject(ref(obj)) and ref(obj)._taken then
+ return true
+ end
+ return false;
+end
+
+function take(obj)
+ local o,w = here():srch(obj);
+ if w then
+ ref(w).obj:del(obj);
+ end
+ me().obj:add(obj);
+ ref(obj)._taken = true
+end
+
+function drop(obj)
+ me().obj:del(obj);
+ here().obj:add(obj);
+ ref(obj)._taken = false
+end
+
+function seen(obj)
+ if here().obj:srch(obj) then
+ return true
+ end
+ return false
+end
+
+function have(obj)
+ if me().obj:srch(obj) then
+ return true
+ end
+ return false
+end
+
+function move(obj, there)
+ local o,w = here():srch(obj);
+ if w then
+ ref(w).obj:del(obj);
+ end
+-- if not isRoom(ref(there)) then
+-- error ("move error");
+-- end
+ ref(there).obj:add(obj);
+end
+
+function get_picture()
+ local s = call(here(),'pic');
+ return s;
+end
+
+function get_title()
+ local s = call(here(),'nam');
+ return s;
+end
+function get_music()
+ return game._music;
+end
+
+function set_music(s)
+ game._music = s;
+end
+
+-- here the game begins
+
diff --git a/themes/Makefile b/themes/Makefile
new file mode 100644
index 0000000..e055de5
--- /dev/null
+++ b/themes/Makefile
@@ -0,0 +1,11 @@
+include ../Rules.make
+clean:
+all:
+install:
+ install -d -m0755 $(THEMESPATH)
+ for f in *; do \
+ if [ ! -d $$f ]; then continue; fi;\
+ install -d -m0755 $(THEMESPATH)/$$f;\
+ tar -c -C $$f . | tar -x -C $(THEMESPATH)/$$f;\
+ done
+
diff --git a/themes/default/adown.png b/themes/default/adown.png
new file mode 100644
index 0000000..7f3a5b7
Binary files /dev/null and b/themes/default/adown.png differ
diff --git a/themes/default/aup.png b/themes/default/aup.png
new file mode 100644
index 0000000..2570087
Binary files /dev/null and b/themes/default/aup.png differ
diff --git a/themes/default/bg.png b/themes/default/bg.png
new file mode 100644
index 0000000..b129721
Binary files /dev/null and b/themes/default/bg.png differ
diff --git a/themes/default/menu.png b/themes/default/menu.png
new file mode 100644
index 0000000..8f35ac1
Binary files /dev/null and b/themes/default/menu.png differ
diff --git a/themes/default/sans.ttf b/themes/default/sans.ttf
new file mode 100644
index 0000000..7ff88f2
Binary files /dev/null and b/themes/default/sans.ttf differ
diff --git a/themes/default/theme.ini b/themes/default/theme.ini
new file mode 100644
index 0000000..ba0e726
--- /dev/null
+++ b/themes/default/theme.ini
@@ -0,0 +1,44 @@
+scr.w = 800
+scr.h = 480
+scr.gfx.bg = bg.png
+scr.col.bg = white
+scr.gfx.use = use.png
+scr.gfx.pad = 16
+
+win.x = 48
+win.y = 8
+win.w = 500
+win.h = 448
+win.fnt.name = sans.ttf
+win.fnt.size = 16
+win.gfx.h = 200
+win.gfx.up = aup.png
+win.gfx.down = adown.png
+win.col.fg = #000000
+win.col.link = #0000FF
+win.col.alink = #FF0000
+
+inv.x = 620
+inv.y = 8
+inv.w = 132
+inv.h = 448
+inv.fnt.name = sans.ttf
+inv.fnt.size = 16
+inv.gfx.up = aup.png
+inv.gfx.down = adown.png
+inv.col.fg = #FFFFFF
+inv.col.link = #CCCCCC
+inv.col.alink = goldenrod
+
+menu.col.bg = #FFFFFF
+menu.col.fg = #000000
+menu.col.link = #0000FF
+menu.col.alink = #FF0000
+menu.col.alpha = 180
+menu.col.border = #000000
+menu.bw = 1
+menu.fnt.name = sans.ttf
+menu.fnt.size = 15
+menu.gfx.button = menu.png
+menu.buttonx = 776
+menu.buttony = 456
diff --git a/themes/default/use.png b/themes/default/use.png
new file mode 100644
index 0000000..fb6b6b4
Binary files /dev/null and b/themes/default/use.png differ