From 65fd023bc06f46f9cd0ff87a77fe20d6163c9993 Mon Sep 17 00:00:00 2001
From: "p.kosyh"
Date: Sun, 6 Jun 2010 17:53:42 +0000
Subject: [PATCH] new stead added
---
stead/stead.lua.new | 2344 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 2344 insertions(+)
create mode 100644 stead/stead.lua.new
diff --git a/stead/stead.lua.new b/stead/stead.lua.new
new file mode 100644
index 0000000..7580de1
--- /dev/null
+++ b/stead/stead.lua.new
@@ -0,0 +1,2344 @@
+stead = {
+ version = "1.2.0",
+ table = table,
+ string = string,
+ math = math,
+ io = io,
+ os = os,
+ call_top = 0,
+ cctx = { txt = nil, self = nil },
+ timer = function()
+ if type(timer) == 'table' and type(timer.callback) == 'function' then
+ return timer:callback();
+ end
+ return
+ end,
+ input = function(event, ...)
+ if type(input) ~= 'table' then
+ return
+ end
+ if event == 'kbd' then
+ if type(input.key) == 'function' then
+ return input:key(unpack(arg)); -- pressed, event
+ end
+ elseif event == 'mouse' then
+ if type(input.click) == 'function' then
+ return input:click(unpack(arg)); -- pressed, x, y, mb
+ end
+ end
+ return
+ end,
+}
+
+function stead.getcmd(str)
+ local a = {}
+ local n = 1
+ local cmd;
+ local i,k = stead.string.find(str,'[a-zA-Z0-9_]+', k);
+ if not i or not k then
+ cmd = str;
+ else
+ cmd = stead.string.sub(str, i, k);
+ end
+ stead.cmd = cmd
+ if cmd == 'load' or cmd == 'save' then
+ a[1] = strip(stead.string.sub(str, k + 1));
+ stead.args = a;
+ return cmd, a
+ end
+ while i do
+ k = k + 1;
+ i,k = stead.string.find(str,'[^,]+', k);
+ if not i then
+ break
+ end
+ a[n] = strip(stead.string.sub(str, i, k));
+ n = n + 1;
+ end
+ stead.args = a;
+ return cmd, a
+end
+
+function cctx()
+ return stead.cctx[stead.call_top];
+end
+
+function callpush(v)
+ stead.call_top = stead.call_top + 1;
+ stead.cctx[stead.call_top] = { txt = nil, self = v };
+end
+
+function callpop()
+ stead.cctx[stead.call_top] = nil;
+ stead.call_top = stead.call_top - 1;
+ if stead.call_top < 0 then
+ error "callpush/callpop mismatch"
+ end
+end
+
+function self(v)
+ if v ~= nil then
+ cctx().self = v;
+ end
+ return cctx().self;
+end
+
+function pclr()
+ cctx().txt = nil
+end
+
+function pget()
+ return cctx().txt;
+end
+
+function p(...)
+ local i
+ for i = 1, stead.table.maxn(arg) do
+ cctx().txt = par('',cctx().txt, arg[i]);
+ end
+ cctx().txt = cat(cctx().txt, ' ');
+end
+
+function pr(...)
+ local i
+ for i = 1, stead.table.maxn(arg) do
+ cctx().txt = par('',cctx().txt, arg[i]);
+ end
+end
+
+function pn(...)
+ p(unpack(arg));
+ cctx().txt = par('',cctx().txt,'^');
+end
+
+-- merge strings with "space" as separator
+function par(space,...)
+ local i, res
+ for i = 1, stead.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, stead.table.maxn(arg) do
+ if type(arg[i]) == 'string' then
+ res = res..arg[i];
+ end
+ end
+ return res;
+end
+
+function txtnb(v)
+ if type(v) ~= 'string' then return nil; end
+ return iface:nb(v);
+end
+
+function img(v)
+ if type(v) ~= 'string' then return nil; end;
+ return iface:img(v);
+end
+
+function txtem(v)
+ if type(v) ~= 'string' then return nil; end;
+ return iface:em(v)
+end
+
+function txtr(v)
+ if type(v) ~= 'string' then return nil; end;
+ return iface:right(v)
+end
+
+function txtl(v)
+ if type(v) ~= 'string' then return nil; end;
+ return iface:left(v)
+end
+
+function txtc(v)
+ if type(v) ~= 'string' then return nil; end;
+ return iface:center(v)
+end
+
+function txtb(v)
+ if type(v) ~= 'string' then return nil; end;
+ return iface:bold(v)
+end
+
+function txtu(v)
+ if type(v) ~= 'string' then return nil; end;
+ return iface:under(v)
+end
+
+function txtnm(n, v)
+ if type(v) ~= 'string' or not tonumber(n) then return nil; end
+ return iface:enum(n, v);
+end
+
+function fmt(...)
+ local i, res
+ if arg == nil then
+ return false
+ end
+ for i=1,stead.table.maxn(arg) do
+ if type(arg[i]) == 'string' then
+ local s = stead.string.gsub(arg[i],'[\t ]+',' ');
+ s = stead.string.gsub(s, '[\n]+', ' ');
+ s = stead.string.gsub(s,'%^','\n');
+ res = par('',res,s);
+ end
+ end
+ return res
+end
+-- integer lists
+function inext(t, k)
+ local v
+ k, v = next(t, k);
+ while k and not tonumber(k) do
+ k, v = next(t, k);
+ end
+ if not tonumber(k) then
+ return nil
+ end
+ return k, v
+end
+
+function ilist(s, var)
+ return inext, s, nil;
+end
+
+function ordered_i(t)
+ local ordered = {};
+ local i,v, max;
+ max = 0;
+ for i,v in ilist(t) do
+ stead.table.insert(ordered, i);
+ max = max + 1;
+ end
+ stead.table.sort(ordered);
+ ordered.i = 1;
+ ordered.max = max;
+ return ordered;
+end
+
+function onext(t, k)
+ local v
+ if not k then
+ k = ordered_i(t);
+ end
+ if k.i > k.max then
+ return nil
+ end
+ v = k[k.i]
+ k.i = k.i + 1
+ return k, t[v], v;
+end
+
+function opairs(s, var)
+ return onext, s, nil;
+end
+
+function isPlayer(v)
+ return (type(v) == 'table') and (v.player_type)
+end
+
+function isRoom(v)
+ return (type(v) == 'table') and (v.location_type)
+end
+
+function isPhrase(v)
+ return (type(v) == 'table') and (v.phrase_type)
+end
+
+function isDialog(v)
+ return (type(v) == 'table') and (v.dialog_type)
+end
+
+function isDisabled(v)
+ return (type(v) == 'table') and (v._disabled)
+end
+
+function isRemoved(v)
+ return (type(v) == 'table') and (v._disabled == -1)
+end
+
+function isObject(v)
+ return (type(v) == 'table') and (v.object_type)
+end
+
+function obj_xref(self,str)
+ function xrefrep(str)
+ local s = stead.string.gsub(str,'[{}]','');
+ return xref(s, self);
+ end
+ if not str then
+ return
+ end
+ if not isObject(self) then
+ return str;
+ end
+ local s = stead.string.gsub(str,'{[^}]+}',xrefrep);
+ return s;
+end
+
+function obj_look(self)
+ local i, vv, o
+ if isDisabled(self) then
+ return
+ end
+ local v = call(self,'dsc');
+ if game.hinting then
+ v = self:xref(v);
+ elseif v then
+ v = stead.string.gsub(v, '[{}]','');
+ end
+ for i,o in opairs(self.obj) do
+ o = ref(o);
+ if isObject(o) then
+ vv = obj_look(o);
+ v = par(' ',v, vv);
+ end
+ end
+ return v;
+end
+
+
+function obj_remove(self)
+ self._disabled = -1;
+ return self
+end
+
+function obj_disable(self)
+ self._disabled = true;
+ return self
+end
+
+function obj_enable(self)
+ self._disabled = false;
+ return self
+end
+
+function obj_enable_all(s)
+ local k,v
+ if not isObject(s) then
+ return
+ end
+ for k,v in opairs(objs(s)) do
+ local o = ref(v);
+ if isObject(o) then
+ o:enable()
+ end
+ end
+end
+
+function obj_disable_all(s)
+ local k,v
+ if not isObject(s) then
+ return
+ end
+ for k,v in opairs(objs(s)) do
+ local o = ref(v);
+ if isObject(o) then
+ o:disable()
+ end
+ end
+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, o;
+ if not isObject(self) then
+ return
+ end
+ if isDisabled(self) then
+ return
+ end
+ for i,o in opairs(self.obj) do
+ o = ref(o);
+ if o~= nil and not isDisabled(o) then -- isObject is better, but compat layer must be ok
+ vv = call(o, 'nam');
+ vv = xref(vv, o);
+ v = par(',', v, vv, obj_str(o));
+ end
+ end
+ return v;
+end
+
+function obj(v)
+ if v.nam == nil then
+ error ("No object name in constructor.");
+ end
+ v.object_type = true;
+
+ if v.xref == nil then
+ v.xref = obj_xref;
+ end
+
+ if v.look == nil then
+ v.look = obj_look;
+ end
+ if v.enable == nil then
+ v.enable = obj_enable;
+ end
+ if v.disable == nil then
+ v.disable = obj_disable;
+ end
+ if v.enable_all == nil then
+ v.enable_all = obj_enable_all;
+ end
+ if v.disable_all == nil then
+ v.disable_all = obj_disable_all;
+ 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 ref(f());
+ end
+ return nil;
+ end
+ if type(n) == 'table' then
+ return n;
+ end
+ if type(n) == 'function' then
+ return ref(n());
+ end
+ return nil
+end
+
+function deref(n)
+ if type(n) == 'string' then
+ return n
+ end
+
+ if type(n) == 'table' and type(n.key_name) == 'string' then
+ return n.key_name
+ end
+ return n
+end
+
+function list_check(self)
+ local i, v, ii;
+ for i,v,ii in opairs(self) do
+ local o = ref(v);
+ if not o then -- isObject(o) then -- compat
+ return false
+ end
+ if deref(v) then
+ self[ii] = deref(v);
+ end
+ end
+ return true;
+end
+
+function list_str(self)
+ local i, v, vv, o;
+ for i,o in opairs(self) do
+ o = ref(o);
+ if o~= nil and not isDisabled(o) then
+ vv = call(o, 'nam');
+ vv = xref(vv, o);
+ v = par(',', v, vv);
+ end
+ end
+ return v;
+end
+
+
+function list_add(self, name, pos)
+ local nam
+ nam = deref(name);
+ if self:look(nam) then
+ return nil
+ end
+ self.__modifyed__ = true;
+ if tonumber(pos) then
+ stead.table.insert(self, tonumber(pos), nam);
+ self[tonumber(pos)] = nam; -- for spare lists
+ else
+ stead.table.insert(self, nam);
+ end
+ return true
+end
+
+function list_set(self, name, pos)
+ local nam
+ local i = tonumber(pos);
+ if not i then
+ return nil
+ end
+ nam = deref(name);
+ self.__modifyed__ = true;
+ self[i] = nam; -- for spare lists
+ return true
+end
+
+function list_find(self, name)
+ local n, v, ii
+ for n,v,ii in opairs(self) do
+ if ref(v) == ref(name) then
+ return ii;
+ end
+ end
+ return nil
+end
+
+function list_save(self, name, h, need)
+ 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, o, ii
+ for n,o,ii in opairs(self) do
+ o = ref(o);
+ if isObject(o) then
+ local nam = call(o,'nam') ;
+ if not isDisabled(o) and name == tostring(nam) then
+ return ii;
+ end
+ end
+ end
+ return nil
+end
+function list_id(self, id)
+ local n,o,ii
+ for n,o,ii in opairs(self) do
+ o = ref(o);
+ if isObject(o) and not isDisabled(o) and id == o.id then
+ return ii;
+ end
+ end
+end
+
+function list_search(self, n)
+ local i;
+ i = self:look(n);
+ if not i then
+ i = self:name(n);
+ end
+ if not i and tonumber(n) then
+ i = self:byid(tonumber(n));
+ if not i then
+ return nil
+ end
+ end
+ if isDisabled(ref(self[i])) then
+ return nil;
+ end
+ return self[i], i;
+end
+
+function list_zap(self)
+ local n,o,ii
+ for n,o,ii in opairs(self) do
+ self[ii] = nil;
+ end
+ self.__modifyed__ = true
+ return self
+end
+
+function list_concat(self, other, pos)
+ local n,o,ii
+ for n,o,ii in opairs(other) do
+ o = ref(o);
+ if pos == nil then
+ self:add(deref(o));
+ else
+ self:add(deref(o), pos);
+ pos = pos + 1;
+ end
+ end
+end
+
+function list_del(self, name)
+ local v,n
+ v, n = self:srch(name);
+ if n == nil then
+ return nil;
+ end
+ self.__modifyed__ = true
+ v = stead.table.remove(self, n);
+ if not v then
+ v = self[n];
+ self[n] = nil -- for spare lists
+ end
+ return v
+end
+
+function list(v)
+ v.list_type = true;
+ v.add = list_add;
+ v.set = list_set;
+ v.cat = list_concat;
+ v.zap = list_zap;
+ 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 isList(v)
+ return (type(v) == 'table') and (v.list_type == true)
+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];
+ end
+ if type(v[n]) == 'function' then
+ callpush(v)
+ local a,b = v[n](v, unpack(arg));
+ if a == nil and b == nil then
+ a = pget()
+ b = nil
+ end
+ callpop()
+ return a,b
+ end
+ if type(v[n]) == 'boolean' then
+ return v[n]
+ end
+ error ("Method not string nor function:"..tostring(n));
+end
+
+function call_bool(v, n, ...)
+ if type(v) ~= 'table' then
+ error ("Call bool on non table object:"..n);
+ end
+
+ if v[n] == nil then
+ return nil
+ end
+
+ if v[n] == false then
+ return false;
+ end
+
+ if type(v[n]) == 'function' then
+ callpush(v)
+ local r = v[n](v, unpack(arg));
+ callpop();
+ return r;
+ end
+ return true; -- not nil
+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, o;
+ for i,o in opairs(self.obj) do
+ o = ref(o);
+ if isObject(o) then
+ vv = par(' ',vv, o:look());
+ end
+ 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,o in opairs(v.obj) do
+ o = ref(o);
+ if isObject(o) then
+ local r,rr = obj_search(o, n);
+ if r then
+ return r, rr;
+ end
+ end
+ end
+ return;
+end
+
+function room_save(self, name, h, need)
+ local dsc;
+ if need then
+ h:write(name.." = room {nam = '"..tostring(self.nam).."'}\n");
+ end
+ savemembers(h, self, name, need);
+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
+ if v.save == nil then
+ v.save = room_save;
+ 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)
+ if not dialog_rescan(self) then
+ return nil, false
+ end
+ return nil, true
+end
+
+function dialog_scene(self)
+ local v
+ v = iface:title(call(self,'nam'));
+ v = par('^^', v, call(self, 'dsc')); --obj_look(self));
+ return v;
+end
+
+function dialog_look(self)
+ local i,n,v,ph
+ n = 1
+ for i,ph in opairs(self.obj) do
+ ph = ref(ph);
+ if isPhrase(ph) and not isDisabled(ph) then
+ v = par('^', v, txtnm(n, ph:look()));
+ n = n + 1
+ end
+ end
+ return v;
+end
+
+function dialog_rescan(self)
+ local i,k,ph
+ k = 1
+ for i,ph in opairs(self.obj) do
+ ph = ref(ph);
+ 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
+end
+
+
+function dialog_phrase(self, num)
+ if not tonumber(num) then
+ if isPhrase(ref(num)) then
+ return ref(num);
+ end
+ return nil
+ end
+ return ref(self.obj[tonumber(num)]);
+end
+
+function ponoff(s, on, ...)
+ local i, ph
+ if stead.table.maxn(arg) == 0 then
+ stead.table.insert(arg, self());
+ end
+ for i=1,stead.table.maxn(arg) do
+ ph = dialog_phrase(s, arg[i]);
+ if isPhrase(ph) and not isRemoved(ph) then
+ if on then
+ ph:enable();
+ else
+ ph:disable();
+ end
+ end
+ end
+end
+
+function dialog_prem(s, ...)
+ local i, ph
+ if stead.table.maxn(arg) == 0 then
+ stead.table.insert(arg, self());
+ end
+ for i=1,stead.table.maxn(arg) do
+ ph = dialog_phrase(s, arg[i]);
+ if isPhrase(ph) then
+ ph:remove();
+ 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 = nil;
+ local ret = nil;
+ 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
+ local last = call(ph, 'ans');
+ if last == true or ret == true then
+ r = true;
+ end
+ if isDialog(here()) and not dialog_rescan(here()) then
+ ret = par(' ', ret, me():back());
+ end
+
+ ret = par("^^", last, ret);
+
+ if ret == nil then
+ return r -- hack?
+ end
+
+ return ret
+end
+
+function phrase_save(self, name, h, need)
+ if need then
+ local m = " = phr('"
+ if isDisabled(self) then
+ m = " = _phr('"
+ end
+ h:write(name..m..tostring(self.dsc).."','"..tostring(self.ans).."','"..tostring(self.do_act).."');\n");
+ end
+ savemembers(h, self, name, false);
+end
+
+function phrase_look(self, n)
+ if isDisabled(self) then
+ return
+ end
+ local v = call(self, 'dsc');
+ if type(v) ~= 'string' then return; end
+ if game.hinting then
+ return self:xref('{'..v..'}');
+ end
+ return v;
+end
+
+function phrase(o) --constructor
+ local ret = o;
+ ret.look = phrase_look;
+ ret.nam = ''; -- for start
+ 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: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 ref(self.where):scene();
+end
+
+function obj_tag(self, id)
+ local k,v
+
+ if isDisabled(self) then
+ return id
+ end
+
+ for k,v in opairs(self.obj) do
+ v = ref(v);
+ if isObject(v) and not isDisabled(v) then
+ id = id + 1;
+ v.id = id;
+ id = obj_tag(v, id);
+ end
+ end
+ return id;
+end
+
+function player_tagall(self)
+ local id, k, v;
+ id = 0;
+
+ id = obj_tag(here(), id);
+ id = obj_tag(me(), id);
+
+ for k,v in opairs(ways()) do
+ v = ref(v);
+ if isRoom(v) and not isDisabled(v) then
+ id = id + 1;
+ v.id = id;
+ end
+ end
+end
+
+function player_action(self, what, ...)
+ local v,r,obj
+ obj = ref(self.where):srch(what);
+ if not obj then
+ return call(ref(game), 'action', what, unpack(arg)); --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 and r ~= true then
+ v, r = call(ref(game), 'act', obj, unpack(arg));
+ end
+ end
+ return v, r;
+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
+ take(obj, w);
+ end
+ return v;
+end
+
+function player_use(self, what, onwhat)
+ local obj, obj2, v, vv, r;
+ local scene_use_mode = false
+
+ obj = self:srch(what); -- in inv?
+ if not obj then -- no
+ obj = ref(self.where):srch(what); -- in scene?
+ if not obj then -- no!
+ return game.err, false;
+ end
+ scene_use_mode = true -- scene_use_mode!
+ end
+ if onwhat == nil then -- only one?
+ if scene_use_mode then
+ return self:action(what); -- call act
+ else
+ v, r = call(ref(obj),'inv'); -- call inv
+ end
+ if not v and r ~= true then
+ v, r = call(game, 'inv', obj);
+ end
+ return v, r;
+ end
+ obj2 = ref(self.where):srch(onwhat); -- in scene?
+ if not obj2 then
+ obj2 = self:srch(onwhat); -- in inv?
+ end
+ if not obj2 or obj2 == obj then
+ return game.err, false;
+ end
+ if not scene_use_mode or isSceneUse(ref(obj)) then
+ v, r = call(ref(obj), 'use', obj2);
+ if r ~= false then
+ vv = call(ref(obj2), 'used', obj);
+ end
+ end
+ if not v and not vv then
+ v, r = call(game, 'use', obj, obj2);
+ end
+ return 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 was = self.where;
+ local need_scene = false;
+
+ local ret
+
+ if not stead.in_goto_call then
+ ret = function(rc) stead.in_goto_call = false return nil end
+ else
+ ret = function(rc) return rc end
+ end
+
+ stead.in_goto_call = true
+
+ if where == nil then
+ return nil, ret(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: "..self.where);
+ end
+
+ local v, r;
+
+ if not isVroom(ref(where)) and not stead.in_exit_call then
+ stead.in_exit_call = true -- to break recurse
+ v,r = call(ref(self.where), 'exit', where);
+ stead.in_exit_call = nil
+ if r == false then
+ return v, ret(r)
+ end
+ end
+
+ local res = v;
+ v = nil;
+
+ if not isVroom(ref(where)) then
+ self.where = deref(where);
+ end
+
+ if not back or not isDialog(ref(self.where)) or isDialog(ref(where)) then
+ v, r = call(ref(where), 'enter', deref(was));
+ if r == false then
+ self.where = was;
+ return v, ret(r)
+ end
+ need_scene = true;
+ if ref(where) ~= ref(self.where) then -- jump !!!
+ need_scene = false;
+ end
+ end
+ res = par('^^',res,v);
+
+ if not back then
+ ref(where).__from__ = deref(was);
+ end
+
+ ret()
+
+ if need_scene then -- or isForcedsc(ref(where)) then -- i'am not sure...
+ return par('^^',res,ref(where):scene());
+ end
+ return res;
+end
+
+
+function player_goto(self, where)
+ local v, r = go(self, where, false);
+ return v, r;
+end
+
+function player_go(self, where)
+ local w = ref(self.where).way:srch(where);
+ if not w then
+ return nil,false
+ end
+ local v, r = go(self, w, false);
+ return v, r;
+end
+
+function player_save(self, name, h)
+ h:write(tostring(name)..".where = '"..deref(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.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.player_type = true;
+ return obj(v);
+end
+
+function game_life(self)
+ local i,o
+ local av,v
+
+ stead.in_life_call = true;
+ stead.lifes_off = list {}; -- lifes to off
+
+ for i,o in opairs(self.lifes) do
+ local vv
+ local pre
+ o = ref(o);
+ if not isDisabled(o) then
+ vv,pre = call(o,'life');
+ if not pre then
+ v = par(' ',v, vv);
+ else
+ av = par(' ', av, vv);
+ end
+ end
+ end
+ stead.in_life_call = false;
+ for i,o in ipairs(stead.lifes_off) do
+ lifeoff(o);
+ end
+ stead.lifes_off = nil;
+ return v, av;
+end
+
+function check_list(k, v)
+ if v.check == nil or not v:check() then
+ error ("error in list: "..stead.object..'.'..k);
+ end
+end
+
+function check_room(k, v)
+ if v.obj == nil then
+ error("no obj in room:"..k);
+ end
+ if v.way == nil then
+ error("no way in room:"..k);
+ end
+end
+
+function check_player(k, v)
+ v.where = deref(v.where);
+end
+
+function check_object(k, v)
+ if not v.nam then
+ error ("No name in "..k);
+ end
+ if isRoom(v) then
+ check_room(k, v);
+ end
+ if isPlayer(v) then
+ check_player(k, v);
+ end
+ for_each(v, k, check_list, isList)
+end
+
+function for_everything(f, ...)
+ local is_ok = function(s)
+ return true
+ end
+ for_each(_G, '_G', f, is_ok, unpack(arg))
+end
+
+function do_ini(self)
+ local v='',vv
+ local function call_key(k, o)
+ o.key_name = k;
+ end
+ local function call_ini(k, o)
+ v = par('', v, call(o, 'ini'));
+ end
+
+ math.randomseed(tonumber(os.date("%m%d%H%M%S")))
+ rnd(1); rnd(1); rnd(1); -- Lua bug?
+
+ for_each_object(call_key);
+ for_each_object(check_object);
+
+ game.pl = deref(game.pl);
+ game.where = deref(game.where);
+
+ for_each(game, "game", check_list, isList)
+
+ for_each_object(call_ini);
+
+ 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'));
+ if type(init) == 'function' then
+ init();
+ end
+-- if type(hooks) == 'function' then
+-- hooks();
+-- end
+ 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 isEnableSave()
+ if game.enable_save == nil or get_autosave() then
+ return true
+ end
+ return call_bool(game, 'enable_save');
+end
+
+function for_each(o, n, f, fv, ...)
+ local k,v
+ if type(o) ~= 'table' then
+ return
+ end
+ stead.object = n;
+ for k,v in pairs(o) do
+ if type(v) == 'table' and fv(v) then
+ local i = tonumber(k);
+ local nn
+ if i then
+ nn = n.."["..i.."]"
+ else
+ if n == '_G' then
+ nn = k;
+ else
+ nn = n.."."..k;
+ end
+ end
+ f(k, v, unpack(arg));
+ end
+ end
+end
+
+function for_each_object(f,...)
+ for_each(_G, '_G', f, isObject, unpack(arg))
+end
+
+function for_each_player(f,...)
+ for_each(_G, '_G', f, isPlayer, unpack(arg))
+end
+
+function for_each_room(f,...)
+ for_each(_G, '_G', f, isRoom, unpack(arg))
+end
+
+function for_each_list(f,...)
+ for_each(_G, '_G', f, isList, unpack(arg))
+end
+
+function clearvar (v)
+ local k,o
+ for k,o in pairs(v) do
+ if type(o) == 'table' and o.__visited__ ~= nil then
+ o.__visited__ = nil
+ clearvar(o)
+ end
+ 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 isForSave(k, v, self) then
+ need2 = true;
+ end
+
+ if type(k) == 'string' then
+ savevar(h, v, name..'["'..k:gsub('"','\\"')..'"]', 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 stead.string.find(n, '_') == 1 or stead.string.match(n,'^%u') then
+-- need = true;
+-- end
+
+ if type(v) == "string" then
+ if not need then
+ return
+ end
+ h:write(stead.string.format("%s=%q\n",n,v))
+ return;
+ end
+
+ if type(v) == "table" then
+ if v.__visited__ ~= nil then
+ return
+ end
+
+ v.__visited__ = n;
+
+ if type(v.save) == 'function' then
+ v:save(n, h, need);
+ return;
+ end
+
+ 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 = '"..deref(self.pl).."'\n");
+ savemembers(file, self, name, false);
+ return nil, true
+ end
+
+ if not isEnableSave() then
+ return nil, false
+ end
+
+ if name == nil then
+ return nil, false
+ end
+ h = stead.io.open(name,"w");
+ if not h then
+ return nil, false
+ end
+ local n = call(here(),'nam');
+ if type(n) == 'string' and n ~= "" then
+ h:write("-- $Name: "..n:gsub("\n","\\n").."$\n");
+ end
+ for_each_object(save_object, h);
+ save_object('game', self, h);
+ clearvar(_G);
+ h:flush();
+ h:close();
+ game.autosave = false; -- we have only one try for autosave
+ 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_step(self)
+ self._time = self._time + 1;
+ return self:life(self);
+end
+
+
+game = game {
+ nam = "INSTEAD -- Simple Text Adventure interpreter v"..stead.version.." '2009-2010 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,
+ _snapshots = {},
+};
+function strip(s)
+ local s = tostring(s);
+ s = stead.string.gsub(s, '^[ \t]*', '');
+ s = stead.string.gsub(s, '[ \t]*$', '');
+ return s;
+end
+
+function isForcedsc(v)
+ local r,g
+ r = call_bool(v, 'forcedsc');
+ if r then
+ return true
+ end
+ g = call_bool(game, 'forcedsc');
+ return g and r ~= false
+end
+
+function isSceneUse(v)
+ local o,g
+ o = call_bool(v, 'scene_use');
+ if o then
+ return true
+ end
+ g = call_bool(game, 'scene_use');
+ return g and o ~= false
+end
+
+iface = {
+ img = function(self, str)
+ return '';
+ end,
+ nb = function(self, str)
+ return str;
+ end,
+ em = function(self, str)
+ return str;
+ end,
+ right = function(self, str)
+ return str;
+ end,
+ left = function(self, str)
+ return str;
+ end,
+ center = function(self, str)
+ return str;
+ end,
+ bold = function(self, str)
+ return str;
+ end,
+ under = function(self, str)
+ return str;
+ end,
+ enum = function(self, n, str)
+ return n..' - '..str;
+ end,
+ xref = function(self, str, obj)
+ local o = ref(here():srch(obj));
+ if not o then
+ o = ref(ways():srch(obj));
+ end
+ if not o then
+ o = ref(me():srch(obj));
+ end
+ if not o or not o.id then
+ return str;
+ end
+ return cat(str,"("..tostring(o.id)..")");
+ 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,
+ fmt = function(self, cmd, st, moved, r, av, objs, pv) -- st -- changed state (main win), move -- loc changed
+ local l
+ if st and not moved then
+ if cmd ~= 'look' and cmd ~= '' then
+ av = txtem(av);
+ pv = txtem(pv);
+ r = txtem(r);
+ if isForcedsc(here()) then
+ l = me():look();
+ end
+ end
+ end
+ vv = fmt(cat(par("^^", l, r, av, objs, pv), '^'));
+ return vv
+ end,
+ cmd = function(self, inp)
+ local r, v;
+ v = false
+ local st = false; -- changed state (main screen)
+ local a = { };
+ local cmd;
+
+ cmd,a = stead.getcmd(inp);
+-- me():tag();
+ local oldloc = here();
+
+ 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
+ elseif cmd == 'nop' then
+ v = true;
+ r = nil;
+ st = true;
+ else
+ r,v = me():action(cmd, unpack(a));
+ st = true;
+ end
+ -- here r is action result, v - ret code value
+ -- st -- game state changed
+ if st and r == nil and v == true then -- we do nothing
+ return nil;
+ end
+
+ if RAW_TEXT then
+ RAW_TEXT = nil
+ v = false
+ end
+
+ if v == false then
+ return cat(r, '\n'), false;
+ end
+
+ ACTION_TEXT = r; -- here, life methods can redefine this
+
+ local av, pv -- av -- active lifes, pv -- background
+ local vv
+
+ if st then
+ pv,av = game:step();
+ me():tag();
+ vv = here():look();
+ end
+
+ vv = self:fmt(cmd, st, oldloc ~= here(), ACTION_TEXT, av, vv, pv);
+
+ if st then
+ game._lastdisp = vv
+ end
+
+ if vv == nil then -- nil is error
+ return ''
+ end
+ return vv;
+ end,
+ shell = function(self)
+ local inp, i, k, cmd, a, n;
+ me():tag();
+ while game._running do
+ inp = stead.io.read("*l");
+ if inp == 'quit' then
+ break;
+ end
+ self:text(self:cmd(inp));
+ end
+ end
+};
+
+
+function me()
+ return ref(game.pl);
+end
+
+function where(s)
+ if isPlayer(ref(s)) then
+ return ref(ref(s).where);
+ end
+ return ref(ref(s).__where__);
+end
+
+function here()
+ return ref(me().where);
+end
+
+function from(w)
+ if w == nil then
+ w = here();
+ else
+ w = ref(w);
+ end
+ return ref(w.__from__);
+end
+
+function time()
+ return game._time;
+end
+
+function inv()
+ return me().obj;
+end
+
+function objs(w)
+ if not w then
+ return here().obj;
+ else
+ return ref(w).obj;
+ end
+end
+
+function ways(w)
+ if not w then
+ return here().way;
+ else
+ return ref(w).way;
+ end
+end
+
+function xref(str, obj)
+ if type(str) ~= 'string' then return nil; end;
+ 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)
+ if stead.in_life_call then
+ stead.lifes_off:add(what);
+ return
+ end
+ game.lifes:del(what);
+end
+
+function allocator_save(s, name, h, need)
+ if need then
+ local m = ' = allocator:get("'..name:gsub('"','\\"')..'","'..tostring(s.constructor):gsub('"','\\"')..'");';
+ h:write(name..m..'\n');
+ end
+ savemembers(h, s, name, false);
+end
+
+allocator = obj {
+ nam = 'allocator',
+ get = function(s, n, c)
+ local v = ref(c);
+ v.key_name = n;
+ v.save = allocator_save;
+ v.constructor = c;
+ return v
+ end,
+ delete = function(s, w)
+ w = ref(w);
+ if type(w.key_name) ~= 'string' then
+ return
+ end
+ local f = loadstring(w.key_name..'= nil;');
+ if f then
+ f();
+ end
+ end,
+ new = function(s, n)
+ local v = ref(n);
+ if type(v) ~= 'table' or type(n) ~= 'string' then
+ error "Error in new.";
+ end
+ v.save = allocator_save;
+ v.constructor = n;
+ stead.table.insert(s.objects, v);
+ v.key_name = 'allocator.objects['..stead.table.maxn(s.objects)..']';
+ return v
+ end,
+ objects = {
+ save = function(self, name, h, need)
+ savemembers(h, self, name, true);
+ end
+ },
+};
+
+function new(str)
+ if type(str) ~= 'string' then
+ error("Non string constructor in new.");
+ end
+ return allocator:new(str);
+end
+
+function delete(v)
+ allocator:delete(v);
+end
+
+timer = obj { -- timer calls stead.timer callback
+ nam = 'timer',
+ ini = function(s)
+ if tonumber(s._timer) ~= nil and type(set_timer) == 'function' then
+ set_timer(s._timer);
+ end
+ end,
+ get = function(s)
+ if tonumber(s._timer) == nil then
+ return 0
+ end
+ return tonumber(s._timer);
+ end,
+ stop = function(s)
+ return s:set(0);
+ end,
+ del = function(s)
+ return s:set(0);
+ end,
+ set = function(s, v)
+ s._timer = tonumber(v);
+ if type(set_timer) ~= 'function' then
+ return false
+ end
+ set_timer(v)
+ return true
+ end,
+--[[ callback = function(s)
+ end, ]]
+};
+
+input = obj { -- input object
+ nam = 'input',
+--[[ key = function(s, down, key)
+ return
+ end, ]]
+--[[ click = function(s, down, mb, x, y, [ px, py ] )
+ return
+ end ]]
+};
+
+prefs = obj {
+ nam = 'preferences',
+ ini = function(s)
+ local name = get_savepath() .. '/prefs';
+ local f, err = loadfile(name);
+ if not f then return nil end
+ f();
+ end,
+ store = function(s)
+ local name = get_savepath() .. '/prefs';
+ local h = stead.io.open(name,"w");
+ if not h then return false end
+ savemembers(h, s, 'prefs', true);
+ h:flush();
+ h:close();
+ end,
+ purge = function(s)
+ local name = get_savepath() .. '/prefs';
+ return stead.os.remove(name);
+ end
+};
+
+function vobj_save(self, name, h, need)
+ local dsc;
+ local w
+ if type(self.dsc) ~= 'string' then
+ dsc = 'nil';
+ else
+ dsc = "[["..self.dsc.."]]";
+ end
+
+ if type(deref(self.where)) ~= 'string' then
+ w = 'nil';
+ else
+ w = "'"..deref(self.where).."'";
+ end
+
+ if need then
+ h:write(name.." = vobj("..tostring(self.key)..",[["..self.nam.."]],"..dsc..","..w..");\n");
+ end
+ savemembers(h, self, name,false);
+end
+
+function vobj_act(self, ...)
+ local o, r = here():srch(self); -- self.nam
+ if ref(o) and ref(o).where then
+ return goto(ref(o).where);
+ end
+ 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, w)
+ if not tonumber(key) then
+ error ("vobj key must be number!");
+ end
+ return obj{ key = key, nam = name, dsc = dsc, where = deref(w), act = vobj_act, used = vobj_used, save = vobj_save, obj = list({}) };
+end
+
+function vway(name, dsc, w)
+-- o.object_type = true;
+ return obj{ key = -1, nam = name, dsc = dsc, act = vobj_act, where = deref(w), used = vobj_used, save = vobj_save, obj = list({}), };
+end
+
+function vroom_save(self, name, h, need)
+ if need then
+ h:write(name.." = vroom('"..self.nam.."','"..deref(self.where).."');\n");
+ end
+ savemembers(h, self, name,false);
+end
+
+function vroom_enter(self, ...)
+ return go(me(), self.where, false);
+end
+
+function isVroom(v)
+ return (type(v) == 'table') and (v.vroom_type)
+end
+
+function vroom(name, w)
+ return room { vroom_type = true, nam = name, where = deref(w), enter = vroom_enter, save = vroom_save, };
+end
+
+function goto(what)
+ local v,r=me():goto(what);
+ me():tag();
+ return v,r;
+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 remove(obj, from)
+ local o,w
+ if from then
+ o,w = ref(from):srch(obj);
+ else
+ o,w = here():srch(obj);
+ end
+ if w then
+ ref(w).obj:del(obj);
+ end
+ o = ref(o);
+ if not isObject(o) then
+ o = ref(obj);
+ end
+ return o
+end
+
+function take(obj, wh)
+ local o = remove(obj, wh);
+ if not isObject(o) then
+ error "Trying to take wrong object.";
+ end
+ inv():add(obj);
+ o._taken = true
+ return o
+end
+
+function putto(obj, w, pos)
+ local wh
+ local o = ref(obj);
+ if not isObject(o) then
+ error "Trying to put wrong object.";
+ end
+ if not w then
+ wh = deref(here());
+ w = here();
+ else
+ wh = deref(w);
+ w = ref(w);
+ end
+ w.obj:add(obj, pos);
+ if type(wh) == 'string' then
+ o.__where__ = wh;
+ end
+ return o;
+end
+
+
+function put(obj, w)
+ return putto(obj, w);
+end
+
+function putf(obj, w)
+ return putto(obj, w, 1);
+end
+
+function drop(obj, w)
+ local o = put(obj, w);
+ if not isObject(o) then
+ error "Trying to drop wrong object:";
+ end
+ inv():del(obj);
+ o._taken = false
+ return o;
+end
+
+function dropf(obj)
+ local o = putf(obj);
+ if not isObject(o) then
+ error "Trying to dropf wrong object:";
+ end
+ inv():del(obj);
+ o._taken = false
+ return o;
+end
+
+function seen(obj, wh)
+ if not wh then
+ wh = here();
+ else
+ wh = ref(wh);
+ end
+ local o,w = wh:srch(obj);
+ o = ref(o);
+ if isObject(o) then
+ return o,w
+ end
+ return nil
+end
+
+function have(obj)
+ local o = inv():srch(obj);
+ o = ref(o);
+ if isObject(o) then
+ return o
+ end
+ return nil
+end
+
+function moveto(obj, there, from, pos)
+ remove(obj, from);
+ putto(obj, there, pos);
+ return ref(obj);
+end
+
+
+function move(obj, there, from)
+ return moveto(obj, there, from);
+end
+
+function movef(obj, there, from)
+ return moveto(obj, there, from, 1);
+end
+
+function get_picture()
+ local s = call(here(),'pic');
+ if not s then
+ s = call(game, 'pic');
+ end
+ return s;
+end
+
+function get_title()
+ local s = call(here(),'nam');
+ return s;
+end
+
+function get_music()
+ return game._music, game._music_loop;
+end
+
+function get_music_loop()
+ return game._music_loop;
+end
+
+function save_music(s)
+ s.__old_music__ = get_music();
+ s.__old_loop__ = get_music_loop();
+end
+
+function restore_music(s)
+ set_music(s.__old_music__, s.__old_loop__);
+end
+
+function dec_music_loop()
+ if game._music_loop == 0 then
+ return 0
+ end
+ game._music_loop = game._music_loop - 1;
+ if game._music_loop == 0 then
+ game._music_loop = -1;
+ end
+ return game._music_loop;
+end
+
+function set_music(s, count)
+ game._music = s;
+ if not tonumber(count) then
+ game._music_loop = 0;
+ else
+ game._music_loop = tonumber(count);
+ end
+end
+
+function stop_music()
+ set_music(nil, -1);
+end
+
+function is_music()
+ return game._music ~= nil and game._music_loop ~= -1
+end
+
+if is_sound == nil then
+ function is_sound()
+ return false -- sdl-instead export own function
+ end
+end
+
+if get_savepath == nil then
+ function get_savepath()
+ return "./"
+ end
+end
+
+function autosave(slot)
+ game.autosave = true;
+ game.autosave_slot = slot;
+end
+
+function get_autosave()
+ return game.autosave, game.autosave_slot
+end
+
+function get_sound()
+ return game._sound, game._sound_channel, game._sound_loop;
+end
+
+function get_sound_chan()
+ return game._sound_channel
+end
+
+function get_sound_loop()
+ return game._sound_loop
+end
+
+function set_sound(s, chan, loop)
+ game._sound = s;
+ if not tonumber(loop) then
+ game._sound_loop = 1;
+ else
+ game._sound_loop = tonumber(loop);
+ end
+
+ if not tonumber(chan) then
+ game._sound_channel = -1;
+ else
+ game._sound_channel = tonumber(chan);
+ end
+end
+
+function change_pl(p)
+ local o = ref(p);
+ if type(deref(p)) ~= 'string' or not o then
+ error "Wrong player name in change_pl...";
+ end
+ game.pl = deref(p);
+ return goto(o.where);
+end
+
+function disabled(o)
+ return isDisabled(ref(o))
+end
+
+function isForSave(k, v, s) -- k - key, v - value, s -- parent table
+ return stead.string.find(k, '_') == 1 or stead.string.match(k,'^%u')
+end
+
+function make_snapshot(nr)
+ if not tonumber(nr) then nr = 0 end
+ local h = { };
+ h.txt = ''
+ h.write = function(s, ...)
+ local i
+ for i = 1, stead.table.maxn(arg) do
+ s.txt = s.txt .. tostring(arg[i]);
+ end
+ end
+ local old = game._snapshots; game._snapshots = nil
+ for_each_object(save_object, h);
+ save_object('game', game, h);
+ clearvar(_G);
+ game._snapshots = old
+ game._snapshots[nr] = h.txt;
+end
+
+function restore_snapshot(nr)
+ if not tonumber(nr) then nr = 0 end
+ local ss = game._snapshots
+ if not ss[nr] then return nil, true end -- nothing todo
+ stead_init();
+ dofile('main.lua');
+ if type(init) == 'function' then -- no hooks here!!!
+ init();
+ end
+ local f, err = loadstring(ss[nr]);
+ if not f then return end
+ local i,r = f();
+ game._snapshots = ss
+ if r then
+ return nil, false
+ end
+ i = do_ini(game);
+ RAW_TEXT = true
+ return i;
+end
+
+function delete_snapshot(nr)
+ if not tonumber(nr) then nr = 0 end
+ game._snapshots[nr] = nil
+end
+
+function inherit(o, f)
+ return function(...)
+ return f(o(unpack(arg)))
+ end
+end
+
+function hook(o, f)
+ return function(...)
+ return f(o, unpack(arg))
+ end
+end
+
+--- here the game begins
+function stead_init()
+pl = player {
+ nam = "Incognito",
+ where = 'main',
+ obj = { }
+};
+
+main = room {
+ nam = 'main',
+ dsc = 'No main room defined.',
+}
+end
+stead_init();