1stead = {
2	version = "3.4.1",
3	api_version = "1.1.6", -- last version before 1.2.0
4	table = table,
5	delim = ',',
6	scene_delim = "^^",
7	space_delim = ' ',
8	string = string,
9	tostr = tostring,
10	tonum = tonumber,
11	collectgarbage = collectgarbage,
12	type = type,
13	ipairs = ipairs,
14	pairs = pairs,
15	getinfo = debug.getinfo;
16	rawget = rawget;
17	rawset = rawset;
18	math = math,
19	random = instead_random,
20	randomseed = instead_srandom,
21	next = next,
22	math = math,
23	io = io,
24	os = os,
25	readdir = instead_readdir,
26	cache = {},
27	call_top = 0,
28	call_ctx = { txt = nil, self = nil },
29--	functions = {}, -- code blocks
30
31	modules_ini = {},
32	modules_done = {},
33	modules_start = {},
34	modules_cmd = {},
35	busy = function() end;
36	module_init = function(f, ...)
37		if stead.type(f) ~= 'function' then
38			error ("Wrong parameter to module_init.", 2);
39		end
40		stead.table.insert(stead.modules_ini, f);
41		f();
42	end;
43
44	module_done = function(f, ...)
45		if stead.type(f) ~= 'function' then
46			error ("Wrong parameter to module_done.", 2);
47		end
48		stead.table.insert(stead.modules_done, f);
49	end;
50
51	module_start = function(f, ...)
52		if stead.type(f) ~= 'function' then
53			error ("Wrong parameter to module_start.", 2);
54		end
55		stead.table.insert(stead.modules_start, f);
56	end;
57
58	module_cmd = function(f, ...)
59		if stead.type(f) ~= 'function' then
60			error ("Wrong parameter to module_cmd.", 2);
61		end
62		stead.table.insert(stead.modules_cmd, f);
63	end;
64}
65
66function instead_menu_toggle(n)
67	if n == nil then
68		n = 'main'
69	elseif type(n) ~= 'string' then
70		n = 'toggle'
71	end
72	stead.need_menu = n
73end
74
75stead.menu_toggle = instead_menu_toggle
76
77stead.api_atleast = function(...)
78	for k, v in stead.ipairs {...} do
79		if stead.type(v) ~= 'number' then
80			return false
81		end
82		if v > (stead.api_version_table[k] or 0) then
83			return false
84		end
85		if v < (stead.api_version_table[k] or 0) then
86			return true
87		end
88	end
89	return true
90end;
91
92stead.atleast = function(...)
93	for k, v in stead.ipairs {...} do
94		if stead.type(k) ~= 'number' then
95			return false
96		end
97		if v > (stead.version_table[k] or 0) then
98			return false
99		end
100		if v < (stead.version_table[k] or 0) then
101			return true
102		end
103	end
104	return true
105end;
106
107stead.last_act = function(s)
108	local r = game.__last_act
109
110	if s ~= nil and s ~= true then
111		game.__last_act = s
112	end
113
114	return r
115end
116
117stead.last_disp = function(s)
118	local r = game._lastdisp
119
120	if s == nil then
121		return r
122	end
123	if not s then s = nil end
124	game._lastdisp = s
125	return r
126end
127
128stead.act_text = function(s)
129	local o = stead.rawget(_G, 'ACTION_TEXT')
130	if s == nil then
131		return o
132	end
133	if not s then s = nil end
134	stead.rawset(_G, 'ACTION_TEXT', s)
135	return o
136end
137
138stead.nop = function(s) -- to refresh entry scene w/o time tick
139	stead.act_text(true)
140	return stead.last_disp() or ''
141end
142
143stead.need_scene = function(s)
144	if s == nil then
145		stead.rawset(_G, 'NEED_SCENE', true)
146	else
147		stead.rawset(_G, 'NEED_SCENE', s)
148	end
149end
150
151if _VERSION == "Lua 5.1" then
152	stead.eval = loadstring
153	stead.unpack = unpack
154else
155	stead.eval = load
156	stead.unpack = table.unpack
157	unpack = table.unpack -- buggy games
158	stead.table.maxn = table_get_maxn
159	string.gfind = string.gmatch
160	math.mod = math.fmod
161	math.log10 = function(a)
162		return stead.math.log(a, 10)
163	end
164end
165
166instead = stead;
167
168function stead.getcmd(str)
169	local a = {}
170	local n = 1
171	local cmd;
172	local i,k = stead.string.find(str, '[a-zA-Z0-9_]+');
173	if not i or not k then
174		cmd = str;
175	else
176		cmd = stead.string.sub(str, i, k);
177	end
178
179	stead.cmd = cmd
180	if cmd == 'load' or cmd == 'save' then
181		a[1] = stead.strip(stead.string.sub(str, k + 1));
182		stead.args = a;
183		return cmd, a
184	end
185	while i do
186		k = k + 1;
187		i,k = stead.string.find(str,'[^,]+', k);
188		if not i then
189			break
190		end
191		a[n] = stead.strip(stead.string.sub(str, i, k));
192		n = n + 1;
193	end
194	stead.args = a;
195	return cmd, a
196end
197
198stead.tostring = function(v)
199	if isCode(v) then
200		v = stead.string.format("code %q", stead.functions[v].code);
201	elseif stead.type(v) == 'string' then
202		v = stead.string.format("%q", v);
203	elseif v == nil or stead.type(v) == 'boolean' or stead.type(v) == 'number' then
204		v = stead.tostr(v);
205	elseif stead.type(v) == 'table' and stead.type(stead.deref(v)) == 'string' then
206		v = stead.deref(v);
207	else
208		v = nil
209	end
210	return v
211end
212
213stead.cctx = function()
214	return stead.call_ctx[stead.call_top];
215end
216
217stead.callpush = function(v, ...)
218	stead.call_top = stead.call_top + 1;
219	stead.call_ctx[stead.call_top] = { txt = nil, self = v, action = false };
220	stead.rawset(_G, 'args', {...});
221	stead.rawset(_G, 'arg1', args[1])
222	stead.rawset(_G, 'arg2', args[2])
223	stead.rawset(_G, 'arg3', args[3])
224	stead.rawset(_G, 'arg4', args[4])
225	stead.rawset(_G, 'arg5', args[5])
226	stead.rawset(_G, 'arg6', args[6])
227	stead.rawset(_G, 'arg7', args[7])
228	stead.rawset(_G, 'arg8', args[8])
229	stead.rawset(_G, 'arg9', args[9])
230	-- dirty but clean and fast :)
231	stead.rawset(_G, 'self', v)
232end
233
234stead.clearargs = function()
235	stead.rawset(_G, 'arg1', nil)
236	stead.rawset(_G, 'arg2', nil)
237	stead.rawset(_G, 'arg3', nil)
238	stead.rawset(_G, 'arg4', nil)
239	stead.rawset(_G, 'arg5', nil)
240	stead.rawset(_G, 'arg6', nil)
241	stead.rawset(_G, 'arg7', nil)
242	stead.rawset(_G, 'arg8', nil)
243	stead.rawset(_G, 'arg9', nil)
244	stead.rawset(_G, 'self', nil)
245end
246
247stead.callpop = function()
248	stead.call_ctx[stead.call_top] = nil;
249	stead.call_top = stead.call_top - 1;
250	if stead.call_top < 0 then
251		error ("callpush/callpop mismatch")
252	end
253	stead.clearargs()
254end
255
256stead.pclr = function()
257	stead.cctx().txt = nil
258end
259
260stead.pget = function()
261	return stead.cctx().txt;
262end
263
264stead.p = function(...)
265	local a = {...}
266	if stead.cctx() == nil then
267		error ("Call from global context.", 2);
268	end
269	for i = 1, stead.table.maxn(a) do
270		stead.cctx().txt = stead.par('', stead.cctx().txt, stead.tostr(a[i]));
271	end
272	stead.cctx().txt = stead.cat(stead.cctx().txt, stead.space_delim);
273end
274
275stead.pr = function(...)
276	local a = {...}
277	if stead.cctx() == nil then
278		error ("Call from global context.", 2);
279	end
280	for i = 1, stead.table.maxn(a) do
281		stead.cctx().txt = stead.par('', stead.cctx().txt, stead.tostr(a[i]));
282	end
283end
284
285stead.pn = function(...)
286	if stead.cctx() == nil then
287		error ("Call from global context.", 2);
288	end
289	p(...);
290	stead.cctx().txt = stead.par('', stead.cctx().txt,'^');
291end
292
293-- merge strings with "space" as separator
294stead.par = function(space,...)
295	local res
296	local a = {...};
297	for i = 1, stead.table.maxn(a) do
298		if stead.type(a[i]) == 'string' then
299			if res == nil then
300				res = ""
301			else
302				res = res..space;
303			end
304			res = res..a[i];
305		end
306	end
307	return res;
308end
309-- add to not nill string any string
310stead.cat = function(v,...)
311	local res
312	if not v then
313		return nil
314	end
315	res = v;
316	local a = {...}
317	for i = 1, stead.table.maxn(a) do
318		if stead.type(a[i]) == 'string' then
319			res = res..a[i];
320		end
321	end
322	return res;
323end
324
325function txtnb(v)
326	if stead.type(v) ~= 'string' then return nil; end
327	return iface:nb(v);
328end
329
330function img(v)
331	if stead.type(v) ~= 'string' then return nil; end;
332	return iface:img(v);
333end
334
335function imgl(v)
336	if stead.type(v) ~= 'string' then return nil; end;
337	return iface:imgl(v);
338end
339
340function imgr(v)
341	if stead.type(v) ~= 'string' then return nil; end;
342	return iface:imgr(v);
343end
344
345function txtem(v)
346	if stead.type(v) ~= 'string' then return nil; end;
347	return iface:em(v)
348end
349
350function txtst(v)
351	if stead.type(v) ~= 'string' then return nil; end;
352	return iface:st(v)
353end
354
355function txtr(v)
356	if stead.type(v) ~= 'string' then return nil; end;
357	return iface:right(v)
358end
359
360function txtl(v)
361	if stead.type(v) ~= 'string' then return nil; end;
362	return iface:left(v)
363end
364
365function txtc(v)
366	if stead.type(v) ~= 'string' then return nil; end;
367	return iface:center(v)
368end
369
370function txttab(v,a)
371	return iface:tab(v, a)
372end
373
374function txty(v, a)
375	return iface:y(v, a)
376end
377
378function txtj(v)
379	if stead.type(v) ~= 'string' then return nil; end;
380	return iface:just(v)
381end
382
383function txtb(v)
384	if stead.type(v) ~= 'string' then return nil; end;
385	return iface:bold(v)
386end
387
388function txtu(v)
389	if stead.type(v) ~= 'string' then return nil; end;
390	return iface:under(v)
391end
392
393function txtnm(n, v)
394	if stead.type(v) ~= 'string' or not stead.tonum(n) then return nil; end
395	return iface:enum(n, v);
396end
397
398function txttop(v)
399	if stead.type(v) ~= 'string' then return nil; end;
400	return iface:top(v)
401end
402
403function txtbottom(v)
404	if stead.type(v) ~= 'string' then return nil; end;
405	return iface:bottom(v)
406end
407
408function txtmiddle(v)
409	if stead.type(v) ~= 'string' then return nil; end;
410	return iface:middle(v)
411end
412
413stead.fmt = function(...)
414	local res
415	local a = {...};
416
417	for i = 1, stead.table.maxn(a) do
418		if stead.type(a[i]) == 'string' then
419			local s = stead.string.gsub(a[i],'[\t ]+', stead.space_delim);
420			s = stead.string.gsub(s, '[\n]+', stead.space_delim);
421			s = stead.string.gsub(s, '\\?[\\^]', { ['^'] = '\n', ['\\^'] = '^', ['\\\\'] = '\\'} );
422			res = stead.par('', res, s);
423		end
424	end
425	return res
426end
427
428-- integer lists
429local inext = function(t, k)
430	local v
431	k, v = stead.next(t, k);
432	while k and not stead.tonum(k) do
433		k, v = stead.next(t, k);
434	end
435	if not stead.tonum(k) then
436		return nil
437	end
438	return k, v
439end
440
441local ilist = function(s, var)
442	return inext, s, nil;
443end
444
445local ordered_i = function(t)
446	local ordered = {};
447	local max = 0
448	for i, v in ilist(t) do
449		stead.table.insert(ordered, i);
450		max = max + 1;
451	end
452	stead.table.sort(ordered);
453	ordered.i = 1;
454	ordered.max = max;
455	return ordered;
456end
457
458local onext = function(t, k)
459	local v
460	if not k then
461		k = ordered_i(t);
462	end
463	if k.i > k.max then
464		return nil
465	end
466	v = k[k.i]
467	k.i = k.i + 1
468	return k, t[v], v;
469end
470
471function opairs(s)
472	return onext, s, nil;
473end
474stead.opairs = opairs
475
476function isPlayer(v)
477	return (stead.type(v) == 'table') and (v.player_type)
478end
479
480function isRoom(v)
481	return (stead.type(v) == 'table') and (v.location_type)
482end
483
484function isPhrase(v)
485	return (stead.type(v) == 'table') and (v.phrase_type)
486end
487
488function isDialog(v)
489	return (stead.type(v) == 'table') and (v.dialog_type)
490end
491
492function isDisabled(v)
493	return (stead.type(v) == 'table') and (v._disabled)
494end
495
496function isRemoved(v)
497	return (stead.type(v) == 'table') and (v._disabled == -1)
498end
499
500function isObject(v)
501	return (stead.type(v) == 'table') and (v.object_type)
502end
503
504function isXaction(v)
505	return (stead.type(v) == 'table') and (v.xaction_type)
506end
507
508
509stead.obj_xref = function(self,str)
510	function xrefrep(str)
511		local s = stead.string.gsub(str,'[\001\002]','');
512		return stead.xref(s, self);
513	end
514	if not str then
515		return
516	end
517	if not isObject(self) then
518		return str;
519	end
520	local s = stead.string.gsub(str, '\\?[\\{}]',
521		{ ['{'] = '\001', ['}'] = '\002', [ '\\{' ] = '{', [ '\\}' ] = '}' }):gsub('\001([^\002]+)\002', xrefrep):gsub('[\001\002]', { ['\001'] = '{', ['\002'] = '}' });
522	return s;
523end
524
525stead.obj_look = function(self)
526	local vv
527	if isDisabled(self) then
528		return
529	end
530	local v = stead.call(self,'dsc');
531	if game.hinting then
532		v = self:xref(v);
533	elseif v then
534		v = stead.string.gsub(v, '[{}]','');
535	end
536	for i, o in stead.opairs(self.obj) do
537		o = stead.ref(o);
538		if isObject(o) then
539			vv = stead.obj_look(o);
540			v = stead.par(stead.space_delim, v, vv);
541		end
542	end
543	return v;
544end
545
546
547stead.obj_remove = function(self)
548	self._disabled = -1;
549	return self
550end
551
552stead.obj_disable = function(self)
553	self._disabled = true;
554	return self
555end
556
557stead.obj_enable = function(self)
558	self._disabled = false;
559	return self
560end
561
562stead.obj_disabled = function(self)
563	return (self._disabled == true);
564end
565
566stead.obj_enable_all = function(s)
567	if not isObject(s) then
568		return
569	end
570	objs(s):enable_all();
571end
572
573stead.obj_disable_all = function(s)
574	if not isObject(s) then
575		return
576	end
577	objs(s):disable_all();
578end
579
580stead.obj_save = function(self, name, h, need)
581	local dsc;
582	if need then
583		print ("Warning: object "..name.." can not be saved!");
584		return
585	end
586	stead.savemembers(h, self, name, need);
587end
588
589stead.obj_str = function(self)
590	local v, vv;
591	if not isObject(self) then
592		return
593	end
594	if isDisabled(self) then
595		return
596	end
597	for i, o in stead.opairs(self.obj) do
598		o = stead.ref(o);
599		if o~= nil and not isDisabled(o) then -- isObject is better, but compat layer must be ok
600			vv = stead.call(o, 'nam');
601			vv = stead.xref(vv, o);
602			v = stead.par(',', v, vv, stead.obj_str(o));
603		end
604	end
605	return v;
606end
607
608function obj(v)
609	if v.nam == nil then
610		if isRoom(v) then
611			if isDialog(v) then
612				error ("No dialog name in constructor.", 3);
613			end
614			error ("No room name in constructor.", 3);
615		end
616		error ("No object name in constructor.", 2);
617	end
618	v.object_type = true;
619
620	if v.xref == nil then
621		v.xref = stead.obj_xref;
622	end
623
624	if v.look == nil then
625		v.look = stead.obj_look;
626	end
627	if v.enable == nil then
628		v.enable = stead.obj_enable;
629	end
630	if v.disable == nil then
631		v.disable = stead.obj_disable;
632	end
633	if v.disabled == nil then
634		v.disabled = stead.obj_disabled;
635	end
636	if v.enable_all == nil then
637		v.enable_all = stead.obj_enable_all;
638	end
639	if v.disable_all == nil then
640		v.disable_all = stead.obj_disable_all;
641	end
642	if v.remove == nil then
643		v.remove = stead.obj_remove;
644	end
645	if v.obj == nil then
646		v.obj = {};
647	end
648	if v.srch == nil then
649		v.srch = stead.obj_search;
650	end
651	if v.str == nil then
652		v.str = stead.obj_str;
653	end
654	v.obj = list(v.obj);
655	if v.save == nil then
656		v.save = stead.obj_save;
657	end
658	return v
659end
660
661
662function stead.ref(n, nofunc) -- ref object by name
663	if stead.type(n) == 'string' then
664		if n:find("^[_a-zA-Z][_a-zA-Z0-9]*$") then -- fastest path
665			return stead.rawget(_G, n);
666		end
667		local f = stead.eval('return '..n);
668		if f then
669			return stead.ref(f(), nofunc);
670		end
671		return nil;
672	end
673	if stead.type(n) == 'table' then
674		return n;
675	end
676	if stead.type(n) == 'function' and not nofunc then
677		local r,v = pcall(n);
678		if not r then
679			return nil
680		end
681		return stead.ref(v);
682	end
683	return nil
684end
685
686function stead.deref(n)
687	if stead.type(n) == 'string' then
688		return n
689	end
690
691	if stead.type(n) == 'table' and stead.type(n.key_name) == 'string' then
692		return n.key_name
693	end
694	return n
695end
696
697stead.list_check = function(self, name)
698	for i, v, ii in stead.opairs(self) do
699		local o = stead.ref(v);
700		if not o then -- isObject(o) then -- compat
701			error ("No object: "..name.."["..stead.tostr(ii).."]".." ("..stead.tostr(stead.type(v))..")")
702			return false
703		end
704		if stead.deref(v) then
705			self[ii] = stead.deref(v);
706		end
707	end
708	return true;
709end
710
711stead.list_str = function(self)
712	local v, vv;
713	for i, o in stead.opairs(self) do
714		o = stead.ref(o);
715		if o~= nil and not isDisabled(o) then
716			vv = stead.call(o, 'nam');
717			vv = stead.xref(vv, o);
718			v = stead.par(',', v, vv);
719		end
720	end
721	return v;
722end
723
724
725stead.list_add = function(self, name, pos)
726	local nam
727	nam = stead.deref(name);
728	if self:look(nam) then
729		return nil
730	end
731	self.__modified__ = true;
732	if stead.tonum(pos) then
733		pos = stead.tonum(pos)
734		if pos <= #self then
735			stead.table.insert(self, pos, nam);
736		else
737			self[pos] = nam; -- for spare lists
738		end
739	else
740		stead.table.insert(self, nam);
741	end
742	return true
743end
744
745stead.list_set = function(self, name, pos)
746	local nam
747	local i = stead.tonum(pos);
748	if not i then
749		return nil
750	end
751	nam = stead.deref(name);
752	self.__modified__ = true;
753	self[i] = nam; -- for spare lists
754	return true
755end
756
757stead.list_find = function(self, name)
758	local o = stead.ref(name, true)
759	for n,v,ii in stead.opairs(self) do
760		if stead.ref(v) == o then -- do not call func while search
761			return ii;
762		end
763	end
764	return nil
765end
766
767stead.list_disable_all = function(s)
768	for k, v in stead.opairs(s) do
769		local o = stead.ref(v);
770		if isObject(o) then
771			o:disable()
772		end
773	end
774end
775
776stead.list_enable_all = function(s)
777	for k, v in stead.opairs(s) do
778		local o = stead.ref(v);
779		if isObject(o) then
780			o:enable()
781		end
782	end
783end
784
785stead.list_enable = function(s, w)
786	local o, i = stead.list_search(s, w, true);
787	o = stead.ref(o);
788	if isObject(o) then
789		o:enable()
790		return o
791	end
792end
793
794stead.list_disable = function(s, w)
795	local o, i = stead.list_search(s, w, true);
796	o = stead.ref(o);
797	if isObject(o) then
798		o:disable()
799		return o
800	end
801end
802
803stead.list_save = function(self, name, h, need)
804	if self.__modifyed__ or self.__modified__ then -- compat
805		h:write(name.." = list({});\n");
806		need = true;
807	end
808	stead.savemembers(h, self, name, need);
809end
810
811stead.list_name = function(self, name, dis)
812	for n, o, ii in stead.opairs(self) do
813		o = stead.ref(o);
814		if isObject(o) then
815			local nam = stead.call(o,'nam') ;
816			if ( not isDisabled(o) or dis ) and name == stead.tostr(nam) then
817				return ii;
818			end
819		end
820	end
821	return nil
822end
823stead.list_id = function(self, id, dis)
824	for n, o, ii in stead.opairs(self) do
825		o = stead.ref(o);
826		if dis or not isDisabled(o) then
827			if isObject(o) and id == o.id then
828				return ii;
829			end
830		end
831	end
832end
833
834stead.list_search = function(self, n, dis)
835	local i;
836	i = self:look(n);
837	if not i then
838		i = self:name(n, dis);
839	end
840	if not i and stead.tonum(n) then
841		i = self:byid(stead.tonum(n), dis);
842		if not i then
843			return nil
844		end
845	end
846	if not dis and isDisabled(stead.ref(self[i])) then
847		return nil;
848	end
849	return self[i], i;
850end
851
852stead.list_zap = function(self)
853	for n, o, ii in stead.opairs(self) do
854		self[ii] = nil;
855	end
856	self.__modified__ = true
857	return self
858end
859
860stead.list_concat = function(self, other, pos)
861	for n, o, ii in stead.opairs(other) do
862		o = stead.ref(o);
863		if pos == nil then
864			self:add(stead.deref(o));
865		else
866			self:add(stead.deref(o), pos);
867			pos = pos + 1;
868		end
869	end
870end
871
872stead.list_del = function(self, name)
873	local v,n
874	v, n = self:srch(name);
875	if n == nil then
876		return nil;
877	end
878	self.__modified__ = true
879	if n <= #self then
880		v = stead.table.remove(self, n);
881	else
882		v = self[n];
883		self[n] = nil -- for spare lists
884	end
885	return v
886end
887
888stead.list_purge = function(self, name)
889	local v,n
890	v, n = self:srch(name, true);
891	if n == nil then
892		return nil;
893	end
894	self.__modified__ = true
895	v = stead.table.remove(self, n);
896	if not v then
897		v = self[n];
898		self[n] = nil -- for spare lists
899	end
900	return v
901end
902
903stead.list_replace = function(self, name, name2)
904	local o, ii
905	o, ii = self:srch(name);
906	if ii then
907		self:set(name2, ii);
908	else
909		self:add(name2);
910	end
911	return ii;
912end
913
914function list(v)
915	v.list_type = true;
916	v.add = stead.list_add;
917	v.set = stead.list_set;
918	v.cat = stead.list_concat;
919	v.zap = stead.list_zap;
920	v.del = stead.list_del;
921	v.purge = stead.list_purge;
922	v.replace = stead.list_replace;
923	v.look = stead.list_find;
924	v.name = stead.list_name;
925	v.byid = stead.list_id;
926	v.srch = stead.list_search;
927	v.str = stead.list_str;
928	v.check = stead.list_check;
929	v.save = stead.list_save;
930	v.enable = stead.list_enable;
931	v.disable = stead.list_disable;
932	v.enable_all = stead.list_enable_all;
933	v.disable_all = stead.list_disable_all;
934	return v;
935end
936
937function isList(v)
938	return (stead.type(v) == 'table') and (v.list_type == true)
939end
940
941stead.call = function(v, n, ...)
942	if stead.type(v) ~= 'table' then
943		error ("Call on non table object:"..stead.tostr(n), 2);
944	end
945	if v[n] == nil then
946		return nil,nil;
947	end
948	if stead.type(v[n]) == 'string' then
949		return v[n];
950	end
951	if stead.type(v[n]) == 'function' then
952		stead.callpush(v, ...)
953		local a,b = v[n](v, ...);
954		-- boolean, nil
955		if stead.type(a) == 'boolean' and b == nil then
956			b, a = a, stead.pget()
957			if a == nil then
958				if stead.cctx().action then
959					a = true
960				else
961					a = b
962					b = nil
963				end
964			end
965		elseif a == nil and b == nil then
966			a = stead.pget()
967			b = nil
968		end
969		if a == nil and b == nil and stead.cctx().action then
970			a = true
971		end
972		stead.callpop()
973		return a,b
974	end
975	if stead.type(v[n]) == 'boolean' then
976		return v[n]
977	end
978	error ("Method not string nor function:"..stead.tostr(n), 2);
979end
980
981stead.call_bool = function(v, n, ...)
982	if stead.type(v) ~= 'table' then
983		error ("Call bool on non table object:"..n, 2);
984	end
985
986	if v[n] == nil then
987		return nil
988	end
989
990	if v[n] == false then
991		return false;
992	end
993
994	if stead.type(v[n]) == 'function' then
995		stead.callpush(v, ...)
996		local r,v = v[n](v, ...);
997		stead.callpop();
998		return r,v;
999	end
1000	return true; -- not nil
1001end
1002
1003stead.call_value = function(v, n, ...)
1004	if stead.type(v) ~= 'table' then
1005		error ("Call value on non table object:"..n, 2);
1006	end
1007
1008	if v[n] == nil then
1009		return nil
1010	end
1011
1012	if stead.type(v[n]) ~= 'function' then
1013		return v[n];
1014	end
1015	stead.callpush(v, ...)
1016	local r,v = v[n](v, ...);
1017	stead.callpop();
1018	return r,v;
1019end
1020
1021stead.room_scene = function(self)
1022	local v;
1023	v = iface:title(stead.call(self,'nam'));
1024	v = stead.par(stead.scene_delim, v, stead.call(self,'dsc')); --obj_look(self));
1025	return stead.cat(v, stead.space_delim);
1026end
1027
1028stead.room_look = function(self)
1029	local vv;
1030	for i, o in stead.opairs(self.obj) do
1031		o = stead.ref(o);
1032		if isObject(o) then
1033			vv = stead.par(stead.space_delim, vv, o:look());
1034		end
1035	end
1036	return stead.cat(vv, stead.space_delim);
1037end
1038
1039stead.obj_search = function(v, n, dis)
1040	local i;
1041	local o;
1042	if not dis and isDisabled(v) then
1043		return
1044	end
1045	o = v.obj:srch(n, dis);
1046	if o then
1047		return o, v;
1048	end
1049	for i, o in stead.opairs(v.obj) do
1050		o = stead.ref(o);
1051		if isObject(o) then
1052			local r,rr = stead.obj_search(o, n, dis);
1053			if r then
1054				return r, rr;
1055			end
1056		end
1057	end
1058	return;
1059end
1060
1061stead.room_save = function(self, name, h, need)
1062	local dsc;
1063	if need then
1064		print ("Warning: room "..name.." can not be saved!");
1065		return
1066	end
1067	stead.savemembers(h, self, name, need);
1068end
1069
1070function room(v) --constructor
1071--	if v.nam == nil then
1072--		error ("No room name in constructor.", 2);
1073--	end
1074	if v.scene == nil then
1075		v.scene = stead.room_scene;
1076	end
1077	if v.look == nil then
1078		v.look = stead.room_look;
1079	end
1080	if v.save == nil then
1081		v.save = stead.room_save;
1082	end
1083	v.location_type = true;
1084	if v.way == nil then
1085		v.way = { };
1086	end
1087	v.way = list(v.way);
1088	v = obj(v);
1089	return v;
1090end
1091
1092stead.dialog_enter = function(self)
1093	if not stead.dialog_rescan(self) then
1094		return nil, false
1095	end
1096	return nil, true
1097end
1098
1099stead.dialog_scene = function(self)
1100	local v
1101	v = iface:title(stead.call(self,'nam'));
1102	v = stead.par(stead.scene_delim, v, stead.call(self, 'dsc')); --obj_look(self));
1103	return v;
1104end
1105
1106stead.dialog_look = function(self)
1107	local n, v
1108	n = 1
1109	for i, ph in stead.opairs(self.obj) do
1110		ph = stead.ref(ph);
1111		if isPhrase(ph) and not isDisabled(ph) then
1112			v = stead.par('^', v, txtnm(n, ph:look()));
1113			n = n + 1
1114		end
1115	end
1116	return v;
1117end
1118
1119stead.dialog_rescan = function(self)
1120	local k
1121	k = 1
1122	for i, ph in stead.opairs(self.obj) do
1123		ph = stead.ref(ph);
1124		if isPhrase(ph) and not isDisabled(ph) then
1125			ph.nam = stead.tostr(k);
1126			k = k + 1;
1127		end
1128	end
1129	if k == 1 then
1130		return false
1131	end
1132	return true
1133end
1134
1135stead.dialog_empty = function(self)
1136	return not stead.dialog_rescan(self);
1137end
1138
1139stead.dialog_phrase = function(self, num)
1140	if not stead.tonum(num) then
1141		if isPhrase(stead.ref(num)) then
1142			return stead.ref(num);
1143		end
1144		return nil
1145	end
1146	return stead.ref(self.obj[stead.tonum(num)]);
1147end
1148
1149stead.phrase_seen = function(s, enb, ...)
1150	local ph
1151	local a = {...}
1152	if stead.table.maxn(a) == 0 then
1153		stead.table.insert(a, stead.cctx().self);
1154	end
1155	for i = 1,stead.table.maxn(a) do
1156		ph = stead.dialog_phrase(s, a[i]);
1157		local r = not isPhrase(ph) or isRemoved(ph) or ph:disabled();
1158		if not enb then r = not r end
1159		if r then return false end
1160	end
1161	return true
1162end
1163
1164stead.dialog_pseen = function(s, ...)
1165	return stead.phrase_seen(s, true, ...);
1166end
1167
1168stead.dialog_punseen = function(s, ...)
1169	return stead.phrase_seen(s, false, ...);
1170end
1171
1172local function ponoff(s, on, ...)
1173	local ph
1174	local a = {...}
1175	if stead.table.maxn(a) == 0 then
1176		stead.table.insert(a, stead.cctx().self)
1177	end
1178	for i = 1,stead.table.maxn(a) do
1179		ph = stead.dialog_phrase(s, a[i]);
1180		if isPhrase(ph) and not isRemoved(ph) then
1181			if on then
1182				ph:enable();
1183			else
1184				ph:disable();
1185			end
1186		end
1187	end
1188end
1189
1190stead.dialog_prem = function(s, ...)
1191	local ph
1192	local a = {...}
1193	if stead.table.maxn(a) == 0 then
1194		stead.table.insert(a, stead.cctx().self);
1195	end
1196	for i = 1,stead.table.maxn(a) do
1197		ph = stead.dialog_phrase(s, a[i]);
1198		if isPhrase(ph) then
1199			ph:remove();
1200		end
1201	end
1202end
1203
1204stead.dialog_pon = function(self,...)
1205	return ponoff(self, true, ...);
1206end
1207
1208stead.dialog_poff = function(self,...)
1209	return ponoff(self, false, ...);
1210end
1211
1212function dlg(v) --constructor
1213	v.dialog_type = true;
1214	if v.ini == nil then
1215		v.ini = stead.dialog_enter;
1216	end
1217	if v.enter == nil then
1218		v.enter = stead.dialog_enter;
1219	end
1220	if v.look == nil then
1221		v.look = stead.dialog_look;
1222	end
1223	if v.scene == nil then
1224		v.scene = stead.dialog_scene;
1225	end
1226	if v.pon == nil then
1227		v.pon = stead.dialog_pon;
1228	end
1229	if v.poff == nil then
1230		v.poff = stead.dialog_poff;
1231	end
1232	if v.prem == nil then
1233		v.prem = stead.dialog_prem;
1234	end
1235	if v.pseen == nil then
1236		v.pseen = stead.dialog_pseen;
1237	end
1238	if v.punseen == nil then
1239		v.punseen = stead.dialog_punseen;
1240	end
1241	if v.empty == nil then
1242		v.empty = stead.dialog_empty;
1243	end
1244	v = room(v);
1245	return v;
1246end
1247
1248stead.phrase_action = function(self)
1249	local ph = self;
1250	local r, ret;
1251
1252	if isDisabled(ph) then
1253		return nil, false
1254	end
1255-- here it is
1256	ph:disable(); -- /* disable it!!! */
1257
1258	local last = stead.call(ph, 'ans');
1259
1260	if stead.type(ph.do_act) == 'string' then
1261		local f = stead.eval(ph.do_act);
1262		if f ~= nil then
1263			ret = f();
1264		else
1265			error ("Error while eval phrase action.");
1266		end
1267	elseif stead.type(ph.do_act) == 'function' then
1268		ret = ph.do_act(self);
1269	end
1270
1271	if ret == nil then ret = stead.pget(); end
1272
1273	if last == true or ret == true then
1274		r = true;
1275	end
1276
1277	local wh = stead.here();
1278
1279	while isDialog(wh) and not stead.dialog_rescan(wh) and stead.from(wh) ~= wh do
1280		wh = stead.from(wh)
1281	end
1282
1283	if wh ~= stead.here() then
1284		ret = stead.par(stead.space_delim, ret, stead.back(wh));
1285	end
1286
1287	ret = stead.par(stead.scene_delim, last, ret);
1288
1289	if ret == nil then
1290		return r -- hack?
1291	end
1292	return ret
1293end
1294
1295stead.phrase_save = function(self, name, h, need)
1296	if need then
1297		local m = " = phr("
1298		if isDisabled(self) then
1299			m = " = _phr("
1300		end
1301		h:write(stead.string.format("%s%s%s,%s,%s);\n",
1302			name, m,
1303			stead.tostring(self.dsc),
1304			stead.tostring(self.ans),
1305			stead.tostring(self.do_act)));
1306	end
1307	stead.savemembers(h, self, name, false);
1308end
1309
1310stead.phrase_look = function(self, n)
1311	if isDisabled(self) then
1312		return
1313	end
1314	local v = stead.call(self, 'dsc');
1315	if stead.type(v) ~= 'string' then return; end
1316	if game.hinting then
1317		return self:xref('{'..v..'}');
1318	end
1319	return v;
1320end
1321
1322function phrase(o) --constructor
1323	local ret = o;
1324	ret.look = stead.phrase_look;
1325	ret.nam = ''; -- for start
1326	ret.phrase_type = true;
1327	ret.act = stead.phrase_action;
1328	ret.save = stead.phrase_save;
1329	ret = obj(ret);
1330	return ret;
1331end
1332
1333function _phr(ask, answ, act)
1334	local p = phrase ({ dsc = ask, ans = answ, do_act = act });
1335	p:disable();
1336	return p;
1337end
1338
1339function phr(ask, answ, act)
1340	local p = phrase ({ dsc = ask, ans = answ, do_act = act });
1341--	p:enable();
1342	return p;
1343end
1344
1345stead.player_inv = function(self)
1346	return iface:inv(stead.cat(self:str()));
1347end
1348
1349stead.player_ways = function(self)
1350	return iface:ways(stead.cat(stead.ref(self.where).way:str()));
1351end
1352
1353stead.player_objs = function(self)
1354	return iface:objs(stead.cat(stead.ref(self.where):str()));
1355end
1356
1357stead.player_look = function(self)
1358	return stead.ref(self.where):scene();
1359end
1360
1361stead.obj_tag = function(self, id)
1362	if isDisabled(self) then
1363		return id
1364	end
1365
1366	for k, v in stead.opairs(self.obj) do
1367		v = stead.ref(v);
1368		if isObject(v) and not isDisabled(v) and v.id ~= false then
1369			id = id + 1;
1370			v.id = id;
1371			id = stead.obj_tag(v, id);
1372		end
1373	end
1374	return id;
1375end
1376
1377stead.player_tagall = function(self)
1378	local id = 0;
1379	id = stead.obj_tag(stead.here(), id);
1380	for k, v in stead.opairs(ways()) do
1381		v = stead.ref(v);
1382		if isRoom(v) and not isDisabled(v) then
1383			id = id + 1;
1384			v.id = id;
1385		end
1386	end
1387	stead.rawset(_G, 'MENU_TAG_ID', id)
1388	id = stead.obj_tag(stead.me(), id);
1389end
1390
1391stead.player_action = function(self, what, ...)
1392	local v,r,obj
1393	obj = stead.ref(self.where):srch(what);
1394	if not obj then
1395		return stead.call(stead.ref(game), 'action', what, ...); --player_do(self, what, ...);
1396	end
1397	v, r = stead.player_take(self, what, ...);
1398	if not v then
1399		v, r = stead.call(stead.ref(obj), 'act', ...);
1400		if not v and r ~= true then
1401			v, r = stead.call(stead.ref(game), 'act', obj, ...);
1402		end
1403	end
1404	return v, r;
1405end
1406
1407stead.player_take = function(self, what, ...)
1408	local v,r,obj,w
1409	obj,w = stead.ref(self.where):srch(what);
1410	if not obj then
1411		return nil, false;
1412	end
1413	v,r = stead.call(stead.ref(obj), 'tak', ...);
1414	if v and r ~= false then
1415		take(obj, w);
1416	end
1417	return v;
1418end
1419
1420stead.player_use = function(self, what, onwhat, ...)
1421	local obj, obj2, v, vv, r;
1422	local scene_use_mode = false
1423
1424	obj = self:srch(what); -- in inv?
1425	if not obj then -- no
1426		obj = stead.ref(self.where):srch(what); -- in scene?
1427		if not obj then -- no!
1428			return game.err, false;
1429		end
1430		scene_use_mode = true -- scene_use_mode!
1431	end
1432	if onwhat == nil then -- only one?
1433		if scene_use_mode then
1434			return self:action(what, ...); -- call act
1435		else
1436			v, r = stead.call(stead.ref(obj),'inv', ...); -- call inv
1437		end
1438		if not v and r ~= true then
1439			v, r = stead.call(game, 'inv', obj, ...);
1440		end
1441		return v, r;
1442	end
1443	obj2 = stead.ref(self.where):srch(onwhat); -- in scene?
1444	if not obj2 then
1445		obj2 = self:srch(onwhat); -- in inv?
1446	end
1447	if not obj2 or obj2 == obj then
1448		return game.err, false;
1449	end
1450	if not scene_use_mode or isSceneUse(stead.ref(obj)) then
1451		v, r = stead.call(stead.ref(obj), 'use', obj2, ...);
1452		if r ~= false then
1453			vv = stead.call(stead.ref(obj2), 'used', obj, ...);
1454		end
1455	end
1456	if not v and not vv then
1457		v, r = stead.call(game, 'use', obj, obj2, ...);
1458	end
1459	return stead.par(stead.space_delim, v, vv);
1460end
1461
1462stead.player_back = function(self)
1463	local where = stead.ref(self.where);
1464	if where == nil then
1465		return nil,false
1466	end
1467	return stead.go(self, where.__from__, true);
1468end
1469
1470stead.go = function(self, where, back)
1471	local was = self.where;
1472	local need_scene = false;
1473	local ret
1474
1475	if not stead.in_walk_call then
1476		ret = function(rc) stead.in_walk_call = false return nil end
1477	else
1478		ret = function(rc) return rc end
1479	end
1480
1481	stead.in_walk_call = true
1482
1483	if where == nil then
1484		return nil,ret(false)
1485	end
1486	if not isRoom(stead.ref(where)) then
1487		error ("Trying to go nowhere: "..where, 2);
1488	end
1489	if not isRoom(stead.ref(self.where)) then
1490		error ("Trying to go from nowhere: "..self.where, 2);
1491	end
1492
1493	if stead.in_entered_call or stead.in_onexit_call then
1494		error ("Do not use walk from onexit/entered action! Use exit/enter action instead:" .. self.where, 2);
1495	end
1496
1497	local v, r;
1498	if not isVroom(stead.ref(where)) and not stead.in_exit_call then
1499		stead.in_exit_call = true -- to break recurse
1500		v,r = stead.call(stead.ref(self.where), 'exit', where);
1501		stead.in_exit_call = nil
1502		if r == false then
1503			return v, ret(r)
1504		end
1505	end
1506
1507	local res = v;
1508
1509	v = nil;
1510	if not back or not isDialog(stead.ref(self.where)) or isDialog(stead.ref(where)) then
1511		v, r = stead.call(stead.ref(where), 'enter', self.where);
1512		if r == false then
1513			return v, ret(r)
1514		end
1515		need_scene = true;
1516		if stead.ref(was) ~= stead.ref(self.where) then -- jump !!!
1517			where = stead.deref(self.where);
1518			need_scene = false;
1519		end
1520	end
1521	res = stead.par(stead.scene_delim, res, v);
1522
1523	if not back then
1524		stead.ref(where).__from__ = stead.deref(self.where);
1525	end
1526
1527	self.where = stead.deref(where);
1528
1529	ret();
1530
1531	stead.rawset(_G, 'PLAYER_MOVED', true)
1532	if need_scene then -- or isForcedsc(stead.ref(where)) then -- i'am not sure...
1533		return stead.par(stead.scene_delim, res, stead.ref(where):scene());
1534	end
1535	return res;
1536end
1537
1538stead.player_walk = function(self, where, ...)
1539	local v, r = stead.go(self, where, ...);
1540	return v, r;
1541end
1542
1543stead.player_go = function(self, where)
1544	local w = stead.ref(self.where).way:srch(where);
1545	if not w then
1546		return nil,false
1547	end
1548	local v, r = stead.go(self, w, false);
1549	return v, r;
1550end
1551
1552stead.player_save = function(self, name, h)
1553	h:write(stead.string.format('%s.where = %q;\n', stead.tostr(name), stead.deref(self.where)));
1554	stead.savemembers(h, self, name, false);
1555end
1556
1557function player(v)
1558	if v.nam == nil then
1559		error ("No player name in constructor.", 2);
1560	end
1561	if v.where == nil then
1562		v.where = 'main';
1563	end
1564	if v.tag == nil then
1565		v.tag = stead.player_tagall;
1566	end
1567	if v.walk == nil then
1568		v.walk = stead.player_walk;
1569	end
1570	if v.go == nil then
1571		v.go = stead.player_go;
1572	end
1573	if v.ways == nil then
1574		v.ways = stead.player_ways;
1575	end
1576	if v.back == nil then
1577		v.back = stead.player_back;
1578	end
1579	if v.look == nil then
1580		v.look = stead.player_look;
1581	end
1582	if v.inv == nil then
1583		v.inv = stead.player_inv;
1584	end
1585	if v.use == nil then
1586		v.use = stead.player_use;
1587	end
1588	if v.action == nil then
1589		v.action = stead.player_action;
1590	end
1591	if v.save == nil then
1592		v.save = stead.player_save;
1593	end
1594	if v.objs == nil then
1595		v.objs = stead.player_objs;
1596	end
1597	v.player_type = true;
1598	return obj(v);
1599end
1600
1601stead.game_life = function(self)
1602	local av, v
1603	stead.in_life_call = true;
1604	stead.in_life_move = false
1605	stead.lifes_op = {}; -- lifes to on/off
1606	stead.PLAYER_MOVED = stead.rawget(_G, 'PLAYER_MOVED')
1607	for i, o in stead.opairs(self.lifes) do
1608		local vv
1609		local pre
1610		o = stead.ref(o);
1611		if not isDisabled(o) then
1612			stead.rawset(_G, 'PLAYER_MOVED', false)
1613			vv,pre = stead.call(o, 'life');
1614			if stead.rawget(_G, 'PLAYER_MOVED') then -- clear life output, but not current
1615				av = nil
1616				v = nil
1617				stead.in_life_move = true
1618				stead.rawset(_G, 'ACTION_TEXT', vv);
1619			elseif pre then
1620				av = stead.par(stead.space_delim, av, vv);
1621			else
1622				v = stead.par(stead.space_delim, v, vv);
1623			end
1624		end
1625	end
1626	stead.rawset(_G, 'PLAYER_MOVED', stead.in_life_move)
1627	if not stead.rawget(_G, 'PLAYER_MOVED') then stead.rawset(_G, 'PLAYER_MOVED', stead.PLAYER_MOVED) end
1628	stead.PLAYER_MOVED = nil
1629	stead.in_life_call = false;
1630	for i,o in stead.ipairs(stead.lifes_op) do
1631		if o[1] then
1632			stead.lifeon(o[2], o[3]);
1633		else
1634			stead.lifeoff(o[2]);
1635		end
1636	end
1637	stead.lifes_op = nil;
1638	return v, av;
1639end
1640
1641stead.player_moved = function()
1642	return stead.rawget(_G, 'PLAYER_MOVED') or stead.PLAYER_MOVED
1643end
1644
1645stead.life_moved = function()
1646	return stead.in_life_move
1647end
1648
1649stead.check_list = function(k, v, p)
1650	if v.check == nil or not v:check(stead.string.format("%s[%q]", p, k)) then
1651		error ("error in list: "..stead.object..'.'..k);
1652	end
1653end
1654
1655stead.check_room = function(k, v)
1656	if v.obj == nil then
1657		error("no obj in room:"..k);
1658	end
1659	if v.way == nil then
1660		error("no way in room:"..k);
1661	end
1662end
1663
1664stead.check_player = function(k, v)
1665	v.where = stead.deref(v.where);
1666end
1667
1668stead.check_object = function(k, v)
1669	if not v.nam then
1670		error ("No name in "..k);
1671	end
1672	if isRoom(v) then
1673		stead.check_room(k, v);
1674	end
1675	if isPlayer(v) then
1676		stead.check_player(k, v);
1677	end
1678	for_each(v, k, stead.check_list, isList, stead.deref(v))
1679end
1680
1681function for_everything(f, ...)
1682	local is_ok = function(s)
1683		return true
1684	end
1685	for_each(_G, '_G', f, is_ok, ...)
1686end
1687
1688local compat_api = function()
1689	if stead.compat_api then
1690		return
1691	end
1692
1693	if not stead.api_atleast(1, 6, 0) then
1694		if not stead.rawget(_G, 'go') then
1695			go = stead.go
1696		end
1697		if not stead.rawget(_G, 'goin') then
1698			goin = walkin
1699		end
1700		if not stead.rawget(_G, 'goout') then
1701			goout = walkout
1702		end
1703		if not stead.rawget(_G, 'goback') then
1704			goback = walkback
1705		end
1706		if not stead.rawget(_G, "goto") then
1707			if _VERSION == "Lua 5.1" then -- 5.1 lua
1708				stead.rawset(_G, "goto", walk)
1709			end
1710		end
1711	end
1712
1713	if not stead.api_atleast(1, 7, 1) then
1714		if not stead.rawget(_G, 'goin') then
1715			goin = function() error ("Please use 'walkin' instead 'goin'.", 2) end
1716		end
1717		if not stead.rawget(_G, 'goout') then
1718			goout = function() error ("Please use 'walkout' instead 'goout'.", 2) end
1719		end
1720		if not stead.rawget(_G, 'goback') then
1721			goback = function() error ("Please use 'walkback' instead 'goback'.", 2) end
1722		end
1723		if not stead.rawget(_G, "goto") then
1724			if _VERSION == "Lua 5.1" then -- 5.1 lua
1725				stead.rawset(_G, "goto", function() error ("Please use 'walk' instead 'goto'.", 2) end)
1726			end
1727		end
1728
1729		get_savepath = instead_savepath
1730		get_gamepath = instead_gamepath
1731		get_steadpath = instead_steadpath
1732		get_gamespath = instead_gamespath
1733
1734		menu_toggle = instead_menu_toggle
1735		readdir = instead_readdir
1736
1737		call = stead.call
1738		call_bool = stead.call_bool
1739		call_value = stead.call_value
1740
1741		get_title = stead.get_title
1742		get_picture = stead.get_picture
1743		get_inv = stead.get_inv
1744		get_ways = stead.get_ways
1745
1746		get_autosave = stead.get_autosave
1747
1748		fmt = stead.fmt
1749
1750		obj_tag = stead.obj_tag
1751
1752		module_init = stead.module_init
1753
1754		player_inv = stead.player_inv
1755		dialog_enter = stead.dialog_enter
1756	end
1757
1758	if not stead.api_atleast(1, 4, 5) then
1759		stead.xref = function(...)
1760			return xref(...);
1761		end
1762
1763		-- internals of call
1764		cctx = stead.cctx
1765		callpush = stead.callpush
1766		callpop = stead.callpop
1767		clearargs = stead.clearargs
1768		-- saving
1769		savemembers = stead.savemembers;
1770		savevar = stead.savevar
1771		clearvar = stead.clearvar
1772	end
1773
1774	stead.compat_api = true
1775end
1776
1777stead.do_ini = function(self, load)
1778	local v = ''
1779	local vv
1780	local function call_key(k, o)
1781		o.key_name = k;
1782	end
1783	local function call_codekey(k, o)
1784		stead.functions[o].key_name = k;
1785	end
1786	local function call_ini(k, o, ...)
1787		v = stead.par('', v, stead.call(o, 'ini', ...));
1788	end
1789	stead.math.randomseed(stead.os.time(stead.os.date("*t")))
1790	stead.rnd(1); stead.rnd(2); stead.rnd(3); -- Lua bug?
1791	if stead.type(game) ~= 'table' then
1792		error ("No valid 'game' object.");
1793	end
1794	if not isPlayer(stead.me()) then
1795		error ("No valid player.");
1796	end
1797	if not isRoom(stead.here()) then
1798		error ("No valid room.");
1799	end
1800	game.pl = stead.deref(game.pl);
1801	stead.me().where = stead.deref(stead.me().where);
1802--	game.where = stead.deref(game.where);
1803
1804	for i, f in ipairs(stead.modules_start) do
1805		f(load)
1806	end
1807
1808	if not load then
1809		compat_api()
1810		for_everything(function(k, s)
1811			if isObject(s) then
1812				call_key(k, s)
1813			elseif isCode(s) then
1814				call_codekey(k, s)
1815			end
1816		end)
1817		for_each_object(stead.check_object);
1818		call_key("game", game);
1819		for_each(game, "game", stead.check_list, isList, stead.deref(game))
1820	end
1821
1822	for_each_object(call_ini, load);
1823	stead.me():tag();
1824	stead.initialized = true
1825	return v
1826end
1827
1828stead.game_ini = function(self)
1829	local v,vv
1830	v = stead.do_ini(self);
1831	vv = iface:title(stead.call(self,'nam'));
1832	vv = stead.par(stead.scene_delim, vv, stead.call(self,'dsc'));
1833	if stead.type(stead.rawget(_G, 'init')) == 'function' then
1834		init();
1835	end
1836	return stead:fmt(stead.par(stead.scene_delim, vv, v));
1837end
1838
1839stead.game_start = function(s)
1840	if stead.type(stead.rawget(_G, 'start')) == 'function' then
1841		start() -- start function
1842	end
1843	stead.started = true
1844	if not s.showlast then
1845		stead.last_disp(false)
1846	end
1847	return stead.cat('', stead.last_disp())
1848end
1849
1850function game(v)
1851	if v.nam == nil then
1852		error ("No game name in constructor.", 2);
1853	end
1854	if v.pl == nil then
1855		v.pl = 'player';
1856	end
1857	if v.ini == nil then
1858		v.ini = stead.game_ini;
1859	end
1860	if v.start == nil then
1861		v.start = stead.game_start
1862	end
1863	if v.save == nil then
1864		v.save = stead.game_save;
1865	end
1866	if v.load == nil then
1867		v.load = stead.game_load;
1868	end
1869	if v.life == nil then
1870		v.life = stead.game_life;
1871	end
1872	if v.step == nil then
1873		v.step = stead.game_step;
1874	end
1875	if v.lifes == nil then
1876		v.lifes = {};
1877	end
1878	v.lifes = list(v.lifes);
1879	v._time = 0;
1880	v._running = true;
1881	v.game_type = true;
1882	return v;
1883end
1884
1885function live(v)
1886	return stead.ref(game.lifes:srch(v));
1887end
1888
1889function isEnableSave()
1890	if game.enable_save == nil or stead.get_autosave() then
1891		return true
1892	end
1893	return stead.call_bool(game, 'enable_save');
1894end
1895
1896function isEnableAutosave()
1897	if game.enable_autosave == nil then
1898		return true
1899	end
1900	return stead.call_bool(game, 'enable_autosave');
1901end
1902
1903function for_each(o, n, f, fv, ...)
1904	local call_list = {}
1905
1906	if stead.type(o) ~= 'table' then
1907		return
1908	end
1909	stead.object = n;
1910
1911	for k, v in stead.pairs(o) do
1912		if v ~= _G and fv(v) then
1913			stead.table.insert(call_list, { k = k, v = v });
1914		end
1915	end
1916
1917	for k, v in stead.ipairs(call_list) do
1918		f(v.k, v.v, ...);
1919	end
1920end
1921
1922function isCode(s)
1923	return stead.type(s) == 'function' and stead.type(stead.functions[s]) == 'table'
1924end
1925function for_each_codeblock(f,...)
1926	for_each(_G, '_G', f, isCode, ...)
1927end
1928
1929function for_each_object(f,...)
1930	for_each(_G, '_G', f, isObject, ...)
1931end
1932
1933function for_each_player(f,...)
1934	for_each(_G, '_G', f, isPlayer, ...)
1935end
1936
1937function for_each_room(f,...)
1938	for_each(_G, '_G', f, isRoom, ...)
1939end
1940
1941function for_each_list(f,...)
1942	for_each(_G, '_G', f, isList, ...)
1943end
1944
1945stead.clearvar = function(v)
1946	for k, o in stead.pairs(v) do
1947		if stead.type(o) == 'table' and o ~= _G and o.__visited__ ~= nil then
1948			o.__visited__ = nil
1949			o.auto_saved = nil
1950			stead.clearvar(o)
1951		end
1952	end
1953end
1954
1955stead.savemembers = function(h, self, name, need)
1956	for k, v in stead.pairs(self) do
1957		local need2
1958		if k ~= "__visited__" then
1959			need2 = false
1960			if isForSave(k, v, self) then
1961				need2 = true;
1962			end
1963
1964			if stead.type(k) == 'string' then
1965				stead.savevar(h, v, name..'['..stead.string.format("%q",k)..']', need or need2);
1966			elseif stead.type(k) == 'number' then
1967				stead.savevar(h, v, name.."["..k.."]", need or need2)
1968			elseif stead.type(k) == 'table' and stead.type(k.key_name) == 'string' then
1969				stead.savevar(h, v, name.."["..k.key_name.."]", need or need2)
1970			end
1971		end
1972	end
1973end
1974-- savemembers = stead.savemembers;
1975
1976stead.savevar = function(h, v, n, need)
1977	local r,f
1978
1979	if v == nil or stead.type(v) == "userdata" or
1980			 stead.type(v) == "function" then
1981		if isCode(v) and need then
1982			if stead.type(stead.functions[v].key_name) == 'string'
1983				and stead.functions[v].key_name ~= n then
1984				h:write(stead.string.format("%s=%s\n", n, stead.functions[v].key_name))
1985			else
1986				h:write(stead.string.format("%s=code %q\n", n, stead.functions[v].code))
1987			end
1988		end
1989--		if need then
1990--			error ("Variable "..n.." can not be saved!");
1991--		end
1992		return
1993	end
1994
1995--	if stead.string.find(n, '_') ==  1 or stead.string.match(n,'^%u') then
1996--		need = true;
1997--	end
1998
1999	if stead.type(v) == "string" then
2000		if not need then
2001			return
2002		end
2003		h:write(stead.string.format("%s=%q\n",n,v))
2004		return;
2005	end
2006
2007	if stead.type(v) == "table" then
2008		if v == _G then return end
2009		if stead.type(v.key_name) == 'string' and v.key_name ~= n then -- just xref
2010			if v.auto_allocated and not v.auto_saved then
2011				v:save(v.key_name, h, false, true); -- here todo
2012			end
2013			if need then
2014				if stead.ref(v.key_name) == nil then
2015					v.key_name = 'null'
2016				end
2017				h:write(stead.string.format("%s = %s\n", n, v.key_name));
2018			end
2019			return
2020		end
2021		if v.__visited__ ~= nil then
2022			return
2023		end
2024
2025		v.__visited__ = n;
2026
2027		if stead.type(v.save) == 'function' then
2028			v:save(n, h, need);
2029			return;
2030		end
2031
2032		if need then
2033			h:write(n.." = {};\n");
2034		end
2035
2036		stead.savemembers(h, v, n, need);
2037		return;
2038	end
2039
2040	if not need then
2041		return
2042	end
2043	h:write(n, " = ",tostring(v))
2044	h:write("\n")
2045end
2046-- savevar = stead.savevar
2047
2048stead.gamereset = function(file, forget)
2049	stead.clearargs()
2050	if stead.api_atleast(2, 2, 0) then
2051		init = function() -- init called only once
2052		end
2053	end
2054	if forget then
2055		stead:done();
2056		stead.rawset(_G, 'init', function() -- null init function
2057		end)
2058		stead.rawset(_G, 'start', function() -- null start function
2059		end)
2060		for_each_object(function(k, o) -- destroy all objects
2061			if o.system_type then
2062				return
2063			end
2064			stead.rawset(_G, k, nil)
2065		end);
2066		game._scripts = { }
2067		game.lifes:zap()
2068		game.scriptsforget = true
2069		stead.collectgarbage()
2070		-- anything else?
2071		stead:init();
2072	end
2073	dofile(file);
2074	game:ini();
2075
2076	if #game._scripts == 0 or file ~= game._scripts[#game._scripts] then
2077		if #game._scripts ~= 0 or file ~= 'main.lua' then
2078			stead.table.insert(game._scripts, file);
2079		end
2080	end
2081end
2082
2083stead.gamefile = function(file, forget)
2084	stead.gamereset(file, forget)
2085	if forget then
2086		game:start()
2087		return stead.walk(stead.here(), false, false, true);
2088	end
2089end
2090
2091
2092stead.do_savegame = function(s, h)
2093	stead.busy(true)
2094	local function save_object(key, value, h)
2095		stead.busy(true)
2096		stead.savevar(h, value, key, false);
2097	end
2098	local function save_var(key, value, h)
2099		stead.busy(true)
2100		stead.savevar(h, value, key, isForSave(key, value, _G))
2101	end
2102	local forget = game.scriptsforget
2103	for i, v in stead.ipairs(s._scripts) do
2104		h:write(stead.string.format("stead.gamereset(%q,%s)\n",
2105			v, stead.tostr(forget)))
2106		forget = nil
2107	end
2108	save_object('allocator', allocator, h); -- always first!
2109	for_each_object(save_object, h);
2110	save_object('game', s, h);
2111	for_everything(save_var, h);
2112--	save_object('_G', _G, h);
2113	stead.clearvar(_G);
2114	stead.busy(false)
2115end
2116
2117stead.savename = function()
2118	return stead.call(stead.here(), 'nam');
2119end
2120
2121stead.game_save = function(self, name, file)
2122	local h;
2123
2124	if file ~= nil then
2125		file:write(stead.string.format("%s.pl = %q\n", name, stead.deref(self.pl)));
2126		stead.savemembers(file, self, name, false);
2127		return nil, true
2128	end
2129
2130	if not isEnableSave() then
2131		return nil, false
2132	end
2133
2134	if name == nil then
2135		return nil, false
2136	end
2137	h = stead.io.open(name .. '.tmp', "wb");
2138	if not h then
2139		return nil, false
2140	end
2141	local n
2142	if stead.type(stead.savename) == 'function' then
2143		n = stead.savename()
2144	end
2145	if stead.type(n) == 'string' and n ~= "" then
2146		h:write("-- $Name: "..n:gsub("\n","\\n").."$\n");
2147	end
2148	stead.do_savegame(self, h);
2149	h:flush();
2150	h:close();
2151	stead.os.remove(name);
2152	stead.os.rename(name .. '.tmp', name);
2153	game.autosave = false; -- we have only one try for autosave
2154	stead.restart_game = false
2155	return nil;
2156end
2157
2158stead.game_load = function(self, name)
2159	if name == nil then
2160		return nil, false
2161	end
2162
2163	if stead.started then
2164		stead.gamereset('main.lua', true)
2165	end
2166
2167	local f, err = loadfile(name);
2168	if f then
2169		local i,r = f();
2170		if r then
2171			return nil, false
2172		end
2173		i, r = stead.do_ini(self, true);
2174		if not stead.started then
2175			i, r = game:start()
2176		end
2177		return i, r
2178	end
2179	return nil, false
2180end
2181
2182
2183stead.game_step = function(self)
2184	self._time = self._time + 1;
2185	return self:life(self);
2186end
2187
2188
2189game = game {
2190	codepage = "UTF-8";
2191	nam = [[INSTEAD -- Simple Text Adventure interpreter v]]..stead.version..[[ '2009-2020 by Peter Kosyh]];
2192	dsc = [[
2193Commands:^
2194    look(or just enter), act <on what> (or just what), use <what> [on what], go <where>,^
2195    back, inv, way, obj, quit, save <fname>, load <fname>.]];
2196	pl ='pl';
2197	showlast = true;
2198	_scripts = {};
2199};
2200
2201stead.strip = function(s)
2202	local s = stead.tostr(s);
2203	s = stead.string.gsub(s, '^[ \t]*', '');
2204	s = stead.string.gsub(s, '[ \t]*$', '');
2205	return s;
2206end
2207
2208function isForcedsc(v)
2209	local r,g
2210	r = stead.call_bool(v, 'forcedsc');
2211	if r then
2212		return true
2213	end
2214	g = stead.call_bool(game, 'forcedsc', v);
2215	return g and r ~= false
2216end
2217
2218function isSceneUse(v)
2219	local o,g
2220	o = stead.call_bool(v, 'scene_use');
2221	if o then
2222		return true
2223	end
2224	g = stead.call_bool(game, 'scene_use', v);
2225	return g and o ~= false
2226end
2227
2228iface = {
2229	anchor = function(self)
2230		return '';
2231	end;
2232	img = function(self, str)
2233		return '';
2234	end,
2235	nb = function(self, str)
2236		return str;
2237	end,
2238	em = function(self, str)
2239		return str;
2240	end,
2241	right = function(self, str)
2242		return str;
2243	end,
2244	left = function(self, str)
2245		return str;
2246	end,
2247	center = function(self, str)
2248		return str;
2249	end,
2250	just = function(self, str)
2251		return str;
2252	end,
2253	top = function(self, str)
2254		return str;
2255	end,
2256	bottom = function(self, str)
2257		return str;
2258	end,
2259	middle = function(self, str)
2260		return str;
2261	end,
2262	tab = function(self, str, al)
2263		return '';
2264	end;
2265	bold = function(self, str)
2266		return str;
2267	end,
2268	under = function(self, str)
2269		return str;
2270	end,
2271	st = function(self, str)
2272		return str;
2273	end,
2274	enum = function(self, n, str)
2275		return n..' - '..str;
2276	end,
2277	xref = function(self, str, obj)
2278		local o = stead.ref(stead.here():srch(obj));
2279		if not o then
2280			o = stead.ref(ways():srch(obj));
2281		end
2282		if not o then
2283			o = stead.ref(stead.me():srch(obj));
2284		end
2285		if not o or not o.id then
2286			return str;
2287		end
2288		local n = stead.tonum(stead.nameof(o))
2289		return stead.cat(str, "("..stead.tostr(n or o.id)..")");
2290	end,
2291	title = function(self, str)
2292		return "["..str.."]";
2293	end,
2294	objs = function(self, str)
2295		return str;
2296	end,
2297	ways = function(self, str)
2298		return str;
2299	end,
2300	inv = function(self, str)
2301		return str;
2302	end,
2303	text = function(self, str)
2304		if str then
2305			print(str);
2306		end
2307	end,
2308	fmt = function(self, cmd, st, moved, r, av, objs, pv) -- st -- changed state (main win), move -- loc changed
2309		local l, vv
2310		if st and not moved then
2311			if cmd ~= 'look' then
2312				av = txtem(av);
2313				pv = txtem(pv);
2314				r  = txtem(r);
2315				if isForcedsc(stead.here()) then
2316					l = stead.me():look();
2317				end
2318			end
2319		end
2320		vv = stead.fmt(stead.cat(stead.par(stead.scene_delim, l, r, av, objs, pv), '^'));
2321		return vv
2322	end,
2323	cmd = function(self, inp)
2324		local r, v;
2325		v = false
2326		stead.state = false; -- changed state (main screen)
2327		local a = { };
2328		local cmd;
2329
2330		stead.rawset(_G, 'RAW_TEXT', nil)
2331		stead.rawset(_G, 'PLAYER_MOVED', nil)
2332		stead.cache = {}
2333		cmd, a = stead.getcmd(inp);
2334
2335		for i, f in ipairs(stead.modules_cmd) do
2336			local r, v = f(cmd, stead.unpack(a))
2337			if r ~= nil or v ~= nil then
2338				return r, v
2339			end
2340		end
2341		if cmd == '' then cmd = 'look' end
2342--		stead.me():tag();
2343		local oldloc = stead.here();
2344		if cmd == 'look' then
2345			stead.state = true
2346			r, v = stead.me():look();
2347		elseif cmd == 'obj' then
2348			r, v = stead.me():objs();
2349		elseif cmd == 'inv' then
2350			r, v = stead.me():inv();
2351		elseif cmd == 'way' then
2352			r, v = stead.me():ways();
2353		elseif cmd == 'ls' then
2354			r = stead.par(stead.scene_delim, stead.me():objs(), stead.me():inv(), stead.me():ways());
2355			v = nil;
2356		elseif cmd == 'go' then
2357			stead.state = true
2358			r, v = stead.me():go(stead.unpack(a));
2359		elseif cmd == 'back' then
2360			stead.state = true
2361			r, v = stead.me():go(stead.from());
2362		elseif cmd == 'act' then
2363			stead.state = true
2364			r, v = stead.me():action(stead.unpack(a));
2365		elseif cmd == 'use' then
2366			stead.state = true
2367			r, v = stead.me():use(stead.unpack(a));
2368		elseif cmd == 'save' then
2369			r, v = game:save(stead.unpack(a));
2370		elseif cmd == 'load' then
2371			r, v = game:load(stead.unpack(a));
2372			if v ~= false and game.showlast then
2373				return r;
2374			end
2375		elseif cmd == 'wait' then -- nothing todo in game, skip tick
2376			v = nil;
2377			r = true;
2378			stead.state = true
2379		elseif cmd == 'nop' then -- inv only
2380			v = true;
2381			r = nil;
2382			stead.state = true
2383		else
2384			stead.state = true
2385			r, v = stead.me():action(cmd, stead.unpack(a));
2386		end
2387		-- here r is action result, v - ret code value
2388		-- state -- game state changed
2389		if stead.state and r == nil and v == true then -- we do nothing
2390			return nil, true; -- menu
2391		end
2392
2393		if stead.state and r == nil and v == nil and stead.api_atleast(1, 3, 5) then -- new goto
2394			return nil, false -- really nothing
2395		end
2396
2397		if stead.rawget(_G, 'RAW_TEXT') and v ~= false then
2398			return stead.cat(r, '\n'), true;
2399		end
2400
2401		if v == false then
2402			return stead.cat(r, '\n'), false;
2403		end
2404
2405		stead.rawset(_G, 'ACTION_TEXT', r); -- here, life methods can redefine this
2406
2407		local av, pv -- av -- active lifes, pv -- background
2408		local vv
2409
2410		if stead.state then
2411			pv,av = game:step();
2412			stead.me():tag();
2413			vv = stead.here():look();
2414		end
2415
2416		vv = self:fmt(cmd, stead.state, (oldloc ~= stead.here()) or stead.player_moved(),
2417			stead.act_text(), av, vv, pv);
2418
2419		if stead.state then
2420			stead.last_disp(vv or false)
2421			stead.last_act(stead.act_text())
2422		end
2423		if vv == nil then -- nil is error
2424			vv = ''
2425		end
2426		return vv, true; -- action is here
2427	end,
2428	shell = function(self)
2429		local inp, i, k, cmd, a, n;
2430		stead.me():tag();
2431		while game._running do
2432			inp = stead.io.read("*l");
2433			if inp == 'quit' then
2434				break;
2435			end
2436			self:text(self:cmd(inp));
2437		end
2438	end
2439};
2440
2441
2442function me()
2443	return stead.ref(game.pl);
2444end
2445stead.me = me
2446
2447function where(s)
2448	if not isObject(stead.ref(s)) then error("Wrong parameter to where.", 2); end
2449	if isPlayer(stead.ref(s)) then
2450		return stead.ref(stead.ref(s).where);
2451	end
2452	return stead.ref(stead.ref(s).__where__);
2453end
2454
2455function here()
2456	return stead.ref(stead.me().where);
2457end
2458stead.here = here
2459
2460function from(w)
2461	if w == nil then
2462		w = stead.here();
2463	else
2464		w = stead.ref(w);
2465	end
2466	return stead.ref(w.__from__);
2467end
2468stead.from = from
2469
2470stead.time = function(s)
2471	local n = game._time;
2472	if stead.type(s) == 'number' then
2473		game._time = s
2474	end
2475	return n
2476end
2477
2478function inv()
2479	return stead.me().obj;
2480end
2481
2482function objs(w)
2483	if not w then
2484		return stead.here().obj;
2485	else
2486		return stead.ref(w).obj;
2487	end
2488end
2489
2490function ways(w)
2491	if not w then
2492		return stead.here().way;
2493	else
2494		return stead.ref(w).way;
2495	end
2496end
2497
2498stead.xref = function(str, obj, ...)
2499	if stead.type(str) ~= 'string' then return nil; end;
2500	return iface:xref(str, obj, ...);
2501end
2502xref = stead.xref
2503
2504function pseen(...)
2505	if not isDialog(stead.here()) then
2506		return
2507	end
2508	return stead.here():pseen(...);
2509end
2510
2511function punseen(...)
2512	if not isDialog(stead.here()) then
2513		return
2514	end
2515	return stead.here():punseen(...);
2516end
2517
2518function pon(...)
2519	if not isDialog(stead.here()) then
2520		return
2521	end
2522	stead.here():pon(...);
2523end
2524
2525function poff(...)
2526	if not isDialog(stead.here()) then
2527		return
2528	end
2529	stead.here():poff(...);
2530end
2531
2532function prem(...)
2533	if not isDialog(stead.here()) then
2534		return
2535	end
2536	stead.here():prem(...);
2537end
2538
2539function lifeon(what, nr)
2540	if stead.in_life_call then
2541		stead.table.insert(stead.lifes_op, { true, what, nr });
2542		return
2543	end
2544	game.lifes:add(what, nr);
2545end
2546stead.lifeon = lifeon
2547
2548function lifeoff(what)
2549	if stead.in_life_call then
2550		stead.table.insert(stead.lifes_op, { false, what });
2551		return
2552	end
2553	game.lifes:del(what);
2554end
2555stead.lifeoff = lifeoff
2556
2557stead.allocator_save = function(s, name, h, need, auto)
2558	if s.auto_allocated and not auto then
2559		return
2560	end
2561	if need then
2562		if s.auto_allocated then -- in current realization always false
2563			local m = stead.string.format("allocator:new(%s, %s)\n",
2564				stead.tostring(s.constructor),
2565				stead.tostring(s.constructor));
2566			h:write(m);
2567		else
2568			local m = stead.string.format(" = allocator:get(%s, %s)\n",
2569				stead.tostring(name),
2570				stead.tostring(s.constructor));
2571			h:write(name..m);
2572			if stead.api_atleast(1, 3, 0) then
2573				m = stead.string.format("stead.check_object(%s, %s)\n",
2574					stead.tostring(name),
2575					name);
2576				h:write(m);
2577			end
2578		end
2579	end
2580	stead.savemembers(h, s, name, false);
2581	if s.auto_allocated then
2582		s.auto_saved = true
2583	end
2584end
2585
2586function new(str)
2587	if stead.type(str) ~= 'string' then
2588		error("Non string constructor in new.", 2);
2589	end
2590	return allocator:new(str);
2591end
2592
2593function delete(v)
2594	allocator:delete(v);
2595end
2596
2597stead.vobj_save = function(self, name, h, need)
2598	local dsc = self.dsc;
2599	local w = stead.deref(self.where);
2600
2601	if need then
2602		h:write(stead.string.format("%s  = vobj(%s, %s, %s, %s);\n",
2603			name,
2604			stead.tostring(self.key),
2605			stead.tostring(self.nam),
2606			stead.tostring(dsc),
2607			stead.tostring(w)));
2608
2609	end
2610	stead.savemembers(h, self, name,false);
2611end
2612
2613stead.vobj_act = function(self, ...)
2614	local o, r = stead.here():srch(self); -- self.nam
2615	if stead.ref(o) and stead.ref(o).where then
2616		return stead.walk(stead.ref(o).where);
2617	end
2618	return stead.call(stead.ref(r),'act', self.key, ...);
2619end
2620
2621stead.vobj_used = function(self, ...)
2622	local o, r = stead.here():srch(self.nam);
2623	return stead.call(stead.ref(r),'used', self.key, ...);
2624end
2625
2626function vobj(key, name, dsc, w)
2627	if not stead.tonum(key) then
2628		error ("vobj key must be number!", 2);
2629	end
2630	return obj{ key = key, nam = name, dsc = dsc, where = stead.deref(w), act = stead.vobj_act, used = stead.vobj_used, save = stead.vobj_save, obj = list({}) };
2631end
2632
2633function vway(name, dsc, w)
2634	return  obj{ key = -1, nam = name, dsc = dsc, act = stead.vobj_act, where = stead.deref(w), used = stead.vobj_used, save = stead.vobj_save, obj = list({}), };
2635end
2636
2637stead.vroom_save = function(self, name, h, need)
2638	if need then
2639		local t = stead.string.format("%s = vroom(%s, %q);\n",
2640			name, stead.tostring(self.nam),
2641				stead.deref(self.where))
2642		h:write(t);
2643	end
2644	stead.savemembers(h, self, name,false);
2645end
2646
2647stead.vroom_enter = function(self, ...)
2648	return stead.walk(self.where);
2649end
2650
2651function isVroom(v)
2652	return (stead.type(v) == 'table') and (v.vroom_type)
2653end
2654
2655function vroom(name, w)
2656	if w == nil then
2657		error("Wrong parameter to vroom.", 2);
2658	end
2659	return room { vroom_type = true, nam = name, where = stead.deref(w), enter = stead.vroom_enter, save = stead.vroom_save, };
2660end
2661
2662function walk(what)
2663	local v,r=stead.me():walk(what);
2664	stead.me():tag();
2665	return v,r;
2666end
2667stead.walk = walk;
2668
2669function back()
2670	return stead.me():back();
2671end
2672stead.back = back;
2673
2674stead.rnd = function(...)
2675	if stead.random then
2676		return stead.random(...)
2677	end
2678	return stead.math.random(...);
2679end
2680
2681stead.rndseed = function(...)
2682	if stead.randomseed then
2683		return stead.randomseed(...)
2684	end
2685	stead.math.randomseed(...)
2686end
2687
2688function taken(obj)
2689	if isObject(stead.ref(obj)) and stead.ref(obj)._taken then
2690		return true
2691	end
2692	return false;
2693end
2694
2695function remove(obj, from)
2696	local o,w
2697	from = stead.ref(from)
2698	if from then
2699		if isList(from) then
2700			return from:del(obj)
2701		end
2702		o,w = from:srch(obj);
2703	else
2704		o,w = stead.here():srch(obj);
2705	end
2706	if w then
2707		stead.ref(w).obj:del(obj);
2708	end
2709	o = stead.ref(o);
2710	if not isObject(o) then
2711		o = stead.ref(obj);
2712	end
2713	if isObject(o) then
2714		o.__where__ = nil;
2715	end
2716	return o
2717end
2718stead.remove = remove
2719
2720function purge(obj, from)
2721	local o,w
2722	from = stead.ref(from)
2723	if from then
2724		if isList(from) then
2725			return from:purge(obj)
2726		end
2727		o,w = from:srch(obj, true);
2728	else
2729		o,w = stead.here():srch(obj, true);
2730	end
2731	if w then
2732		stead.ref(w).obj:purge(obj);
2733	end
2734	o = stead.ref(o);
2735	if not isObject(o) then
2736		o = stead.ref(obj);
2737	end
2738	if isObject(o) then
2739		o.__where__ = nil;
2740	end
2741	return o
2742end
2743stead.purge = purge
2744
2745function taketo(obj, wh, pos)
2746	local o = remove(obj, wh);
2747	if not isObject(o) then
2748		error ("Trying to take wrong object.", 2);
2749	end
2750	inv():add(obj, pos);
2751	o._taken = true
2752	wh = stead.deref(stead.me())
2753	if stead.type(wh) == 'string' then
2754		o.__where__ = wh;
2755	end
2756	return o
2757end
2758
2759function take(obj, wh)
2760	return taketo(obj, wh);
2761end
2762
2763function takef(obj, wh)
2764	return taketo(obj, wh, 1);
2765end
2766
2767function putto(obj, w, pos)
2768	local wh
2769	local o = stead.ref(obj);
2770	if not isObject(o) then
2771		error ("Trying to put wrong object.", 2);
2772	end
2773	if not w then
2774		wh = stead.deref(stead.here());
2775		w = stead.here();
2776	else
2777		wh = stead.deref(w);
2778		w = stead.ref(w);
2779	end
2780	if isList(w) then
2781		w:add(obj, pos);
2782	else
2783		w.obj:add(obj, pos);
2784	end
2785	if stead.type(wh) == 'string' then
2786		o.__where__ = wh;
2787	end
2788	return o;
2789end
2790
2791
2792function put(obj, w)
2793	return stead.placeto(obj, w);
2794end
2795
2796function putf(obj, w)
2797	return stead.placeto(obj, w, 1);
2798end
2799
2800place = put
2801placef = putf
2802placeto = putto
2803stead.placeto = placeto
2804
2805function replace(obj, obj2, from)
2806	local o,w,i
2807	if not isObject(stead.ref(obj2)) then
2808		error ("Wrong parameter to replace.", 2);
2809	end
2810	from = stead.ref(from)
2811	if from then
2812		if isList(from) then
2813			from:replace(obj, obj2);
2814			return stead.ref(obj)
2815		end
2816		o,w = from:srch(obj);
2817	else
2818		o,w = stead.here():srch(obj);
2819	end
2820	if w then
2821		stead.ref(w).obj:replace(o, obj2);
2822		stead.ref(obj2).__where__ = stead.deref(w);
2823	else
2824		stead.placeto(obj2, from);
2825	end
2826	o = stead.ref(o);
2827	if not isObject(o) then
2828		o = stead.ref(obj);
2829	end
2830	if isObject(o) then
2831		o.__where__ = nil;
2832	end
2833	return o;
2834end
2835
2836function drop(obj, w)
2837	local o = put(obj, w);
2838	if not isObject(o) then
2839		error ("Trying to drop wrong object.", 2);
2840	end
2841	inv():del(obj);
2842	o._taken = false
2843	return o;
2844end
2845
2846function dropf(obj, w)
2847	local o = putf(obj, w);
2848	if not isObject(o) then
2849		error ("Trying to dropf wrong object.", 2);
2850	end
2851	inv():del(obj);
2852	o._taken = false
2853	return o;
2854end
2855
2856function dropto(obj, w, pos)
2857	local o = putto(obj, w, pos);
2858	if not isObject(o) then
2859		error ("Trying to dropto wrong object.", 2);
2860	end
2861	inv():del(obj);
2862	o._taken = false
2863	return o;
2864end
2865
2866function seen(obj, wh)
2867	if not wh then
2868		wh = stead.here();
2869	else
2870		wh = stead.ref(wh);
2871	end
2872	local o,w = wh:srch(obj);
2873	o = stead.ref(o);
2874	if isObject(o) then
2875		return o,w
2876	end
2877	return nil
2878end
2879
2880function exist(obj, wh)
2881	if not wh then
2882		wh = stead.here();
2883	else
2884		wh = stead.ref(wh);
2885	end
2886	local o,w = wh:srch(obj, true);
2887	o = stead.ref(o);
2888	if isObject(o) then
2889		return o,w
2890	end
2891	return nil
2892end
2893
2894function have(obj)
2895	local o = inv():srch(obj);
2896	o = stead.ref(o);
2897	if isObject(o) then
2898		return o
2899	end
2900	return nil
2901end
2902
2903function moveto(obj, there, from, pos)
2904	stead.remove(obj, from);
2905	stead.placeto(obj, there, pos);
2906	return stead.ref(obj);
2907end
2908stead.moveto = moveto
2909
2910function move(obj, there, from)
2911	return stead.moveto(obj, there, from);
2912end
2913
2914function movef(obj, there, from)
2915	return stead.moveto(obj, there, from, 1);
2916end
2917
2918stead.cacheable = function(n, f)
2919	return function(...)
2920		local s = stead.cache[n]
2921		if s ~= nil then
2922			if s == -1 then s = nil end
2923			return s
2924		end
2925		stead.cache[n] = -1
2926		s = f(...)
2927		if s ~= nil then
2928			stead.cache[n] = s
2929		end
2930		return s
2931	end
2932end
2933
2934stead.get_picture = stead.cacheable('pic', function()
2935	local s = stead.call(stead.here(), 'pic');
2936	if not s then
2937		s = stead.call(game, 'pic');
2938	end
2939	return s;
2940end)
2941
2942stead.get_title = stead.cacheable('title', function()
2943	local s = stead.call(stead.here(), 'nam');
2944	return s;
2945end)
2946
2947if instead_savepath == nil then
2948	function instead_savepath()
2949		return "./"
2950	end
2951end
2952
2953function autosave(slot)
2954	game.autosave = true;
2955	game.autosave_slot = slot;
2956end
2957stead.autosave = autosave;
2958
2959stead.get_restart = function()
2960	return stead.restart_game
2961end
2962
2963stead.get_menu = function()
2964	local n = stead.need_menu
2965	stead.need_menu = nil
2966	return n
2967end
2968
2969stead.restart = function()
2970	stead.restart_game = true
2971end
2972
2973stead.get_autosave = function()
2974	return game.autosave, game.autosave_slot
2975end
2976
2977function change_pl(p)
2978	local o = stead.ref(p);
2979	if stead.type(stead.deref(p)) ~= 'string' or not o then
2980		error ("Wrong player name in change_pl...", 2);
2981	end
2982	game.pl = stead.deref(p);
2983	return stead.walk(o.where, false, true, true); -- no call enter/exit
2984end
2985
2986function disabled(o)
2987	return isDisabled(stead.ref(o))
2988end
2989
2990function disable(o)
2991	o = stead.ref(o)
2992	if isObject(o) then
2993		o:disable()
2994	end
2995	return o
2996end
2997
2998function enable(o)
2999	o = stead.ref(o)
3000	if isObject(o) then
3001		o:enable()
3002	end
3003	return o
3004end
3005
3006function disable_all(o)
3007	o = stead.ref(o)
3008	if isObject(o) or isList(o) then
3009		o:disable_all()
3010	end
3011	return o
3012end
3013
3014function enable_all(o)
3015	o = stead.ref(o)
3016	if isObject(o) or isList(o) then
3017		o:enable_all()
3018	end
3019	return o
3020end
3021
3022function isForSave(k, v, s) -- k - key, v - value, s -- parent table
3023	if stead.type(k) == 'function' then
3024		return false
3025	end
3026	if stead.type(v) == 'function' or stead.type(v) == 'userdata' then
3027		return false
3028	end
3029	return stead.string.find(k, '_') ==  1 or stead.string.match(k,'^%u')
3030end
3031
3032stead.inherit = function(o, f)
3033	return function(...)
3034		return f(o(...))
3035	end
3036end
3037inherit = stead.inherit
3038
3039stead.hook = function(o, f)
3040	return function(...)
3041		local ff
3042		if stead.type(o) ~= 'function' then
3043			ff = function(s)
3044				return o;
3045			end
3046		else
3047			ff = o
3048		end
3049		return f(ff, ...)
3050	end
3051end
3052hook = stead.hook
3053
3054function nameof(v)
3055	if isObject(v) then
3056		local r = stead.call(v, 'nam');
3057		return r
3058	end
3059end
3060
3061stead.nameof = nameof
3062
3063stead.dispof = function(v)
3064	if isObject(v) then
3065		local r
3066		if game.gui then
3067			r = stead.call(v, 'disp')
3068		end
3069		if r == nil then
3070			r = stead.call(v, 'nam');
3071		end
3072		return r
3073	end
3074end
3075
3076function stead_version(v)
3077	if not stead.tostr(v) then
3078		return
3079	end
3080
3081	stead.version_table = {}
3082	stead.api_version_table = {}
3083
3084	for n in stead.string.gmatch(stead.version, "[0-9]+") do
3085		stead.table.insert(stead.version_table, stead.tonum(n))
3086	end
3087
3088	for n in stead.string.gmatch(v, "[0-9]+") do
3089		stead.table.insert(stead.api_version_table, stead.tonum(n))
3090	end
3091
3092	if not stead.atleast(stead.unpack(stead.api_version_table)) then
3093		error ([[The game requires instead engine of version ]] ..v.. [[ or higher.
3094		https://instead-hub.github.io]], 2)
3095	end
3096
3097	stead.api_version = v
3098
3099	if stead.api_atleast(1, 2, 0) then
3100		require ("walk")
3101		require ("vars")
3102		require ("object")
3103	end
3104	if stead.api_atleast(1, 6, 3) then
3105		require ("dlg")
3106	end
3107end
3108instead_version = stead_version
3109
3110function code(v)
3111	local f = stead.eval(v)
3112	if not f then
3113		error ("Wrong script: "..stead.tostr(v), 2);
3114	end
3115	stead.functions[f] = { f = f, code = v };
3116	return f;
3117end
3118stead.code = code
3119
3120--- here the game begins
3121stead.objects = {
3122	null = obj {
3123		nam = 'null';
3124	};
3125
3126	allocator = function()
3127		return obj {
3128		nam = 'allocator',
3129		get = function(s, n, c)
3130			if isObject(stead.ref(n)) and stead.api_atleast(1, 3, 0) then -- static?
3131				return stead.ref(n);
3132			end
3133			local v = stead.ref(c);
3134			if not v then
3135				error ("Null object in allocator: "..stead.tostr(c));
3136			end
3137			v.key_name = n;
3138			v.save = stead.allocator_save;
3139			v.constructor = c;
3140			return v
3141		end,
3142		delete = function(s, w)
3143			w = stead.ref(w);
3144			if stead.type(w.key_name) ~= 'string' then
3145				return
3146			end
3147			local f = stead.eval(w.key_name..'= nil;');
3148			if f then
3149				f();
3150			end
3151		end,
3152		new = function(s, n, key)
3153			local v = stead.ref(n);
3154			if stead.type(v) ~= 'table' or stead.type(n) ~= 'string' then
3155				error ("Error in new.", 2);
3156			end
3157			v.save = stead.allocator_save;
3158			v.constructor = n;
3159			if key then
3160				s.objects[key] = v
3161				v.key_name = stead.string.format('allocator["objects"][%s]', stead.tostring(key));
3162			else
3163				local nm = #s.objects + 1 -- here is new index
3164				stead.table.insert(s.objects, v);
3165				v.key_name = 'allocator["objects"]['..stead.tostr(nm)..']';
3166			end
3167			if stead.api_atleast(1, 3, 0) then
3168				stead.check_object(v.key_name, v)
3169			end
3170			return v
3171		end,
3172		objects = {
3173			save = function(self, name, h, need)
3174				stead.savemembers(h, self, name, true);
3175			end,
3176		},
3177	};
3178	end;
3179	pl = function()
3180		return player {
3181		nam = "Incognito",
3182		where = 'main',
3183		obj = { }
3184	};
3185	end;
3186	main = function()
3187		return room {
3188		nam = 'main',
3189		dsc = 'No main room defined.',
3190	};
3191	end;
3192}
3193
3194
3195stead.sandbox = function()
3196	if STANDALONE then
3197		return
3198	end
3199-- sandbox --
3200local check_path = function(realpath, type, find, gsub, savepath, gamepath, path)
3201	if not path then
3202		return false
3203	end
3204	path = realpath(path)
3205	if not path then
3206		return false
3207	end
3208	local spath = realpath(savepath)
3209	if not spath then
3210		return false
3211	end
3212	local s = find(path, spath..'/', 1, true)
3213	if s ~= 1 then
3214		spath = realpath(gamepath);
3215		if spath then
3216			s = find(path, spath..'/', 1, true)
3217		end
3218	end
3219	if s ~= 1 then
3220		return false
3221	end
3222	return true
3223end
3224
3225local build_sandbox_open = function(realpath, error, type, find, gsub, savepath, gamepath)
3226	return stead.hook(io.open, function(f, path, acc, ...)
3227		if type(acc) ~= 'string' or not find(acc, "[aw+]") then -- only write access
3228			return f(path, acc, ...)
3229		end
3230		if not check_path(realpath, type, find, gsub, savepath, gamepath, path) then
3231			error ("Access denied (write): ".. path, 3);
3232			return false
3233		end
3234		return f(path, acc, ...)
3235	end)
3236end
3237
3238local build_sandbox_remove = function(realpath, error, type, find, gsub, savepath, gamepath)
3239	return stead.hook(os.remove, function(f, path, ...)
3240		if type(path) ~= 'string' then
3241			return f(path, ...)
3242		end
3243		if not check_path(realpath, type, find, gsub, savepath, gamepath, path) then
3244			error ("Access denied (remove): ".. path, 3);
3245			return false
3246		end
3247		return f(path, ...)
3248	end)
3249end
3250
3251local build_sandbox_rename = function(realpath, error, type, find, gsub, savepath, gamepath)
3252	return stead.hook(os.rename, function(f, oldname, newname, ...)
3253		if not check_path(realpath, type, find, gsub, savepath, gamepath, oldname) or
3254			not check_path(realpath, type, find, gsub, savepath, gamepath, newname) then
3255			error ("Access denied (rename): ".. oldname .. ', '.. newname, 3);
3256			return false
3257		end
3258		return f(oldname, newname, ...)
3259	end)
3260end
3261
3262local build_sandbox_output = function(realpath, error, type, find, gsub, savepath, gamepath)
3263	return stead.hook(io.output, function(f, path, ...)
3264		if type(path) == 'string' and not check_path(realpath, type, find, gsub, savepath, gamepath, path) then
3265			error ("Access denied (output): ".. path, 3);
3266			return false
3267		end
3268		return f(path, ...)
3269	end)
3270end
3271
3272local build_sandbox_load = function(eval, error, type, find)
3273	return stead.hook(eval, function(f, str, ...)
3274		if type(str) == 'string' and find(str, "\x1b", 1, true) == 1 then
3275			error ("Loading bytecode is forbidden!", 3)
3276			return false
3277		end
3278		return f(str, ...)
3279	end)
3280end
3281
3282io.open = build_sandbox_open(instead_realpath, error, type, string.find, string.gsub,
3283		instead_savepath(), instead_gamepath());
3284
3285os.remove = build_sandbox_remove(instead_realpath, error, type, string.find, string.gsub,
3286		instead_savepath(), instead_gamepath());
3287
3288os.rename = build_sandbox_rename(instead_realpath, error, type, string.find, string.gsub,
3289		instead_savepath(), instead_gamepath());
3290
3291io.output = build_sandbox_output(instead_realpath, error, type, string.find, string.gsub,
3292		instead_savepath(), instead_gamepath());
3293
3294os.execute = function(s)
3295	print ("Warning: trying to do os.execute: "..s);
3296end
3297
3298io.popen = function(s)
3299	print ("Warning: trying to do io.popen: "..s);
3300end
3301
3302os.tmpname = function(s)
3303	print ("Warning: trying to do os.tmpname");
3304end
3305
3306if not DEBUG then
3307	debug = nil
3308end
3309if _VERSION == "Lua 5.1" then
3310	loadstring = build_sandbox_load(loadstring, error, type, string.find)
3311	stead.eval = loadstring
3312else
3313	load = build_sandbox_load(load, error, type, string.find)
3314	stead.eval = load
3315end
3316package.cpath = ""
3317package.preload = {}
3318package = nil
3319
3320end
3321-- end of sandbox --
3322
3323stead.init = function(s)
3324	stead.initialized = false
3325	stead.started = false
3326	for k, v in pairs(stead.objects) do
3327		if type(v) == 'function' then
3328			stead.rawset(_G, k, v())
3329		else
3330			stead.rawset(_G, k, v)
3331		end
3332	end
3333	s.functions = {} -- code blocks
3334
3335	for k,v in stead.ipairs(s.modules_ini) do
3336		v();
3337	end
3338
3339	if stead.type(stead.sandbox) == 'function' then
3340		stead.sandbox()
3341		stead.sandbox = nil
3342	end
3343end
3344
3345stead.done = function(s)
3346	for k, v in stead.ipairs(s.modules_done) do
3347		v();
3348	end
3349end
3350
3351ref = stead.ref
3352deref = stead.deref
3353
3354pclr = stead.pclr
3355pget =  stead.pget
3356p = stead.p
3357pr = stead.pr
3358pn = stead.pn
3359par = stead.par
3360cat = stead.cat
3361player_moved = stead.player_moved
3362rnd = stead.rnd;
3363gamefile = stead.gamefile
3364time = stead.time
3365
3366instead_version(stead.api_version)
3367-- vim:ts=4
3368