1--$Name:Miner Bold$ 2--$Version:1.4$ 3--$Author:Peter Kosyh$ 4 5instead_version "2.0.0" 6TIMER = 85 7FAST_TIMER = 30 8 9require "sprites" 10require "sound" 11require "timer" 12require "kbd" 13require "click" 14 15-- require "prefs" 16 17sprites = {} 18sprites_small = {} 19 20history = {} 21 22sounds = {} 23global { 24 nr_level = 0; 25 selected_level = 0; 26 nr_score = 0; 27 map = {}; 28 prefs = { } 29}; 30 31prefs.stat = {} 32prefs.maps_stat = {} 33 34SDIE = 1 35SFALL = 2 36SCLICK = 3 37SLEVELIN = 4 38STRILL = 5 39SPHASER = 6 40 41load_sounds = function() 42 sounds[SDIE] = sound.load "snd/explode.ogg" 43 sounds[SFALL] = sound.load "snd/fall.ogg" 44 sounds[SCLICK] = sound.load "snd/click.ogg" 45 sounds[SLEVELIN] = sound.load "snd/levelin.ogg" 46 sounds[STRILL] = sound.load "snd/trill.ogg" 47 sounds[SPHASER] = sound.load "snd/phaser.ogg" 48end 49 50load_sprites = function() 51 local i 52 local files = { 53 '00.png', 54 '01.png', 55 '02.png', 56 '03.png', 57 '04.png', 58 '05.png', 59 '06.png', 60 '07.png', 61 '02.png', 62 '02.png', 63 '03.png', 64 '03.png', 65 '12.png', 66 '13.png', 67 '14.png', 68 '15.png', 69 '16.png', 70 '17.png', 71 '18.png', 72 '19.png', 73 '20.png', 74 '21.png', 75 } 76 for i=1, #files do 77 local s = sprite.load("gfx/"..files[i]) 78 if i <= 8 then 79 sprites_small[i] = s 80 end 81 sprites[i] = sprite.scale(s, 2.0, 2.0, false) 82-- sprite.free(s) 83 end 84 fn = sprite.font("gfx/font.ttf", 16); 85 fn2 = sprite.font("gfx/font.ttf", 26); 86 tfn = sprite.font("gfx/font.ttf", 12); 87 press_any_key = sprite.text(tfn, _("press:PRESS ANY KEY"), 'red', 1) 88 press_enter = sprite.text(fn, _("press_enter:PRESS ENTER"), 'red', 1) 89 select_maps_spr = sprite.text(fn2, _("banks:SELECT GAME"), 'red', 1) 90 la_spr = sprite.load("gfx/la.png") 91 ra_spr = sprite.load("gfx/ra.png") 92end 93 94BEMPTY = 0 95BGRASS = 1 96BSTONE = 2 97BSTONE_LAZY = BSTONE + 128 98BGOLD = 3 99BHUMAN = 4 100BBLOCK = 5 101BHEART = 6 102BFLY = 7 103 104BSTONE2 = BSTONE * 2 + 4 105BSTONE3 = BSTONE2 + 1 106 107BGOLD2 = BGOLD * 2 + 4 108BGOLD3 = BGOLD2 + 1 109 110global { 111 scatter_dir = -1; 112 enemies = {}; 113} 114 115level_store = function() 116 local map2char = { 117 [0] = ' ', 118 [1] = ':', 119 [2] = '@', 120 [3] = '$', 121 [4] = '+', 122 [5] = '#', 123 [6] = '&', 124 [7] = '%', 125 } 126 local x 127 local y 128 for y = 0, 15 do 129 local line = '' 130 for x = 0, 15 do 131 local c = cell_get(x * 2, y * 2) 132 c = map2char[c]; 133 line = line .. c; 134 end 135 maps[nr_level * 16 + y + 1] = line 136 end 137end 138 139level_load = function() 140 enemies = {}; 141 history = {} 142 scatter_dir = -1 143 144 local char2map = { 145 [' '] = 0, 146 [':'] = 1, 147 ['@'] = 2, 148 ['$'] = 3, 149 ['+'] = 4, 150 ['#'] = 5, 151 ['&'] = 6, 152 ['%'] = 7, 153 } 154 local line = nr_level * 16 155 local x 156 local y 157 local was_human 158 for y = 1, 16 do 159 map[y] = {} 160 local row = maps[line + y] 161 for x = 1, 16 do 162 local c = string.sub(row, x, x); 163 c = char2map[c] 164 if c == BHUMAN and was_human then 165 c = BEMPTY 166 end 167 map[y][x] = c 168 if c == BHUMAN then 169 was_human = true 170 player_x = (x - 1) * 2 171 player_y = (y - 1) * 2 172 player_movex = 0; 173 player_movey = 0; 174 elseif c >= BHEART then -- 175 stead.table.insert(enemies, { x = (x - 1) * 2, y = (y - 1) * 2, dx = 0, dy = 0 }) 176 end 177 end 178 end 179 if not was_human then 180 player_x = 0 181 player_y = 0 182 player_movex = 0; 183 player_movey = 0; 184 map[1][1] = BHUMAN 185 end 186end 187 188scr_w = 512 189scr_h = 512 190 191level_render = function(where, offset) 192 if not offset then offset = 0 end 193 local y 194 local x 195 for y = 1,16 do 196 local yy = 32 * (y - 1) + offset 197 if yy >= scr_h then 198 return 199 end 200 if yy >= 0 then 201 local l = map[y] 202 for x = 1, 16 do 203 local c = l[x] + 1 204 sprite.copy(sprites[c], where, 32 * (x - 1), yy) 205 end 206 end 207 end 208end 209level_map = function(where, ox, oy) 210 local y 211 local x 212 for y = 1,16 do 213 local yy = 16 * (y - 1) 214 local l = map[y] 215 for x = 1, 16 do 216 local c = l[x] + 1 217 sprite.copy(sprites_small[c], where, 16 * (x - 1) + ox, yy + oy) 218 end 219 end 220end 221 222keys = {} 223key_empty = function() 224 fingers = {} 225 keys = {} 226 key_any, key_esc, key_demo, key_return, key_edit = false, false, false, false, false 227end 228 229fingers = {} 230touch_stamp = 0; 231touch_num = 0 232touch_max = 0 233if stead.finger_pos then 234 require "finger" 235 game.finger = function(s, press, fid, x, y) 236 use_fingers = true 237 if press then 238 if stead.ticks() - touch_stamp > 200 then 239 touch_num = 0 240 touch_stamp = stead.ticks() 241 end 242 touch_num = touch_num + 1 243 touch_max = #finger:list() 244 else 245 local tm = touch_max 246 touch_num = 0 247 touch_stamp = 0 248 touch_max = 0 249 if tm >=4 and edit_mode then 250 local x, y 251 for y=0, 15 do 252 for x=0, 15 do 253 sprite_draw(x * 2, y * 2, BEMPTY); 254 cell_set(x * 2, y * 2, BEMPTY); 255 end 256 end 257 return 258 elseif tm >= 3 then 259 key_edit = true 260 return 261 end 262 end 263 if touch_num >= 3 then 264 key_esc = true 265 return 266 end 267 if press and x > scr_w / 3 and x < scr_w * 2 / 3 and not edit_mode and touch_max == 1 then 268 key_return = press 269 key_any = press 270 end 271 if press then 272 stead.table.insert(fingers, 1, { id = fid, x = x, y = y }) 273 else 274 local k,v 275 for k,v in ipairs(fingers) do 276 if v.id == fid then 277 stead.table.remove(fingers, k) 278 break 279 end 280 end 281 if #fingers == 0 then 282 key_empty() 283 end 284 end 285 end 286end 287 288function check_fingers() 289 if not use_fingers then 290 return 291 end 292 keys = {} 293 294 local fng = finger:list() 295 local k, v 296 if #fingers == 0 then 297 return 298 end 299 local V 300 for k,v in ipairs(fng) do 301 if v.id == fingers[1].id then 302 V = v 303 break 304 end 305 end 306 if not V then 307 stead.table.remove(fingers, 1) -- lost one? 308 return 309 end 310 v = V 311 312 local dx = v.x - fingers[1].x 313 local dy = v.y - fingers[1].y 314 315 local r = stead.math.sqrt(dx*dx + dy*dy) 316 317 if r < 8 then 318 return 319 end 320 321 if stead.math.abs(dx) >= stead.math.abs(dy) then 322 -- lr 323 if dx < 0 then 324 game:kbd(true, 'left') 325 else 326 game:kbd(true, 'right') 327 end 328 else 329 -- ud 330 if dy < 0 then 331 game:kbd(true, 'up') 332 else 333 game:kbd(true, 'down') 334 end 335 end 336end 337 338click_history = { {0,0}, {0,0}, {0,0}, {0,0} } 339cell_edit = function(x, y, a) 340 local c = cell_get(x, y) 341 if c == edit_c and not a then 342 edit_c = c + 1 343 else 344 edit_c = edit_c or c 345 end 346 if edit_c > 7 then 347 edit_c = 0 348 end 349 cell_set(x, y, edit_c) 350end 351 352game.click = function(s, x, y, a, b) 353 if edit_mode and not menu_mode then 354 local nx = math.floor(x / 32) * 2; 355 local ny = math.floor(y / 32) * 2; 356 if nx == player_x and ny == player_y then 357 cell_edit(player_x, player_y) 358 else 359 sprite_draw(player_x, player_y, cell_get(player_x, player_y)); 360 player_x, player_y = nx, ny 361-- cell_edit(player_x, player_y); 362 end 363 end 364end 365 366game.kbd = function(s, down, key) 367 if key == 'space' or key == 'return' then 368 key_return = down 369 return 370 end 371 372 if key == 'escape' or key == 'backspace' then 373 if menu_mode ~= 'title' then 374 key_esc = down 375 return true 376 end 377 key_esc = false 378 end 379 380 if key == 'd' then 381 key_demo = down 382 return 383 end 384 385 if key == 'e' then 386 key_edit = down 387 return 388 end 389 390 if key >= '0' and key <= '7' then 391 key_num = down and key 392 return 393 end 394 395 if not down then 396 local k,v 397 local i 398 for k,v in ipairs(keys) do 399 if v == key then 400 i = k 401 break 402 end 403 end 404 if i then 405 stead.table.remove(keys, i) 406 end 407 return 408 end 409 s:kbd(false, key) -- release first 410 stead.table.insert(keys, 1, key) 411end 412 413 414banks = { 415} 416 417banks_init = function(s) 418 local k,v 419 local m = {} 420 for v in stead.readdir(instead_gamepath()) do 421 if v:find("%.map$") then 422 stead.table.insert(m, v) 423 end 424 end 425 stead.table.sort(m, function(a ,b) 426 if a == 'maps.map' then 427 return true 428 elseif b == 'maps.map' then 429 return false 430 else 431 return a < b 432 end 433 end) 434 for k, v in ipairs(m) do 435 local f = io.open(instead_gamepath().."/"..v) 436 if f then 437 local l 438 local name = v:gsub("%.map$", "") 439 local sname = name 440 local name_i18n = false 441 for l in f:lines() do 442 if not l:find("^%-%-") and not l:find("^[ \t]*$") then 443 break 444 end 445 if l:find("$Name:", 1, true) then 446 name = l:gsub("^.*%$Name:[ \t]*(.*)[ \t]*$", "%1") 447 elseif l:find("%$Name%([a-zA-Z]+%):") then 448 name_i18n = l:gsub("^.*%$Name%(([a-zA-Z]+)%):[ \t]*(.*)[ \t]*$", "%2") 449 name_lang = l:gsub("^.*%$Name%(([a-zA-Z]+)%):[ \t]*(.*)[ \t]*$", "%1") 450 end 451 end 452 if name_i18n then 453 stead.table.insert(banks, { title = name, title_i18n = { [name_lang] = name_i18n }, file = v, name = sname }) 454 else 455 stead.table.insert(banks, { title = name, file = v, name = sname }) 456 end 457 f:close(); 458 end 459 end 460 for k,v in ipairs(banks) do 461 local title = v.title 462 if v.title_i18n and v.title_i18n[LANG] then 463 title = v.title_i18n[LANG] 464 end 465 v.spr = sprite.text(fn2, title, '#ff0000', 1) 466 v.sw, v.sh = sprite.size(v.spr) 467 end 468 nr_bank = 1 469end 470 471game.timer = function(s) 472 local rc 473 check_fingers() 474 if menu_mode then 475 rc = _G['menu_'..menu_mode..'_mode']() 476 end 477 if is_esc() then 478 title_enter() 479 return 480 end 481 if not rc then 482 game_loop() 483 end 484end 485 486pos2cell = function(x, y) 487 return stead.math.floor(x / 2), stead.math.floor(y / 2) 488end 489 490cell2pos = function(x, y) 491 return x * 2, y * 2 492end 493 494sprite_draw = function(x, y, c) 495 sprite.copy(sprites[c + 1], sprite.screen(), 16 * x, 16 * y) 496end 497 498cell_set = function(x, y, c) 499 x, y = pos2cell(x, y) 500 if x < 0 or x > 15 or y < 0 or y > 15 then 501 return 502 end 503 map[y + 1][x + 1] = c 504end 505 506cell_get = function(x, y, c) 507 x, y = pos2cell(x, y) 508 return map[y + 1][x + 1] 509end 510 511global { 512 player_x = 0; 513 player_y = 0; 514 player_movex = 0; 515 player_movey = 0; 516} 517 518is_key = function(n) 519 if keys[1] == n then 520 return true 521 end 522end 523 524is_return = function() 525 return key_return 526end 527 528is_esc = function() 529 return key_esc 530end 531 532is_anykey = function() 533 local c = key_any 534 key_any = false 535 if c then 536 key_return = false 537 key_esc = false 538 end 539 return c 540end 541 542input.key = stead.hook(input.key, function(f, s, down, key, ...) 543 if not key:find("escape") and not key:find("shift") 544 and not key:find("ctrl") 545 and not key:find("alt") 546 and not key:find("unknown") then 547 key_any = down 548 end 549 return f(s, down, key, ...) 550end) 551 552is_demo = function() 553 if key_demo then 554 return true 555 end 556end 557 558is_edit = function() 559 if key_edit then 560 key_edit = false 561 return true 562 end 563end 564 565human_stone = function(x, y) 566 local xx, yy, c 567 xx, yy = x + player_movex * 2, y + player_movey * 2 568 while true do 569 if xx >= 32 or yy >= 32 or xx < 0 or yy < 0 then 570 return human_stop(x, y) 571 end 572 c = cell_get(xx, yy) 573 if c == BEMPTY then 574 break 575 end 576 if c ~= BSTONE and c ~= BSTONE3 then 577 return human_stop(x, y) 578 end 579 xx, yy = xx + player_movex * 2, yy + player_movey * 2 580 end 581 cell_set(xx, yy, BSTONE_LAZY) 582 cell_set(x, y, BEMPTY); 583 sprite_draw(x, y, BEMPTY); 584 sprite_draw(xx, yy, BSTONE); 585 return human_move(x, y) 586-- local c = cell_get(xx, yy) 587-- if c == BEM 588end 589human_stop = function(x, y) 590 sprite_draw(player_x, player_y, BHUMAN) 591end 592human_gold = function(x, y) 593 -- sound 594 sound.play(sounds[SCLICK]) 595 -- score 596 nr_score = nr_score + 1 597 return human_move(x, y) 598end 599 600human_move = function(x, y) 601 sprite_draw(player_x, player_y, BEMPTY) 602 if player_movex ~= 0 or player_movey ~= 0 then 603 if player_movex < 0 then 604 c = 16 605 elseif player_movex > 0 then 606 c = 18 607 elseif player_movey < 0 then 608 c = 12 609 else 610 c = 14 611 end 612 sprite_draw(player_x + player_movex, player_y + player_movey, c) 613 cell_set(x, y, c) 614 x, y = player_x + player_movex, player_y + player_movey 615 else 616 cell_set(player_x, player_y, BEMPTY) 617 cell_set(x, y, BHUMAN) 618 end 619 player_x, player_y = x, y 620end 621 622human_death = function(x, y) 623 explode(x, y) 624 level_stat().die = level_stat().die + 1 625 stead.autosave() 626 level_reset() 627end 628 629game_dispatch = function(c, x, y) 630 local dt = { 631 [BEMPTY] = human_move, -- 0 632 [BGRASS] = human_move, -- 1 633 [BSTONE] = human_stone, -- 2 634 [BGOLD] = human_gold, --3 635 [BBLOCK] = human_stop, --5 636 [BHEART] = human_death, --6 637 [BFLY] = human_death, --7 638 [BSTONE2] = human_stop, -- 8 639 [BSTONE3] = human_stone, -- stone 640 [BGOLD2] = human_stop, -- 8 641 [BGOLD3] = human_gold, -- gold 642 [20] = human_death, 643 [21] = human_death, 644 } 645 local fn = dt[c] 646 if not fn then 647 error("Unknown dispatcher: "..c) 648 end 649 return fn(x, y) 650end 651 652check_scatter = function(cc, x, y, d) 653 if d == 1 and x == 30 then 654 return false 655 end 656 if d == -1 and x == 0 then 657 return false 658 end 659 local c = cell_get(x + d * 2, y + 2) 660 if c ~= BEMPTY then 661 return false 662 end 663 c = cell_get(x + d * 2, y) 664 if c ~= BEMPTY then 665 return false 666 end 667 cell_set(x + d * 2, y, cc) 668 cell_set(x, y, BEMPTY) 669 sprite_draw(x, y, BEMPTY) 670 sprite_draw(x + d * 2, y, cc) 671 return true 672end 673fall1 = function(x, y, c) 674 local sc = true 675 if y < 30 then 676 local cd = cell_get(x, y + 2) 677 if cd == BEMPTY then 678 c = c * 2 + 4 679 cell_set(x, y + 2, c) 680 cell_set(x, y, c) 681 sprite_draw(x, y, BEMPTY); 682 sprite_draw(x, y + 1, c) 683 return x, y 684 else -- scatter 685 local dir = scatter_dir 686 687 scatter_dir = - scatter_dir 688 if not check_scatter(c, x, y, dir) then 689 dir = - dir 690 sc = check_scatter(c, x, y, dir) 691 end 692 if dir == 1 and sc then 693 return x + 2, y 694 end 695 end 696 end 697 if not sc then 698 cell_set(x, y, c) 699 end 700 return x, y 701end 702explode = function(x, y) 703 x = x + 2 704 local xe = x 705 y = y + 2 706 local ye = y 707 local xs = x - 4 708 if xs < 0 then 709 xs = xs + 2 710 end 711 local ys = y - 4 712 if ys < 0 then 713 ys = ys + 2 714 end 715 if xe > 31 then 716 xe = xe - 1 717 end 718 if ye > 31 then 719 ye = ye - 1 720 end 721 for y = ys, ye, 2 do 722 for x = xs, xe, 2 do 723 cell_set(x, y, BGOLD) 724 sprite_draw(x, y, BGOLD) 725 end 726 end 727 -- sound 728 sound.play(sounds[SDIE]) 729-- local c = cell_get(player_x, player_y) 730-- if c ~= BHUMAN and c < 12 then 731-- level_stat().die = level_stat().die + 1 732-- prefs:store() 733-- stead.autosave() 734-- level_reset() 735-- end 736 return xe, ye 737end 738bank_stat = function() 739 local st = prefs.stat 740 local nam = banks[nr_bank].name 741 if nam ~= 'maps' then 742 if not prefs.maps_stat then 743 prefs.maps_stat = {} 744 end 745 st = prefs.maps_stat[nam] 746 if not st then 747 prefs.maps_stat[nam] = {} 748 end 749 st = prefs.maps_stat[nam] 750 end 751 return st 752end 753 754level_stat = function() 755 local st = bank_stat() 756 local lst = st[nr_level] 757 if not lst then 758 st[nr_level] = { } 759 end 760 st = st[nr_level] 761 if type(st.completed) ~= 'number' then 762 st.completed = 0 763 end 764 if type(st.die) ~= 'number' then 765 st.die = 0 766 end 767 if type(st.score) ~= 'number' then 768 st.score = 0 769 end 770 return st 771end 772 773fall = function() 774 local nr_gold = 0 775 local x, y, c 776 for y = 30,0,-2 do 777 x = 0 778 while x <= 30 do 779 if level_out then 780 return 781 end 782 c = cell_get(x, y) 783 if c == BGOLD or c == BGOLD3 or c == BGOLD2 then 784 nr_gold = nr_gold + 1 785 end 786 if c == BSTONE_LAZY then 787 c = BSTONE 788 cell_set(x, y, c) 789 elseif c == BGOLD or c == BSTONE then 790 x, y = fall1(x, y, c) 791 elseif c == BSTONE2 or c == BGOLD2 then 792 cell_set(x, y - 2, BEMPTY) 793 sprite_draw(x, y - 2, BEMPTY); 794 cell_set(x, y, c + 1) 795 sprite_draw(x, y, c + 1) 796 elseif c == BGOLD3 or c == BSTONE3 then 797 if y == 30 then 798 c = (c - 5) / 2 799 cell_set(x, y, c); 800 -- sound 801 sound.play(sounds[SFALL]) 802 sprite_draw(x, y, c); 803 else 804 local cd = cell_get(x, y + 2) 805 if cd == BHUMAN or cd == BHEART or cd == BFLY or cd >= 12 then 806 -- explode 807 -- print("explode") 808 x = explode(x, y + 2); 809 else 810 if cd ~= BEMPTY then 811 -- sound 812 sound.play(sounds[SFALL]) 813 end 814 c = (c - 5) /2 815 x, y = fall1(x, y, c) 816 end 817 end 818 end 819 x = x + 2 820 end 821 end 822-- check if dead 823 c = cell_get(player_x, player_y) 824 if c ~= BHUMAN and c < 12 then 825-- print ("dec lives"..c) 826 level_stat().die = level_stat().die + 1 827-- prefs:store() 828 stead.autosave() 829 level_reset() 830 return 831 end 832 if nr_gold == 0 then -- or is_return() then -- hack 833 -- completed 834 if demo_mode then 835 level_reset() 836 return 837 end 838 if nr_level == nr_levels then 839 title_enter() 840 return 841 end 842 level_stat().completed = level_stat().completed + 1 843 if level_stat().score < nr_score then 844 level_stat().score = nr_score 845 end 846-- prefs:store() 847 stead.autosave() 848 local l = nr_level 849 nr_level = nr_level + 1 850 if nr_level == nr_levels then 851 -- lookup first undone 852 local i 853 for i=0,nr_levels - 1 do 854 if (not bank_stat()[i] or 855 not bank_stat()[i].completed or 856 bank_stat()[i].completed == 0) then 857 nr_level = i 858 break 859 end 860 end 861 end 862 if nr_level == nr_levels then 863 -- todo game over 864 nr_level = nr_levels 865 level_reset(l) 866 set_music 'snd/486.xm' 867 else 868 selected_level = nr_level 869 level_reset(l) 870 end 871 end 872end 873 874enemy_halflife = function(c) 875 if c < 16 then 876 c = c + 14 877 else 878 c = c - 14 879 end 880 return c 881end 882 883enemy_turn = function(x, y, c, w, e) 884 sprite_draw(x, y, BEMPTY) 885 c = enemy_halflife(c) 886 local dx, dy = w.dx, w.dy 887 e.x, e.y, e.dx, e.dy = x + dx, y + dy, dx, dy 888 sprite_draw(e.x, e.y, c) 889 cell_set(e.x + dx, e.y + dy, c) 890 return 891end 892 893enemy_logic = function(i) 894 local ways = {} 895 local x, y, dx, dy 896 local e = enemies[i] 897 x, y, dx, dy = e.x, e.y, e.dx, e.dy 898 local c = enemy_cell(i) 899 if (x % 2 ~= 0) or (y % 2) ~= 0 then -- odd 900 c = enemy_halflife(c) 901 cell_set(x - dx, y - dy, BEMPTY) 902 sprite_draw(x - dx, y - dy, BEMPTY) 903 x, y = x + dx, y + dy 904 cell_set(x, y, c) 905 sprite_draw(x, y, c) 906 e.x, e.y = x, y 907 return 908 end 909 -- even, logic decision 910 local delta = -1 911 local half = true 912-- print "start" 913 while true do 914 local xm, ym 915 if half then 916 ym = y + delta * 2 917 xm = x 918 else 919 xm = x + delta * 2 920 ym = y 921 end 922 if xm >= 0 and ym >= 0 and xm < 32 and ym < 32 then 923 local cc = cell_get(xm, ym) 924 if (cc == BEMPTY or cc == BHUMAN) then 925 -- can walk 926 if half then 927 stead.table.insert(ways, { dx = 0, dy = delta }) 928 else 929 stead.table.insert(ways, { dx = delta, dy = 0 }) 930 end 931 end 932 end 933 if half then 934 half = false 935 -- continue 936 else -- flip 937 delta = - delta 938 if delta > 0 then -- another half 939 half = true 940 -- continue 941 else -- all scan is done 942 break 943 end 944 end 945 end 946-- print "break" 947 if #ways == 0 then 948 c = enemy_halflife(c) 949 cell_set(x, y, c) 950 sprite_draw(x, y, c) 951 return 952 end 953 if #ways > 1 then 954 -- do not walk backwards! 955 local i,k 956 for k,v in ipairs(ways) do 957 if v.dx == -e.dx and v.dy == - e.dy then 958 stead.table.remove(ways, k) 959 break 960 end 961 end 962 end 963 964 if #ways == 1 then -- only 1 path 965 enemy_turn(x, y, c, ways[1], e) 966 return 967 end 968 -- chose best one! 969 dx = player_x - x 970 dy = player_y - y 971 if dx < 0 then 972 dx = -1 973 else 974 dx = 1 975 end 976 if dy < 0 then 977 dy = -1 978 else 979 dy = 1 980 end 981 local best = 0 982 local best_w = ways[1] 983 for k,v in ipairs(ways) do 984 local new_best = dx + v.dx 985 local a = new_best 986 if new_best < 0 then new_best = - new_best end 987 local d = dy + v.dy 988 if d < 0 then d = - d end 989 new_best = new_best + d 990 if new_best > best then 991 best = new_best 992 best_w = v 993 end 994 end 995 enemy_turn(x, y, c, best_w, e) 996end 997 998enemy_cell = function(i) 999 local e = enemies[i] 1000 local x, y, dx, dy = e.x, e.y, e.dx, e.dy 1001 if (x % 2) ~= 0 then 1002 x = x - dx 1003 end 1004 if (y % 2) ~= 0 then 1005 y = y - dy 1006 end 1007 return cell_get(x, y) 1008end 1009 1010enemy = function() 1011 if #enemies == 0 then 1012 return 1013 end 1014 local x, y, dx, dy, c, i, e 1015 i = 1 1016 while true do 1017 if i > #enemies then 1018 break 1019 end 1020 e = enemies[i] 1021 x, y, dx, dy = e.x, e.y, e.dx, e.dy 1022 c = enemy_cell(i) 1023 if c ~= BFLY and c ~= BHEART and c ~= 20 and c ~= 21 then 1024 if (x % 2 ~= 0) or (y % 2) ~= 0 then 1025 x = x + dx 1026 y = y + dy 1027 cell_set(x, y, BEMPTY) 1028 sprite_draw(x, y, BEMPTY) 1029 end 1030 -- remove enemy 1031 stead.table.remove(enemies, i) 1032 else 1033 enemy_logic(i) 1034 i = i + 1 1035 end 1036 1037 end 1038 c = cell_get(player_x, player_y) 1039 if c == BHUMAN then 1040 return 1041 end 1042 if c < 12 or c >= 20 then 1043 return human_death(player_x, player_y) 1044 end 1045end 1046 1047history_name = function(nr) 1048 local n = banks[nr_bank].name 1049 if n == 'maps' then 1050 return "demo" 1051 end 1052 return "demo-"..n.."-" 1053end 1054 1055history_check = function(nr) 1056 local p = instead_gamepath().."/"..history_name()..tostring(nr + 1) 1057 local f = io.open(p, "r") 1058 if not f then 1059 p = instead_savepath().."/"..history_name()..tostring(nr + 1) 1060 f = io.open(p, "r") 1061 end 1062 if not f then 1063 return false 1064 end 1065 f:close() 1066 return true 1067end 1068 1069history_load = function() 1070 local p = instead_gamepath().."/"..history_name()..tostring(nr_level + 1) 1071 local f = io.open(p, "r") 1072 if not f then 1073 p = instead_savepath().."/"..history_name()..tostring(nr_level + 1) 1074 f = io.open(p, "r") 1075 end 1076 if not f then 1077 history = {} 1078 return 1079 end 1080 local l 1081 history = {} 1082 for l in f:lines() do 1083 local v = {} 1084 for a in l:gmatch("[0-9-]+") do 1085 stead.table.insert(v, tonumber(a)) 1086 end 1087 stead.table.insert(history, v) 1088 end 1089 f:close(p) 1090end 1091 1092history_store = function(n) 1093 local p = instead_savepath().."/"..history_name()..tostring(n + 1) 1094 local f = io.open(p, "w") 1095 local k,v 1096 for k,v in ipairs(history) do 1097 f:write(stead.string.format("%d %d %d\n", v[1], v[2], v[3])) 1098 end 1099 f:close(p) 1100end 1101 1102history_get = function() 1103 if #history == 0 then 1104 level_load() 1105 level_reset() 1106 return 0, 0 1107-- return 0, 0 1108 end 1109 local v = stead.table.remove(history, 1) 1110 v[3] = v[3] - 1 1111 if v[3] > 0 then 1112 stead.table.insert(history, 1, v) 1113 end 1114 return v[1], v[2] 1115end 1116 1117history_add = function(dx, dy) 1118 if #history == 0 then 1119 stead.table.insert(history, {dx, dy, 1}) 1120 return 1121 end 1122 local n = #history 1123 local v = history[n] 1124 if v[1] == dx and v[2] == dy then 1125 v[3] = v[3] + 1 1126 return 1127 end 1128 stead.table.insert(history, {dx, dy, 1}) 1129 return 1130end 1131 1132game_loop = function() 1133 if is_demo() and not demo_mode and history_check(nr_level) then 1134 level_load() 1135 level_reset() 1136 history_load() 1137 demo_mode = true 1138 return 1139 end 1140 1141 if demo_mode and is_anykey() then 1142 level_load() 1143 level_reset() 1144 return 1145 end 1146 if is_edit() then 1147 local new_mode = not edit_mode 1148 if edit_mode then 1149 level_store() 1150 bank_save() 1151 end 1152 level_load() 1153 level_reset() 1154 edit_mode = new_mode 1155 return 1156 end 1157 if edit_mode then 1158 edit_blink = not edit_blink 1159 local active_edit = false 1160 if is_key 'up' then 1161 active_edit = touch_max >= 1 1162 if acive_edit then cell_edit(player_x, player_y, active_edit); end 1163 sprite_draw(player_x, player_y, cell_get(player_x, player_y)); 1164 player_y = player_y - 2 1165 edit_blink = false 1166 elseif is_key 'down' then 1167 active_edit = touch_max >= 1 1168 if acive_edit then cell_edit(player_x, player_y, active_edit); end 1169 sprite_draw(player_x, player_y, cell_get(player_x, player_y)); 1170 player_y = player_y + 2 1171 edit_blink = false 1172 elseif is_key 'left' then 1173 active_edit = touch_max >= 1 1174 if acive_edit then cell_edit(player_x, player_y, active_edit); end 1175 sprite_draw(player_x, player_y, cell_get(player_x, player_y)); 1176 player_x = player_x - 2 1177 edit_blink = false 1178 elseif is_key 'right' then 1179 active_edit = touch_max >= 1 1180 if acive_edit then cell_edit(player_x, player_y, active_edit); end 1181 sprite_draw(player_x, player_y, cell_get(player_x, player_y)); 1182 player_x = player_x + 2 1183 edit_blink = false 1184 end 1185 if player_x < 0 then player_x = 0 end 1186 if player_x > 30 then player_x = 30 end 1187 if player_y < 0 then player_y = 0 end 1188 if player_y > 30 then player_y = 30 end 1189 1190 if is_return() or active_edit then 1191 edit_blink = true 1192 cell_edit(player_x, player_y, active_edit); 1193 elseif key_num then 1194 c = tonumber(key_num) 1195 cell_set(player_x, player_y, c) 1196 end 1197 1198 if not edit_blink then 1199 sprite.fill(sprite.screen(), player_x * 16, player_y * 16, 32, 32, "white"); 1200 else 1201 sprite_draw(player_x, player_y, cell_get(player_x, player_y)); 1202 end 1203 return 1204 end 1205 if nr_level == nr_levels and happy_end_spr_w then 1206 sprite.fill(sprite.screen(), (scr_w - happy_end_spr_w)/2, scr_h /2, happy_end_spr_w, scr_h / 2, "black") 1207 end 1208 1209 if (player_x % 2 == 0) and (player_y % 2 == 0) then 1210 player_movex, player_movey = 0, 0 1211 if is_key 'up' then 1212 player_movey = -1 1213 elseif is_key 'down' then 1214 player_movey = 1 1215 elseif is_key 'left' then 1216 player_movex = -1 1217 elseif is_key 'right' then 1218 player_movex = 1 1219 end 1220 if demo_mode then 1221 player_movex, player_movey = history_get() 1222 else 1223 history_add(player_movex, player_movey) 1224 end 1225 if player_movex ~= 0 or player_movey ~= 0 then 1226 local x, y = player_x + player_movex * 2, player_y + player_movey * 2 1227 if x <= 31 and y<= 31 and x >= 0 and y >= 0 then 1228 local c = cell_get(x, y) 1229 game_dispatch(c, x, y) 1230 else 1231 human_stop(x, y) 1232 end; 1233 else 1234 human_stop(x, y) 1235 end 1236 else -- inertion 1237 local x, y 1238 sprite_draw(player_x, player_y, BEMPTY) 1239 x, y = player_x - player_movex, player_y - player_movey 1240 local c = cell_get(x, y) 1241 if c == BHUMAN then 1242 cell_set(x, y, BEMPTY) 1243 elseif c == BGOLD or c == BSTONE then -- fix of the original game 1244 sprite_draw(x, y, c) 1245 end 1246 x, y = player_x + player_movex, player_y + player_movey 1247 c = cell_get(x, y) 1248 sprite_draw(x, y, c + 1) 1249 cell_set(x, y, BHUMAN) 1250 player_x, player_y = x, y 1251 end 1252 if menu_mode then 1253 return 1254 end 1255 fall(); 1256 if menu_mode then 1257 return 1258 end 1259 enemy(); 1260 1261 if nr_level == nr_levels then 1262 happy_end_render() 1263 end 1264 1265end 1266 1267orig_save = game.save 1268game.save = function(s, ...) 1269 if demo_mode then 1270 return 1271 end 1272 _G["_selected_level_"..banks[nr_bank].name] = selected_level -- old selection 1273 return orig_save(s, ...) 1274end 1275global { nr_bank = 1 }; 1276 1277function bank_load() 1278 if nr_bank > #banks then 1279 nr_bank = 1 1280 end 1281 dofile (banks[nr_bank].file) 1282 nr_levels = #maps / 16 1283 print (nr_levels.." level(s) loaded..."); 1284 local k,v 1285 for k,v in ipairs(happy_end_map) do 1286 stead.table.insert(maps, v) 1287 end 1288 if not _G["_selected_level_"..banks[nr_bank].name] then 1289 _G["_selected_level_"..banks[nr_bank].name] = 0 1290 end 1291 nr_level = _G["_selected_level_"..banks[nr_bank].name] 1292 if nr_level >= nr_levels then 1293 nr_level = 0 1294 end 1295 selected_level = nr_level -- new selection 1296end 1297 1298function bank_save() 1299 if nr_bank > #banks then 1300 return 1301 end 1302 local f = io.open(banks[nr_bank].file, "w") 1303 if not f then 1304 return 1305 end 1306 f:write(string.format("--$Name:%s\n", banks[nr_bank].title)); 1307 local k,v 1308 if banks[nr_bank].title_i18n then 1309 for k, v in pairs(banks[nr_bank].title_i18n) do 1310 f:write(string.format("--$Name(%s):%s\n", 1311 k, v)); 1312 end 1313 end 1314 f:write(string.format("maps = {\n")) 1315 for k = 1, nr_levels do 1316 f:write(string.format("-- %d\n", k - 1)); 1317 local n 1318 for n=1,16 do 1319 f:write(string.format('"%s",\n', maps[(k - 1) * 16 + n])) 1320 end 1321 end 1322 f:write(string.format("};\n")) 1323 f:close() 1324end 1325 1326init = function() 1327 set_music_fading(500, 500) 1328 hook_keys('left', 'right', 'up', 'down', 'space', 'return', 'd', 'escape', 'e', '0', '1', '2', '3', '4', '5', '6', '7'); 1329 load_sprites() 1330 load_sounds() 1331 offscreen = sprite.blank(scr_w, scr_h) 1332 banner = sprite.blank(scr_w, 32) 1333 sprite.fill(sprite.screen(), 'black'); 1334 level_select = true 1335 banks_init(); 1336end 1337 1338start = function() 1339 bank_load() 1340 if menu_mode ~= 'level_select' and menu_mode ~= 'title' and not demo_mode and menu_mode ~= 'bank_select' then 1341 level_load() 1342 level_movein() 1343 else 1344 title_enter() 1345 end 1346end 1347 1348dofile "i18n.lua" 1349dofile "menu.lua" 1350 1351main.nam = '!!!'; 1352main.dsc = function(s) 1353 p (_("warning:Please, go to settings and switch on own themes feature!")) 1354end 1355