1global { menu_mode = 'title' }
2
3level_reset = function(win, notitle)
4	key_empty()
5	if win and not demo_mode then
6		history_store(win)
7	end
8	happy_end_off = 0
9	sprite.copy(sprite.screen(), offscreen)
10	menu_select('level_out', 0)
11	level_load()
12	local st = level_stat()
13	local bant
14	history = {}
15	if demo_mode then
16		bant = sprite.text(fn2, stead.string.format(_("demo:DEMO").." %d", nr_level + 1), 'red', 1)
17	elseif notitle then
18		bant = false
19	else
20		if win then
21			bant = sprite.text(fn2, stead.string.format(_("score:SCORE").." %d", nr_score), 'red', 1)
22		else
23			bant = sprite.text(fn2, stead.string.format(_("try:TRIES").." %d", st.die), 'red', 1)
24		end
25	end
26	demo_mode = false
27	edit_mode = false
28	nr_score = 0;
29	sprite.fill(banner, 'black')
30	if bant then
31		local w, h = sprite.size(bant)
32		sprite.draw(bant, banner, (scr_w - w) / 2, 0)
33		sprite.free(bant)
34	end
35	timer:set(FAST_TIMER)
36	if level_after then
37		level_after()
38		level_after = false
39	end
40end
41
42level_movein = function()
43	local st = level_stat()
44	local bant
45	if not demo_mode then
46		if nr_level == nr_levels then
47			bant = sprite.text(fn2, stead.string.format(_("end:THE END")), 'red', 1)
48		else
49			bant = sprite.text(fn2, stead.string.format(_("level:LEVEL").." %d", nr_level + 1), 'red', 1)
50		end
51	else
52		bant = sprite.text(fn2, stead.string.format(_("demo:DEMO").." %d", nr_level + 1), 'red', 1)
53	end
54	local w, h = sprite.size(bant)
55	sprite.fill(banner, 'black')
56	sprite.draw(bant, banner, (scr_w - w) / 2, 0)
57	sprite.free(bant)
58
59	sound.play(sounds[SLEVELIN], 3)
60	timer:set(FAST_TIMER)
61	menu_select('level_in', scr_h + h)
62end
63
64level_ready = function()
65	menu_select(false)
66	level_render(sprite.screen());
67	timer:set(TIMER)
68end
69
70level_choose = function()
71	if nr_level >= nr_levels then
72		nr_level = 0
73	end
74	menu_select('level_select', true)
75	level_load()
76
77	select_time = 0
78
79	sprite.fill(offscreen, 'black')
80	level_map(offscreen, (scr_w - 256) / 2, (scr_h - 256) / 2)
81
82	local st = level_stat()
83	local lev = sprite.text(fn, stead.string.format(_("level:LEVEL").." %d", nr_level + 1), 'red', 1)
84	local w, h = sprite.size(lev)
85
86	sprite.fill(offscreen, (scr_w - 256) / 2, (scr_h - 256) / 2 - h - h / 2, 256, h, 'black');
87	sprite.draw(lev, offscreen, (scr_w - 256) / 2 + (256 - w) / 2, (scr_h - 256) / 2 - h - h / 2);
88	sprite.free(lev)
89	sprite.fill(offscreen, (scr_w - 256) / 2, (scr_h - 256) / 2 + 256 + h /2, 256, h, 'black');
90
91	if st.completed > 0 then
92		lev = sprite.text(fn, stead.string.format(_("completed:COMPLETED"), st.completed), 'red', 1)
93		local w, h = sprite.size(lev)
94		sprite.draw(lev, offscreen, (scr_w - 256) / 2, (scr_h - 256) / 2 + 256 + h / 2);
95		sprite.free(lev)
96
97		lev = sprite.text(fn, stead.string.format(_("score:SCORE").." %d", st.score), 'red', 1)
98		local w, h = sprite.size(lev)
99		sprite.draw(lev, offscreen, (scr_w - 256) / 2 + (256 - w), (scr_h - 256) / 2 + 256 + h / 2);
100		sprite.free(lev)
101	elseif st.die > 0 then
102		lev = sprite.text(fn, stead.string.format(_("try:TRIES").." %d", st.die), 'red', 1)
103		local w, h = sprite.size(lev)
104		sprite.draw(lev, offscreen, (scr_w - 256) / 2 + (256 - w) / 2, (scr_h - 256) / 2 + 256 + h / 2);
105		sprite.free(lev)
106	end
107
108	sprite.copy(offscreen, sprite.screen())
109	if (nr_level + 1) ~= nr_levels then
110		sprite.copy(ra_spr, sprite.screen(), scr_w - 24 - 16, 256 - 16)
111	end
112
113	if nr_level > 0 then
114		sprite.copy(la_spr, sprite.screen(), 24, 256 - 16)
115	end
116
117	timer:set(FAST_TIMER / 2)
118end
119
120MAP_SPEED = 32
121
122demo_enter = function()
123	local l
124	local ll = {}
125	for l = 0, nr_levels -1 do
126		if history_check(l) then
127			stead.table.insert(ll, l)
128		end
129	end
130	if #ll == 0 then return end
131	menu_select('demo', false)
132	nr_level = ll[rnd(#ll)]
133	level_load()
134	level_reset(false, true)
135	level_after = title_enter
136	history_load()
137	demo_mode = true
138end
139
140function menu_select(name, var)
141	menu_mode = name
142	if name then
143		_G[name..'_mode'] = var
144	end
145end
146
147function menu_title_mode()
148	title_time = title_time + 1
149	if title_time > 300 then
150		title_time = 0
151		demo_enter()
152		return true
153	end
154	if title_mode ~= true then
155		title_mode = title_mode - 32
156		if title_mode < 32 then title_mode = 32 end
157		title_render(sprite.screen(), 0, title_mode);
158	end
159	if title_mode == 32 then
160		title_mode = true
161		local s
162		if total_score and total_score > 0 then
163			s = sprite.text(tfn, stead.string.format(_("score:SCORE").." %d", total_score), '#00ff00', 1)
164			local w, h = sprite.size(s)
165			sprite.draw(s, sprite.screen(), scr_w - w - 2, 2);
166			sprite.free(s)
167		end
168
169		local s = sprite.text(tfn, stead.string.format(_("version:Version").." 1.4"), '#0000ff', 1)
170		local w, h = sprite.size(s)
171
172		sprite.draw(s, sprite.screen(), 2, 2);
173		sprite.free(s)
174	end
175	if title_mode == true and is_anykey() then
176		key_empty()
177		bank_choose()
178		sound.play(sounds[SPHASER], 3)
179		return true
180	end
181	local w,h = sprite.size(press_any_key)
182	if title_mode == true then
183		sprite.fill(sprite.screen(),
184			(scr_w - w) / 2, scr_h - h * 2, w, h, 'black');
185		if stead.math.floor(title_time / 10) % 2 ~= 0 then
186			sprite.draw(press_any_key, sprite.screen(),
187				(scr_w - w) / 2, scr_h - h * 2);
188		end
189	end
190	return true
191end
192
193function menu_level_in_mode()
194	local bw,bh = sprite.size(banner)
195	if level_in_mode < 0 then level_in_mode = 0 end
196	sprite.copy(banner, sprite.screen(), 0, level_in_mode - bh)
197	level_render(sprite.screen(), level_in_mode)
198	if level_in_mode == 0 then
199		level_ready()
200		return true
201	end
202	level_in_mode = level_in_mode - 8
203	return true
204end
205
206function menu_level_out_mode()
207	local bw,bh = sprite.size(banner)
208	if level_out_mode >= scr_h + bh then level_out_mode = scr_h + bh end
209	sprite.fill(sprite.screen(), 0, level_out_mode - 8 - bh, scr_h, level_out_mode, 'black')
210	sprite.copy(banner, sprite.screen(), 0, level_out_mode - bh);
211	sprite.copy(offscreen, sprite.screen(), 0, level_out_mode)
212	if level_out_mode == scr_h + bh then
213		level_movein()
214		return true
215	end
216	level_out_mode = level_out_mode + 8
217	return true
218end
219
220function bank_choose()
221	select_time = 0
222	sprite.fill(sprite.screen(), 'black')
223	sprite.copy(sprite.screen(), offscreen);
224	local sw, sh = banks[nr_bank].sw, banks[nr_bank].sh
225	sprite.draw(banks[nr_bank].spr, offscreen, (scr_w - sw) / 2, (scr_h - sh)/ 2);
226	sprite.copy(offscreen, sprite.screen());
227	if nr_bank < #banks then
228		sprite.copy(ra_spr, sprite.screen(), scr_w - 24 - 16, 256 - 16)
229	end
230	if nr_bank > 1 then
231		sprite.copy(la_spr, sprite.screen(), 24, 256 - 16)
232	end
233	sw, sh = sprite.size(select_maps_spr)
234	sprite.draw(select_maps_spr, sprite.screen(), (scr_w - sw)/2, 32)
235	menu_select('bank_select', true)
236end
237
238function menu_bank_select_mode()
239	if bank_select_mode ~= true then
240		local sw, sh = banks[nr_bank].sw, banks[nr_bank].sh
241
242		local h = (scr_h - sh) / 2
243
244		if bank_select_mode < 0 then
245			sprite.fill(sprite.screen(), scr_w + bank_select_mode, h, sw, sh, 'black')
246			bank_select_mode = bank_select_mode - MAP_SPEED
247			sprite.copy(offscreen, sprite.screen(), bank_select_mode, 0)
248			if bank_select_mode < -scr_w + (scr_w - sw )/ 2 then
249				bank_select_mode = -scr_w + (scr_w - sw )/ 2
250			end
251			sprite.draw(banks[nr_bank].spr, sprite.screen(), scr_w + bank_select_mode, h);
252		else
253			sprite.fill(sprite.screen(), bank_select_mode - sw, h, sw, sh, 'black')
254			bank_select_mode = bank_select_mode + MAP_SPEED
255			sprite.copy(offscreen, sprite.screen(), bank_select_mode, 0)
256			if bank_select_mode > (scr_w + sw )/ 2 then
257				bank_select_mode = (scr_w + sw )/ 2
258			end
259			sprite.draw(banks[nr_bank].spr, sprite.screen(), bank_select_mode - sw, h);
260		end
261
262		if bank_select_mode <= -scr_w + (scr_w - sw )/ 2 or bank_select_mode >= (scr_w + sw )/ 2 then
263			bank_choose();
264		end
265
266	end
267	if bank_select_mode == true then
268		if (is_key 'down' or is_key 'right') and nr_bank < #banks then
269			_G["_selected_level_"..banks[nr_bank].name] = selected_level -- old selection
270			nr_bank = nr_bank + 1
271			bank_select_mode = -MAP_SPEED
272		elseif (is_key 'up' or is_key 'left') and nr_bank > 1 then
273			_G["_selected_level_"..banks[nr_bank].name] = selected_level -- old selection
274			nr_bank = nr_bank - 1
275			bank_select_mode = MAP_SPEED
276		elseif is_return() then
277			bank_load()
278			key_empty()
279			level_choose()
280			return true
281		end
282		if not select_time then select_time = 0 end
283		select_time = select_time + 1
284		if select_time >= 1000 then select_time = 0 end
285		local w,h = sprite.size(press_enter)
286		sprite.fill(sprite.screen(), (scr_w - w) / 2, scr_h - h * 2, w, h, 'black');
287		if stead.math.floor(select_time / 10) % 2 ~= 0 then
288			sprite.draw(press_enter, sprite.screen(), (scr_w - w) / 2, scr_h - h * 2);
289		end
290	end
291	return true
292end
293
294function menu_level_select_mode()
295	local level_select = level_select_mode
296	if level_select ~= true then -- scroll
297		sprite.copy(offscreen, sprite.screen(), level_select, 0)
298		if level_select < 0 then
299			sprite.fill(sprite.screen(), level_select + scr_w, 0, MAP_SPEED, scr_h, 'black')
300			level_map(sprite.screen(), scr_w + level_select, (scr_h - 256) / 2)
301			sprite.fill(sprite.screen(), scr_w + level_select + 256, 0, MAP_SPEED, scr_h, 'black')
302			level_select = level_select - MAP_SPEED
303		else
304			sprite.fill(sprite.screen(), level_select, 0, MAP_SPEED, scr_h, 'black')
305			level_map(sprite.screen(), level_select - 256, (scr_h - 256) / 2)
306			sprite.fill(sprite.screen(), level_select - 256 - MAP_SPEED, 0, MAP_SPEED, scr_h, 'black')
307			level_select = level_select + MAP_SPEED
308		end
309		if level_select < -384 or level_select > 400 then
310			level_choose()
311			level_select = true
312		end
313		level_select_mode = level_select
314	end
315
316	if level_select == true then
317		select_time = select_time + 1
318		if select_time >= 1000 then select_time = 0 end
319		local w,h = sprite.size(press_enter)
320		sprite.fill(sprite.screen(), (scr_w - w) / 2, scr_h - h * 2, w, h, 'black');
321			if stead.math.floor(select_time / 10) % 2 ~= 0 then
322			sprite.draw(press_enter, sprite.screen(),
323				(scr_w - w) / 2, scr_h - h * 2);
324		end
325		if is_key 'down' and nr_level < nr_levels - 1 then
326			nr_level = nr_level + 10
327			if nr_level >= nr_levels then
328				nr_level = nr_levels - 1
329			end
330			selected_level = nr_level
331			level_select_mode = -MAP_SPEED
332			level_load()
333		elseif is_key 'right' and nr_level < nr_levels - 1 then
334			nr_level = nr_level + 1
335			selected_level = nr_level
336			level_select_mode = -MAP_SPEED
337			level_load()
338		elseif is_key 'up' and nr_level > 0 then
339			nr_level = nr_level - 10
340			if nr_level < 0 then
341				nr_level = 0
342			end
343			selected_level = nr_level
344			level_select_mode = MAP_SPEED
345			level_load()
346		elseif is_key 'left' and nr_level > 0 then
347			nr_level = nr_level - 1
348			selected_level = nr_level
349			level_select_mode = MAP_SPEED
350			level_load()
351		elseif is_return() then
352			selected_level = nr_level
353			_G["_selected_level_"..banks[nr_bank].name] = selected_level -- old selection
354			sprite.fill(sprite.screen(), 'black')
355			stop_music();
356			level_load()
357			level_movein()
358			return true
359		elseif is_demo() and history_check(nr_level) then
360			sprite.fill(sprite.screen(), 'black')
361			level_load()
362			history_load()
363			level_movein()
364			level_after = level_choose
365			demo_mode = true
366			return true
367		elseif is_edit() then
368			sprite.fill(sprite.screen(), 'black')
369			level_load()
370			level_movein()
371			edit_mode = true
372			return true
373		end
374	end
375	return true
376end
377
378function menu_demo_mode()
379end
380
381title = {
382"     :   : ::: :  : ::: ::      ",
383"     :: ::  :  :: : :   : :     ",
384"     : : :  :  : :: ::  ::      ",
385"     :   :  :  :  : :   : :     ",
386"     :   : ::: :  : ::: : :     ",
387"                                ",
388"     ####   ###  ##   ####      ",
389"     ## ## ## ## ##   ## ##     ",
390"     ####  ## ## ##   ## ##     ",
391"     ## ## ## ## ##   ## ##     ",
392"     ####   ###  #### ####      ",
393};
394title_text = {
395"                                    ИНСТРУКЦИЯ:",
396"    Ваша задача: собрать все алмазы в лабиринте и перейти",
397"в следующий.",
398"    Попадаться в руки бабочкам и минам, а также оказаться",
399"под падающим камнем или алмазом опасно для жизни.",
400"    Ваших сил хватит для толкания камней в любом",
401"направлении. Остальное поймете сами по ходу игры.",
402" ",
403"    Программа была написана А. В. Меленьтевым в 1989 г.",
404"для БК-0010. Оформлять игру помог Н. Валтер.",
405"    Порт игры под INSTEAD выполнен П. А. Косых в 2015 г.",
406}
407
408title_text_en = {
409"                                    INSTRUCTIONS:",
410" ",
411"    Your mission: got all jewels on the level. Avoid butterfiles",
412" mines and falling stones.",
413"    You are strong enougth to move stones in any direction.",
414"    Good luck!",
415" ",
416"    Original code was written by A. V. Melentiev in 1989.",
417"for BK-0010 computers. N. Walter helped him.",
418"    Ported to INSTEAD by P.A. Kosyh in 2015.",
419}
420happy_end_map =
421
422{
423"::::::::::::::::",
424"               $",
425"                ",
426"                ",
427"                ",
428"+      @@       ",
429"::::::::::::::::",
430"%              &",
431"                ",
432"                ",
433"                ",
434"                ",
435"                ",
436"                ",
437"                ",
438"                ",
439}
440
441happy_end_text = {
442"Поздравляю!",
443"Вы прошли эту непростую игру!",
444" ",
445"Надеюсь, она понравилась вам также",
446"как и мне 25 лет назад...",
447" ",
448"Кстати, вы можете смотреть записанные",
449"демонстрации, нажав на клавишу D",
450"из режима выбора уровня",
451"или прямо во время игры",
452" ",
453"Вы можете посмотреть",
454"другие INSTEAD игры по адресу:",
455"http://instead.syscall.ru",
456" ",
457"Выражаю благодарность и признательность:",
458" ",
459"Жене и детям",
460"за понимание",
461" ",
462"А. В. Мелентьеву и Н. Валтеру",
463"за Bolder Dash для БК-0010",
464" ",
465"Леониду Брухису",
466"За эмулятор БК-0010 для Unix",
467" ",
468"Всем разработчикам БК-0010",
469" ",
470"Без всех этих людей",
471"ремейк игры был бы невозможен...",
472" ",
473" ",
474"В игре использованы треки:",
475" ",
476"Chip never dies от ajaxlemon",
477"IBM 486 66Mhz от ExcelioN",
478" ",
479" ",
480" ",
481" ",
482"КОНЕЦ",
483" ",
484" ",
485" ",
486" ",
487"                   Косых Петр 2015",
488}
489
490happy_end_text_en = {
491"Congratulations!",
492"You win!",
493" ",
494"I hope you like this small game",
495"It was written 25 years ago...",
496" ",
497"Btw, you may run demo of any level",
498"Just press D key from map selection",
499"menu or just in game",
500" ",
501"Visit http://instead.syscall.ru",
502"for other INSTEAD games",
503" ",
504"Thanks to:",
505" ",
506"My wife and childrens",
507" ",
508"A. V. Melentiev and N. Walter",
509"for they Bolder Dash game",
510" ",
511"Leonid A. Broukhis",
512"for БК-0010 emulator",
513" ",
514"And all BK-0010 developers!",
515" ",
516"Thank you for playing this game!",
517" ",
518" ",
519"Music:",
520" ",
521"Chip never dies by ajaxlemon",
522"IBM 486 66Mhz by ExcelioN",
523" ",
524" ",
525" ",
526" ",
527"THE END",
528" ",
529" ",
530" ",
531" ",
532"                   Peter Kosyh 2015",
533}
534happy_end_spr = {}
535happy_end_render = function()
536	if not happy_end_off then
537		happy_end_off = 0
538	end
539	local off = happy_end_off
540	local het = happy_end_text
541	if LANG ~= 'ru' then
542		het = happy_end_text_en
543	end
544	local k,v
545	local fh = sprite.font_height(tfn)
546	local off2 = off
547	local bh = scr_h / 2
548	local delta = bh - off
549	local start = 1
550	local start_y = scr_h
551	if not happy_end_spr_w then
552		happy_end_spr_w = 0
553		happy_end_spr_h = 0
554		for k,v in ipairs(het) do
555			local w,h = sprite.text_size(tfn, v)
556			if w > happy_end_spr_w then
557				happy_end_spr_w = w
558			end
559			happy_end_spr_h = happy_end_spr_h + h
560		end
561	end
562	if delta < 0 then
563		for k,v in ipairs(het) do
564			if delta + fh >= 0 then
565				start = k
566				start_y = delta
567				break
568			end
569			if happy_end_spr[k] then
570				sprite.free(happy_end_spr[k])
571				happy_end_spr[k] = nil
572			end
573			delta = delta + fh
574		end
575	else
576		start_y = delta
577	end
578--prite.fill(sprite.screen(), (scr_w - happy_end_spr_w)/2, scr_h /2, happy_end_spr_w, scr_h / 2, "black")
579	local ox = (scr_w - happy_end_spr_w)/2
580	for k = start, #het do
581		v = het[k]
582		if v == '' then v = ' ' end
583		if not happy_end_spr[k] then
584			happy_end_spr[k] = sprite.text(tfn, v, '#ff0000', 1)
585		end
586		local w, h = sprite.size(happy_end_spr[k])
587		if delta < 0 and k == start then
588			sprite.draw(happy_end_spr[k], 0, -delta, w, h + delta, sprite.screen(), ox + (happy_end_spr_w - w)/2, scr_h /2 + start_y - delta)
589		else
590			sprite.draw(happy_end_spr[k], sprite.screen(), ox + (happy_end_spr_w - w)/2, scr_h/2 + start_y)
591		end
592		start_y = start_y + fh
593		if start_y >= scr_h then
594			break
595		end
596	end
597	happy_end_off = happy_end_off + 2
598	if happy_end_off > (happy_end_spr_h + bh)  then
599		happy_end_off = 0
600	end
601end
602
603title_render = function(where, ox, oy)
604	local char2map = {
605		[' '] = 0,
606		[':'] = 1,
607		['@'] = 2,
608		['$'] = 3,
609		['+'] = 4,
610		['#'] = 5,
611		['&'] = 6,
612		['%'] = 7,
613	}
614	local x
615	local y
616	for y = 1, #title do
617		for x = 1, 32 do
618			local c = string.sub(title[y], x, x);
619			c = char2map[c]
620			sprite.copy(sprites_small[c + 1], where,
621				ox + (x - 1) * 16, oy + (y - 1) * 16);
622		end
623	end
624	sprite.fill(where, 0, oy + #title * 16, 512, 32, 'black');
625	sprite.fill(where, 0, oy - 32, 512, 32, 'black');
626	local k,v
627	if not title_tspr then
628		tspr_width = 0
629		title_tspr = {}
630		local t = title_text_en
631		if LANG == "ru" then
632			t = title_text
633		end
634		for k,v in ipairs(t) do
635			title_tspr[k] = sprite.text(tfn, v, '#00ff00', 1)
636			local w, h = sprite.size(title_tspr[k])
637			if w > tspr_width then tspr_width = w end
638		end
639	end
640	local dh = #title * 16 + 16
641	local fh = sprite.font_height(tfn)
642	fh = fh + stead.math.floor(fh / 3)
643	for k, v in ipairs(title_tspr) do
644		sprite.fill(where, ox, oy + dh + (k - 1) * fh, scr_w, h, 'black')
645	end
646	local dy
647	for k, v in ipairs(title_tspr) do
648		local w, h = sprite.size(v)
649		dy = oy + dh + (k - 1) * fh
650		sprite.draw(v, where, ox + (scr_w - tspr_width) / 2, dy)
651	end
652	sprite.fill(where, 0, dy + fh, scr_w, 32, 'black')
653end
654
655title_enter = function()
656	set_music('snd/chipneve.xm')
657	menu_select('title', scr_h)
658	demo_mode = false
659	edit_mode = false
660	title_time = 0
661	timer:set(FAST_TIMER)
662--	sound.stop(-1)
663	sound.play(sounds[STRILL], 3)
664	level_after = false
665	key_empty()
666	local k,v
667
668	local score = 0
669
670	for k,v in pairs(bank_stat()) do
671		if v.score then
672			score = score + v.score
673		end
674	end
675	total_score = score
676end
677