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 игры:

+ +

На данный момент автором 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