--[[ Общие утилиты для игр на Instead. Скорее всего будут повторно использоваться в следующих играх, если таковые будут. ]] --[[ ]] ArrayUtils = { indexOf = function(array, item) for i = 1, #array do if (array[i] == item) then return i; end; end; return 0; end; }; --[[ ]] PartyUtils = { addToParty = function(object) if (object.home) then if (ArrayUtils.indexOf(pl.party, object.nam) == 0) then move(object, object.home); table.insert(pl.party, object.nam); end; end; end; }; --[[ functions, design to simplify some typical actions while developing Instead game ]] EngineUtils = { getStringValue = function(source, param) local value = ""; if (type(source) == "function") then value = source(param); else value = source; end; return value; end; getValue = function(source, param) local value = nil; if (type(source) == "function") then value = source(param); else value = source; end; return value; end; }; --[[ internal space ]] _kh = { vroom_enter = function(s) local v = EngineUtils.getValue(s.where); if (v) then walk(v); else return false; end; end; vroom_save = function(s) if need then local t = stead.string.format("%s = kh_vroom(%s, %q, %s);\n", name, stead.tostring(self.disp), stead.deref(self.where), stead.deref(self.nam)); h:write(t); end stead.savemembers(h, self, name,false); end; }; function kh_vobj(nam, dsc, act, used) return obj { nam = nam; dsc = dsc; act = act; used = used; }; end; function kh_vway(disp, dsc, target, seen_level) local temp = vway(disp, dsc, target); temp.seen_level = seen_level; return temp; end; --[[ vroom with additional functionality ]] function kh_vroom(disp, target, nam, seen_level) if (type(nam) == "number") then seen_level = nam; nam = disp; end; if (not nam) then nam = disp; end; return room { nam = nam; disp = disp; where = target; enter = _kh.vroom_enter; seen_level = seen_level; --enter = _kh.vroom_enter; --save = _kh.vroom_save; }; end; obj = inherit(obj, function(v) v.disable_implicit = hook(v.disable, function(f, s, ...) s._disabled_implicit = true; return f(s, unpack(arg)); end); v.disable = hook(v.disable, function(f, s, ...) s._disabled_explicit = true; return f(s, unpack(arg)); end); v.enable_implicit = hook(v.enable, function(f, s, ...) s._disabled_implicit = false; if (s._disabled_explicit) then return s; --mimic original enable() behavior else return f(s, unpack(arg)); end; end); v.enable = hook(v.enable, function(f, s, ...) s._disabled_explicit = false; if (s._disabled_implicit) then return s; --mimic original enable() behavior else return f(s, unpack(arg)); end; end); return v; end); --[[ character object represents character, with whom you can interact ]] function npc(tab) if (not tab.act) then tab.act = function(s) if (s.dlg) then walkin(s.dlg); else return s.phrases[rnd(#s.phrases)]; end; end; end; return obj(tab); end; function darkroom(tab) local life; local entered; local left; if (not tab.has_light) then tab.has_light = false; end; if (tab.life) then life = tab.life; end; if (tab.entered) then entered = tab.entered; end; if (tab.left) then left = tab.left; end; tab.entered = function(s) lifeon(s); if (entered) then entered(s); end; end; tab.left = function(s) lifeoff(s); if (left) then left(s); end; end; tab.life = function(s) if (s.has_light) then -- show all objects that were not explicitly disabled(any seen_level) for i = 1, #objs(s) do objs(s)[i]:enable_implicit(); end; for i = 1, #ways(s) do ways(s)[i]:enable_implicit(); end; elseif (pl.has_light) then -- show all objects that were not explicitly disabled and marked as seen in halflight (seen_level = 1 or higher) for i = 1, #objs(s) do if (type(objs(s)[i].seen_level) == "number" and objs(s)[i].seen_level >= 1) then objs(s)[i]:enable_implicit(); else objs(s)[i]:disable_implicit(); end; end; for i = 1, #ways(s) do if (type(ways(s)[i].seen_level) == "number" and ways(s)[i].seen_level >= 1) then ways(s)[i]:enable_implicit(); else ways(s)[i]:disable_implicit(); end; end; else -- show all objects that were not explicitly disabled and marked as seen in darkness (seen_level = 2 or higher) for i = 1, #objs(s) do if (type(objs(s)[i].seen_level) == "number" and objs(s)[i].seen_level >= 2) then objs(s)[i]:enable_implicit(); else objs(s)[i]:disable_implicit(); end; end; for i = 1, #ways(s) do if (type(ways(s)[i].seen_level) == "number" and ways(s)[i].seen_level >= 2) then ways(s)[i]:enable_implicit(); else ways(s)[i]:disable_implicit(); end; end; end; if (life) then life(s); end; end; if (not tab.dsc) then tab.dsc = function(s) local lt; if (s.has_light) then lt = EngineUtils.getValue(s.dsc_lit); elseif (pl.has_light) then lt = EngineUtils.getValue(s.dsc_halflit); else lt = EngineUtils.getValue(s.dsc_dark); end; return lt; end; end; return room(tab); end; function game_over(nam, dsc) return room { nam = nam; disp = "Игра окончена"; hideinv = true; dsc = dsc; }; end; function cutscene(nam, disp, dsc, nxt) return room { nam = nam; disp = disp; hideinv = true; dsc = dsc; obj = { vway("continue", "{Продолжить}", nxt); }; }; end; --[[ Создает комнату с полем для ввода числа длиной не более tab.maxlen По нажатии enter вызывает метод tab.сheck Приглашение для ввода: tab.label Вводимый текст: tab.input ]] function input_number(tab) if (not tab.maxlen) then tab.maxlen = 2; end; tab.forcedsc = true; tab.noinv = true; tab.input = ""; tab.dsc = function(s) pr(tab.label .. tab.input .. "_"); return false; --return tab.label .. tab.input .. "_"; end; tab.entered = function(s) s.input = ""; hook_keys('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'backspace', 'return'); end; tab.left = function(s) unhook_keys('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'backspace', 'return'); end; tab.kbd = function(s, down, key) if (not down) then if (key == "return") then if (s.input) then s:check(s.input); end; elseif (key == "backspace") then if (s.input:len() > 0) then s.input = s.input:sub(1, s.input:len() - 1); end; else if (string.len(s.input) < s.maxlen) then s.input = s.input .. key; -- hide buttons :) end; end; end; pr(""); end; tab.obj = { -- TODO add onscreen buttons for symbian users or losers with android }; return room(tab); end; --[[ Создает obj, который добавляет другой obj на сцену при активации и становится неинтерактивным nam - имя объекта dsc_a - описание до активации dsc_b - описание после активации act_a - описание взаимодействия до активации act_b - описание взаимодействия после активации o2 - obj, добавляемый на сцену r - удаляет объект после активации ]] function obscured_obj(nam, dsc_a, act_a, o2, r, dsc_b, act_b) return obj { var { activated = false; }; nam = nam; dsc = function(s) if (s.activated) then return dsc_b; else return dsc_a; end; end; act = function(s) if (s.activated) then return act_b; else s.activated = true; put(o2, here()); if (r) then remove(r, here()); end; return act_a; end; end; }; end; _atlantis_suit_menu = dlg { nam = "Скафандр"; _item = nil; dsc = [[ Что вы хотите сделать? ]]; phr = { {1, always = "true", "Использовать рацию", function(s) local val = EngineUtils.getValue(_atlantis.suit_menu._item.dlg, _atlantis.suit_menu._item); if (val) then walkin(val); stead.ref(val).__from__ = _atlantis.suit_menu.__from__; else back(); return "Никто не отвечает"; end; end}; {2, always = "true", "Снять скафандр", function(s) if (EngineUtils.getValue(_atlantis_suit_menu._item.cantakeoff, _atlantis_suit_menu._item)) then drop(_atlantis._uit_menu._item); back(); return "Вы снимаете скафандр"; else back(); return "Вы не можете снять скафандр сейчас"; end; end}; {3, always = "true", "Отмена", function(s) back(); return ""; end}; }; }; _atlantis = { suit_inv = function(s) _atlantis_suit_menu._item = s; walkin(_atlantis_suit_menu); end; }; suit = function(tab) if (not tab.inv) then tab.inv = _atlantis.suit_inv; end; return obj(tab); end; labyrinth = function(tab) local enter = tab.enter; local exit = tab.exit; local dsc = tab.dsc; local lab; tab.enter = function(s) path('e1'):disable(); path('e2'):disable(); path('e3'):disable(); path('e4'):disable(); path('ex'):disable(); local e1open = s.map[s.position].e1 and not EngineUtils.getValue(s.map[s.position].e1lock, s); local e2open = s.map[s.position].e2 and not EngineUtils.getValue(s.map[s.position].e2lock, s); local e3open = s.map[s.position].e3 and not EngineUtils.getValue(s.map[s.position].e3lock, s); local e4open = s.map[s.position].e4 and not EngineUtils.getValue(s.map[s.position].e4lock, s); local exopen = s.map[s.position].ex and not EngineUtils.getValue(s.map[s.position].exlock, s); if (e1open) then path('e1'):enable(); end; if (e2open) then path('e2'):enable(); end; if (e3open) then path('e3'):enable(); end; if (e4open) then path('e4'):enable(); end; if (exopen) then path('ex'):enable(); end; if (type(enter) == 'function') then enter(s); end; if (type(s.map[s.position].enter) == 'function') then s.map[s.position].enter(s); end; end; tab.exit = function(s) if (type(exit) == 'function') then exit(s); end; if (type(s.map[s.position].exit) == 'function') then s.map[s.position].exit(s); end; end; tab.dsc = function(s) if (type(dsc) == "function") then return dsc(s); else return dsc .. s.map[s.position].name; end; end; tab.way = { kh_vroom(tab.dir1, function() lab.oldposition = lab.position; lab.position = lab.map[lab.position].e1; return lab; end, "e1"); kh_vroom(tab.dir2, function() lab.oldposition = lab.position; lab.position = lab.map[lab.position].e2; return lab; end, "e2"); kh_vroom(tab.dir3, function() lab.oldposition = lab.position; lab.position = lab.map[lab.position].e3; return lab; end, "e3"); kh_vroom(tab.dir4, function() lab.oldposition = lab.position; lab.position = lab.map[lab.position].e4; return lab; end, "e4"); kh_vroom(tab.ex, function() return lab.map[lab.position].ex; end, "ex"); kh_vroom("Ждать", function() lab.oldposition = lab.position; return lab; end, "wt"); }; lab = room(tab); print(tab); print(lab); if (not tab.position) then stead.add_var(tab, { position = "00"; }); end; stead.add_var(tab, { oldposition = tab.position; }); return lab; end;