*......,"","","","","",""<33<33<3333<̪̬ʬ̬̬̬ "" "" " ""    """""" ""     "" ""      ""      "" "   "" ""  ""   ""      ""@DD@@DD@@@,",","""",33>33>33>33>3333lllfflffll̜̜ɜ̜ """+"""!"""" "!"" ,,,""""  """ """"""""""?  >~@ @ @ @ @ @ @ @ @@@@ @ @ @ @        g>  """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" """"""""""""""""""""""""""""" """"""""""""" """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" f`ff``ffff`f`f `f`````ff`f`````f`f``ff`fff`ff`ff`````f  "" "+" ""! """" "! ""  """"""""""""" on-- title: The Exciting Cube -- author: Ttalgi Bit -- desc: Matching the cubes isn’t enough with just gravity; you need to spice it up with a gravity + bomb sequence. -- script: lua -- saveid: the-exciting-cube -- Licensed: EULA -- Copyright 2025 Ttalgi Bit version="v1.60" -- === SABİTLER (CONSTANTS) === EMPTY = 0 WALL = 1 BOX_A = 2 BOX_B = 3 BOX_C = 4 BOX_D = 18 BOX_E = 19 BOX_F = 20 BOMB = 16 STONE = 17 SPR_LOGO_START = 21 -- Müzik Listesi MUS_MENU = 0 MUS_GAME = 1 MUS_WIN = 2 MUS_GAMEOVER = 3 MUS_ENDING = 4 -- BÖLÜM İSİMLERİ LEVEL_NAMES = { [0] = "A REAL BEGIN", [1] = "BOMB LEGEND", [2] = "UP & DOWN", [3] = "BOMB THE WALL", [4] = "PYRAMID HELL", [5] = "THE FIRST TRAP", [6] = "EASY BEASY", [7] = "PLATFORMER TIME", [8] = "THIRD PROBLEMS", [9] = "GRAVITY FALLS", [10] = "CRYSTAL CUBE", [11] = "ALPHABET E", [12] = "JAIL METERS", [13] = "8-BIT HOME", [14] = "TETROMINO TIME", [15] = "MATH SYMBOL", [16] = "PACKAGE ERROR", [17] = "8-BIT CONTROLLER", [18] = "PLUS OF POWER", [19] = "LOOP OF PERIPHRASIS", [20] = "REAL OR NOT REAL LIFE", [21] = "SEVENTLY-SEVEN", [22] = "KID GAME", [23] = "NOSTALGIA DAYS", [24] = "UNDERWATER WORLD", [25] = "THE MINI CUBE", [26] = "SPACESHIP", [27] = "POWER OF INFINITY", [28] = "JAIL OF BATHROOM", [29] = "WORLD OF WATER'SOM", [30] = "LIGHTING OF MY HOME", [31] = "AGG LETTERS TIME" } -- === TEK ŞİFRE LİSTESİ === LEVEL_CODES = { [0] = "START", [1] = "BOOMS", [2] = "GRAVY", [3] = "WALLS", [4] = "HELLP", [5] = "TRAP1", [6] = "EASYB", [7] = "TIMEP", [8] = "THIRD", [9] = "FALLS", [10] = "CRYST", [11] = "FIVEA", [12] = "JAILS", [13] = "8HOME", [14] = "RUSIA", [15] = "MATHS", [16] = "PEROR", [17] = "NESFC", [18] = "PLUS0", [19] = "DAIRE", [20] = "WREAL", [21] = "22LVL", [22] = "KIDGM", [23] = "VIANO", [24] = "NDRWR", [25] = "MINI0", [26] = "SPACE", [27] = "INF28", [28] = "HOMEJ", [29] = "SUDOS", [30] = "LMH00", [31] = "SIGNA" } -- === PASSWORD SİSTEMİ === STATE_PASSWORD = 100 PASS_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" pass_indices = {1, 1, 1, 1, 1} pass_cursor = 1 pass_msg = "" -- Hile Modu cheat_mode = false -- Ses Efektleri SFX_GRAB = 0 SFX_LAND = 1 SFX_EXPLODE = 2 SFX_WIN = 3 SFX_LOSE = 4 -- Renkler C_BG = 0 C_FG = 12 C_ACCENT = 13 C_ALERT = 3 C_WIN = 11 C_HUD_BG = 1 C_BAR_BG = 0 C_MOOD = 9 C_TTALGI = 2 -- Oyun Durumları STATE_MENU = 0 STATE_IDLE = 1 STATE_FALLING = 2 STATE_MATCHING = 3 STATE_WIN = 4 STATE_GAMEOVER = 5 STATE_ANIM_EXPLODE= 6 STATE_THE_END = 7 STATE_LEVEL_START = 8 STATE_SECRET_ROOM = 99 -- === DEĞİŞKENLER === state = STATE_MENU anim_timer = 0 level_time = 0 score = 0 current_level = 0 max_reached_level = 0 level_start_score = 0 floating_scores = {} win_particles = {} stars = {} exploding_list = {} -- Ayarlar MAX_LEVELS = 63 LEVEL_DURATION = 60 * 120 MAP_W = 30 MAP_H = 17 ROOM_W = 30 ROOM_H = 17 TILE_SIZE = 8 -- Ekran Yerleşimi SIDEBAR_X = 140 SCREEN_H = 136 OFFSET_X = 0 OFFSET_Y = 0 -- Mouse dragging = false drag_tile = EMPTY drag_start_x = -1 drag_start_y = -1 limit_min_x = 0 limit_max_x = MAP_W - 1 -- Karakter Sprite'ları CHAR_SPRITES = { E = 6, X = 7, I = 9, C = 8, T = 10, N = 11, G = 12, B = 13, U = 14 } -- === YARDIMCI FONKSİYONLAR === function is_player_box(t) return t == BOX_A or t == BOX_B or t == BOX_C or t == BOX_D or t == BOX_E or t == BOX_F end function can_drag(t) return is_player_box(t) or t == BOMB end function is_heavy(t) return is_player_box(t) or t == BOMB end function zeropad(num, width) return string.format("%0" .. width .. "d", math.floor(num)) end -- Ekrana blok sayılarını çizen fonksiyon function draw_block_counts() local counts = {} for y = 0, MAP_H - 1 do for x = 0, MAP_W - 1 do local t = mget(x, y) if is_player_box(t) then counts[t] = (counts[t] or 0) + 1 end end end if dragging and is_player_box(drag_tile) then counts[drag_tile] = (counts[drag_tile] or 0) + 1 end local types_to_draw = {} local check_list = {BOX_A, BOX_B, BOX_C, BOX_D, BOX_E, BOX_F} for _, t in ipairs(check_list) do if counts[t] and counts[t] > 0 then table.insert(types_to_draw, {t = t, c = counts[t]}) end end -- Eğer çizilecek blok varsa hesaplama yap ve arka planı temizle if #types_to_draw > 0 then local item_width = 18 local total_w = #types_to_draw * item_width local start_x = (160 - total_w) // 2 -- [YENİ EKLENEN KISIM] -- Yazıların ve ikonların arkasına siyah kutu çiz (x, y, w, h, renk_kodu) -- Biraz kenar boşluğu (padding) ekleyerek daha temiz görünmesini sağlıyoruz. rect(start_x - 4, 0, total_w + 8, 13, 0) for i, item in ipairs(types_to_draw) do local dx = start_x + (i-1) * item_width spr(item.t, dx, 2, 0) print(item.c, dx + 9, 4, 12, true, 1, true) end end end -- === BAŞLANGIÇ (BOOT) === function BOOT() state = STATE_MENU max_reached_level = pmem(0) music(MUS_MENU) stars = {} for i = 1, 60 do table.insert(stars, { x = math.random(0, 240), y = math.random(0, 136), speed = math.random(1, 5) / 10.0 }) end end -- === BÖLÜM YÜKLEME === -- === BÖLÜM YÜKLEME === function load_level(lvl) if lvl > MAX_LEVELS then state = STATE_THE_END music(MUS_ENDING) return end current_level = lvl if current_level > max_reached_level then max_reached_level = current_level pmem(0, max_reached_level) end level_time = LEVEL_DURATION if state ~= STATE_GAMEOVER then level_start_score = score else score = level_start_score end sync(0, 0, false) -- === GÖRSELDEKİ IZGARAYA GÖRE HESAPLAMA === -- Görseldeki ızgarada bir satırda 8 tane bölüm var (240 / 30 = 8) local levels_per_row = 8 local map_col = lvl % levels_per_row local map_row = lvl // levels_per_row -- Harita editöründeki başlangıç koordinatlarını bul (30x17'lik adımlarla) local map_offset_x = map_col * ROOM_W local map_offset_y = map_row * ROOM_H -- Bölümü kopyala for y = 0, MAP_H - 1 do for x = 0, MAP_W - 1 do -- Editördeki doğru kutucuktan veriyi al local t = mget(map_offset_x + x, map_offset_y + y) -- Oyun alanının sol üst köşesine (0,0) yapıştır mset(x, y, t) end end state = STATE_LEVEL_START anim_timer = 0 exploding_list = {} floating_scores = {} win_particles = {} music(MUS_GAME) end function in_bounds(x, y) return x >= 0 and x < MAP_W and y >= 0 and y < MAP_H end function get_drag_limits(sx, sy) local min_x = 0 local max_x = MAP_W - 1 for x = sx - 1, 0, -1 do if mget(x, sy) ~= EMPTY then min_x = x + 1 break end end for x = sx + 1, MAP_W - 1 do if mget(x, sy) ~= EMPTY then max_x = x - 1 break end end return min_x, max_x end -- === FİZİK VE EŞLEŞTİRME === function apply_gravity_step() local moved = false for y = MAP_H - 2, 0, -1 do for x = 0, MAP_W - 1 do local c = mget(x, y) if is_heavy(c) then if mget(x, y + 1) == EMPTY then mset(x, y + 1, c) mset(x, y, EMPTY) moved = true end end end end return moved end function find_matches() exploding_list = {} local matched_positions = {} local found = false local processed = {} for y = 0, MAP_H - 1 do for x = 0, MAP_W - 1 do local c = mget(x, y) if is_player_box(c) then local neighbors = {} local dirs = {{1,0}, {-1,0}, {0,1}, {0,-1}} for _, d in ipairs(dirs) do local nx, ny = x + d[1], y + d[2] if in_bounds(nx, ny) and mget(nx, ny) == c then table.insert(neighbors, {nx, ny}) end end if #neighbors > 0 then table.insert(matched_positions, {x, y}) for _, n in ipairs(neighbors) do table.insert(matched_positions, n) end end end end end for _, pos in ipairs(matched_positions) do local key = pos[1].."-"..pos[2] if not processed[key] then table.insert(exploding_list, pos) processed[key] = true found = true end end return found end function remove_exploded_blocks() local count = 0 local score_count = 0 local total_x = 0 local total_y = 0 for _, pos in ipairs(exploding_list) do local t = mget(pos[1], pos[2]) if t ~= WALL and t ~= EMPTY then if is_player_box(t) then score_count = score_count + 1 end mset(pos[1], pos[2], EMPTY) count = count + 1 total_x = total_x + (pos[1] * 8 + OFFSET_X) total_y = total_y + (pos[2] * 8 + OFFSET_Y) end end if count > 0 then sfx(SFX_EXPLODE, "C-5", 16, 0) end if score_count > 0 then local points = score_count * 10 if score_count > 2 then points = points + 50 end score = score + points local avg_x = total_x / count local avg_y = total_y / count table.insert(floating_scores, { x = avg_x - 8, y = avg_y, val = points, timer = 60, c = 12 }) end exploding_list = {} end function check_level_clear() for y = 0, MAP_H - 1 do for x = 0, MAP_W - 1 do local c = mget(x, y) if is_player_box(c) then return false end end end return true end -- === ÇİZİM FONKSİYONLARI === function draw_sprite_text(str, x, y, scale) local sprite_size = 8 * scale local cursor_x = x for i = 1, #str do local char = string.sub(str, i, i) local sprite_id = CHAR_SPRITES[char] if sprite_id then spr(sprite_id, cursor_x, y, 0, scale) end cursor_x = cursor_x + sprite_size end end function update_atmosphere() if score < 1000 then C_MOOD = 9 elseif score < 2500 then C_MOOD = 13 else C_MOOD = 3 end end function draw_background() cls(0) for _, s in ipairs(stars) do s.y = s.y + s.speed if s.y > 136 then s.y = 0; s.x = math.random(0, 240) end local star_col = C_MOOD if s.speed < 0.3 then star_col = 14 end pix(s.x, s.y, star_col) end end function draw_hud() local sidebar_x = SIDEBAR_X local sidebar_w = 240 - sidebar_x rect(sidebar_x, 0, sidebar_w, 136, C_HUD_BG) line(sidebar_x, 0, sidebar_x, 136, C_MOOD) local panel_y = 10 rect(sidebar_x + 4, panel_y, sidebar_w - 8, 9, C_MOOD) print("LEVEL", 180, panel_y + 2, C_BG) local lvl_display = zeropad(current_level + 1, 2) print(lvl_display, 176, panel_y + 14, C_FG, false, 3) panel_y = 55 rect(sidebar_x + 4, panel_y, sidebar_w - 8, 9, C_MOOD) print("SCORE", 180, panel_y + 2, C_BG) print(zeropad(score, 6), 164, panel_y + 14, C_WIN, false, 2) panel_y = 95 rect(sidebar_x + 4, panel_y, sidebar_w - 8, 9, C_MOOD) print("TIME", 182, panel_y + 2, C_BG) local seconds = math.ceil(level_time / 60) local time_color = C_FG if seconds < 20 then time_color = 6 end if seconds < 10 then time_color = C_ALERT end print(zeropad(seconds, 3), 176, panel_y + 14, time_color, false, 2) local bar_max_w = sidebar_w - 12 local bar_h = 4 local bar_x = sidebar_x + 6 local bar_y = panel_y + 28 rect(bar_x, bar_y, bar_max_w, bar_h, C_BAR_BG) local fill_w = (level_time / LEVEL_DURATION) * bar_max_w rect(bar_x, bar_y, fill_w, bar_h, time_color) print("[X] RESTART", sidebar_x + 10, 128, 5, false, 1, true) if cheat_mode then print("DEBUG ON", sidebar_x + 10, 115, 6) end end function draw_menu() draw_background() print("THE", 58, 25, 12, false, 1, true) draw_sprite_text("EXCITING", 56, 30, 2) draw_sprite_text("CUBE", 88, 45, 2) print("[Z] START", 100, 80, 6) print("[X] PASSWORD", 85, 90, 13, true) local logo_x = 90 local logo_y = 115 spr(21, logo_x, logo_y, 0, 1) spr(22, logo_x + 8, logo_y, 0, 1) spr(23, logo_x + 16, logo_y, 0, 1) spr(24, logo_x + 24, logo_y, 0, 1) spr(25, logo_x + 32, logo_y, 0, 1) spr(37, logo_x, logo_y + 8, 0, 1) spr(38, logo_x + 8, logo_y + 8, 0, 1) spr(39, logo_x + 16, logo_y + 8, 0, 1) spr(40, logo_x + 24, logo_y + 8, 0, 1) spr(41, logo_x + 32, logo_y + 8, 0, 1) print("2025", logo_x + 45, logo_y + 4, 13, true) print("V1.60", 210,128,13) end function draw_gameover() cls(0) local shake_x = math.random(-2, 2) local shake_y = math.random(-2, 2) print("TIME UP!", 62 + shake_x, 32 + shake_y, 1, true, 3) print("TIME UP!", 60 + shake_x, 30 + shake_y, C_ALERT, true, 3) rectb(65, 70, 110, 35, C_ALERT) print("FINAL SCORE", 92, 75, 12, false, 1, true) print(zeropad(score, 6), 82, 86, 12, false, 2) if (anim_timer % 40) < 20 then print("PRESS [Z] TO RETRY", 75, 120, 6, false, 1, true) end end function draw_the_end() draw_background() local rainbow_col = (anim_timer // 15) % 15 + 1 local title = "CONGRATULATIONS" print(title, (240 - print(title, 0, -20, 0, false, 2))//2, 30, rainbow_col, true, 2) local jump_1 = (anim_timer % 30 < 15) and -4 or 0 local jump_2 = (anim_timer % 30 >= 15) and -4 or 0 spr(BOX_A, 52, 60 + jump_1, 0, 2) spr(BOX_B, 92, 60 + jump_2, 0, 2) spr(BOX_C, 132, 60 + jump_2, 0, 2) spr(BOX_D, 172, 60 + jump_1, 0, 2) print("FINAL SCORE: " .. zeropad(score, 6), 70, 95, 11, true) if (anim_timer % 40) < 20 then print("PRESS Z TO RESTART", 80, 120, 6, false, 1, true) end end -- === GİZLİ ODA ÇİZİMİ === function draw_secret_room() cls(0) if anim_timer % 5 == 0 then for i=1, 20 do pix(math.random(0,240), math.random(0,136), math.random(1,15)) end end local title = "EASTER EGG" print(title, (240 - print(title, 0, -20, 0, false, 3))//2, 20, 11, false, 3) local msg1 = "TTALGI BIT BY ORTHOPEDICALLY DISABLED" local msg2 = "GAME BY TURKISH DEVELOPER" local msg3 = "A DEVELOPER WHO LOVES KOREA" print(msg1, (240 - print(msg1, 0, -20))//2, 60, 12, true) print(msg2, (240 - print(msg2, 0, -20))//2, 75, 13, true) print(msg3, (240 - print(msg3, 0, -20))//2, 90, 13, true) local spr_x = 120 - 16 local spr_y = 105 + math.sin(anim_timer * 0.1) * 5 print("PRESS Z TO RETURN", 85, 128, 6, false, 1, true) end function draw_password_screen() cls(0) local title = "ENTER PASSWORD" print(title, (240 - print(title, 0, -20, 0, false, 2))//2, 20, 12, false, 2) local start_x = 72 local start_y = 60 for i = 1, 5 do local char_idx = pass_indices[i] local char = string.sub(PASS_CHARS, char_idx, char_idx) local box_col = (i == pass_cursor) and 12 or 2 local txt_col = (i == pass_cursor) and 2 or 12 rect(start_x + (i*18), start_y, 16, 18, box_col) print(char, start_x + (i*18) + 5, start_y + 6, txt_col) -- GÜNCELLEME BURADA YAPILDI: -- Eskiden BOX_A (2) çiziyorduk, şimdi 25 çiziyoruz. if i == pass_cursor then spr(26, start_x + (i*18) + 4, start_y + 15) end end print("^/v : CHANGE CHAR", 80, 100, 13) print("< > : MOVE CURSOR", 80, 110, 13) print("[Z] CONFIRM [X] BACK", 70, 125, 14) if pass_msg ~= "" then print(pass_msg, (240 - print(pass_msg, 0, -20))//2, 45, 6, true) end end function draw_game() draw_background() for y = 0, MAP_H - 1 do for x = 0, MAP_W - 1 do local t = mget(x, y) if t ~= EMPTY then local is_exploding = false if state == STATE_ANIM_EXPLODE then for _, pos in ipairs(exploding_list) do if pos[1] == x and pos[2] == y then is_exploding = true break end end end -- GÜNCELLEME: Patlayan nesneyi gizleme! -- Nesne, patlama efekti (rect/circ) ile üst üste çizilsin. -- Böylece patlama anında taş yok olmuş gibi durmaz, "patlıyormuş" gibi durur. spr(t, x * 8 + OFFSET_X, y * 8 + OFFSET_Y) end end end if state == STATE_ANIM_EXPLODE then local t = anim_timer for _, pos in ipairs(exploding_list) do local px = pos[1] * 8 + 4 + OFFSET_X local py = pos[2] * 8 + 4 + OFFSET_Y circ(px, py, t/3, 12) if t % 4 < 2 then line(px-3, py-3, px+3, py+3, 11) line(px+3, py-3, px-3, py+3, 11) end rectb(px - (8-t/4), py - (8-t/4), (16-t/2), (16-t/2), 6) end end if dragging then local mx, my = mouse() local gx = math.floor((mx - OFFSET_X) / 8) if gx < limit_min_x then gx = limit_min_x end if gx > limit_max_x then gx = limit_max_x end spr(drag_tile, gx * 8 + OFFSET_X, drag_start_y * 8 + OFFSET_Y) rectb(gx*8 + OFFSET_X, drag_start_y*8 + OFFSET_Y, 8, 8, 6) end if state == STATE_WIN then for _, p in ipairs(win_particles) do rect(p.x, p.y, 2, 2, p.c) end local text = "LEVEL CLEARED!" for i = 1, #text do local char = string.sub(text, i, i) local wave_y = math.sin((anim_timer + i * 2) * 0.1) * 4 local col = (math.floor(anim_timer / 2) + i) % 15 + 1 print(char, 40 + (i * 6), 60 + wave_y, col, true) end end for _, fs in ipairs(floating_scores) do local txt = "+" .. fs.val print(txt, fs.x, fs.y, (fs.timer < 20 and anim_timer % 4 < 2) and 6 or 12, true) end draw_block_counts() draw_hud() if state == STATE_LEVEL_START then local door_h = 70 local open_start_time = 180 local open_amt = 0 if anim_timer > open_start_time then open_amt = (anim_timer - open_start_time) * 4 end rect(0, 0 - open_amt, 240, door_h, 14) rect(0, 136 - door_h + open_amt, 240, door_h, 14) if anim_timer < (open_start_time + 5) then if anim_timer > 150 then local ready_txt = "READY?" local w = print(ready_txt, 0, -20) print(ready_txt, (240 - w)//2, 64, 12, true) else local lvl_num_str = "LEVEL " .. (current_level + 1) local lvl_name_str = LEVEL_NAMES[current_level] or "SECTOR " .. (current_level+1) local w_num = print(lvl_num_str, 0, -20) print(lvl_num_str, (240 - w_num)//2, 45, 6, true) local w_name = print(lvl_name_str, 0, -20) print(lvl_name_str, (240 - w_name)//2, 55, 12, true) local pass_code = LEVEL_CODES[current_level] or "?????" local pass_text = "PASS: " .. pass_code local w_pass = print(pass_text, 0, -20) print(pass_text, (240 - w_pass)//2, 75, 13, true) end end end end function draw() if state == STATE_MENU then draw_menu() elseif state == STATE_PASSWORD then draw_password_screen() elseif state == STATE_GAMEOVER then draw_gameover() elseif state == STATE_THE_END then draw_the_end() elseif state == STATE_SECRET_ROOM then draw_secret_room() else draw_game() end end -- === OYUN DÖNGÜSÜ (MAIN LOOP) === function TIC() anim_timer = anim_timer + 1 update_atmosphere() if state == STATE_MENU then if btnp(4) then score = 0; load_level(0) end if btnp(5) then state = STATE_PASSWORD pass_msg = "" pass_indices = {1, 1, 1, 1, 1} end draw() elseif state == STATE_PASSWORD then if btnp(2) then pass_cursor = pass_cursor - 1 end if btnp(3) then pass_cursor = pass_cursor + 1 end if pass_cursor < 1 then pass_cursor = 5 end if pass_cursor > 5 then pass_cursor = 1 end if btnp(0) then pass_indices[pass_cursor] = pass_indices[pass_cursor] - 1 if pass_indices[pass_cursor] < 1 then pass_indices[pass_cursor] = #PASS_CHARS end end if btnp(1) then pass_indices[pass_cursor] = pass_indices[pass_cursor] + 1 if pass_indices[pass_cursor] > #PASS_CHARS then pass_indices[pass_cursor] = 1 end end if btnp(5) then state = STATE_MENU end if btnp(4) then local entered = "" for i=1,5 do entered = entered..string.sub(PASS_CHARS, pass_indices[i], pass_indices[i]) end if entered == "TEC80" then cheat_mode = true sfx(SFX_WIN, "D-4", 20, 0) pass_msg = "CHEAT ENABLED!" elseif entered == "TALGI" then sfx(SFX_WIN, "E-5", 30, 0) state = STATE_SECRET_ROOM cheat_mode = false anim_timer = 0 else local found_level = -1 for lvl, code in pairs(LEVEL_CODES) do if code == entered then found_level = lvl break end end if found_level >= 0 then sfx(SFX_WIN, "C-6", 12, 0) score = 0; load_level(found_level) else sfx(SFX_LOSE, "A-3", 12, 0) pass_msg = "INVALID PASSWORD!" end end end draw_password_screen() elseif state == STATE_SECRET_ROOM then if btnp(4) then state = STATE_MENU end draw_secret_room() elseif state == STATE_GAMEOVER then if btnp(4) then load_level(current_level) end draw() elseif state == STATE_THE_END then if btnp(4) then state = STATE_MENU; score = 0 end draw() elseif state == STATE_LEVEL_START then if anim_timer == 180 then sfx(SFX_LAND, "C-3", 12, 0) end if anim_timer > 220 then state = STATE_IDLE; anim_timer = 0 end draw() else -- OYUN İÇİ MANTIK (STATE_IDLE, FALLING vb.) if state == STATE_IDLE or state == STATE_FALLING or state == STATE_MATCHING then if level_time > 0 then level_time = level_time - 1 else sfx(SFX_LOSE, "E-3", 30, 1) music(MUS_GAMEOVER) state = STATE_GAMEOVER draw(); return end end if state == STATE_IDLE then if cheat_mode and btnp(4) then sfx(SFX_WIN, "E-5", 10, 1) load_level(current_level + 1) return end if btnp(5) then score = level_start_score; load_level(current_level); return end local mx, my, left = mouse() local gx = math.floor((mx - OFFSET_X) / 8) local gy = math.floor((my - OFFSET_Y) / 8) if left then -- MOUSE BASILI İKEN if not dragging then -- HENÜZ TUTMAMIŞSAK: TUTMA İŞLEMİ if in_bounds(gx, gy) then local t = mget(gx, gy) local is_floating = (gy < MAP_H - 1) and (mget(gx, gy + 1) == EMPTY) if can_drag(t) and not is_floating then drag_tile = t drag_start_x, drag_start_y = gx, gy limit_min_x, limit_max_x = get_drag_limits(gx, gy) mset(gx, gy, EMPTY) dragging = true sfx(SFX_GRAB, "C-4", 8, 0) end end else -- ZATEN TUTUYORSAK: BOŞLUĞA DÜŞME KONTROLÜ (MOUSE İLE SÜRÜKLERKEN DÜŞME) -- Görsel gx'i limitlere sıkıştır local visual_gx = gx if visual_gx < limit_min_x then visual_gx = limit_min_x end if visual_gx > limit_max_x then visual_gx = limit_max_x end -- Eğer sürüklenen yerin altı boşsa, oyuncu bırakmasa bile taş düşmeli local ground_check = true if drag_start_y < MAP_H - 1 then if mget(visual_gx, drag_start_y + 1) == EMPTY then ground_check = false end end if ground_check == false then mset(visual_gx, drag_start_y, drag_tile) state = STATE_FALLING anim_timer = 0 sfx(SFX_GRAB, "E-4", 8, 0) drag_tile = EMPTY; dragging = false end end else -- MOUSE BIRAKILDIĞINDA (DROP İŞLEMİ) if dragging then dragging = false local target_stone_pos = nil -- 1. BOMBA KONTROLÜ (DUVARLARI DA PATLATIR ARTIK) if drag_tile == BOMB then -- Sağ kontrol if gx > limit_max_x and in_bounds(limit_max_x + 1, drag_start_y) then local t_chk = mget(limit_max_x + 1, drag_start_y) if t_chk == STONE or t_chk == WALL then target_stone_pos = {limit_max_x + 1, drag_start_y} end end -- Sol kontrol if gx < limit_min_x and in_bounds(limit_min_x - 1, drag_start_y) then local t_chk = mget(limit_min_x - 1, drag_start_y) if t_chk == STONE or t_chk == WALL then target_stone_pos = {limit_min_x - 1, drag_start_y} end end end if target_stone_pos then -- PATLAMA GERÇEKLEŞİYOR sfx(SFX_EXPLODE, "C-5", 16, 0) state = STATE_ANIM_EXPLODE; anim_timer = 0 table.insert(exploding_list, {target_stone_pos[1], target_stone_pos[2]}) local tx, ty = target_stone_pos[1], target_stone_pos[2] -- Zincirleme patlama (Duvar ve Taş) for py = -1, 1 do for px = -1, 1 do if not (px == 0 and py == 0) then local ex, ey = tx + px, ty + py if in_bounds(ex, ey) then local et = mget(ex, ey) if et == STONE then table.insert(exploding_list, {ex, ey}) end end end end end drag_tile = EMPTY -- Bomba yok oldu else -- 2. NORMAL BIRAKMA (GERİ FIRLAMAYI ÖNLEYEN KISIM) -- Mouse nereye giderse gitsin, taşı limitlerin içinde tutuyoruz (Clamp) local final_x = gx if final_x < limit_min_x then final_x = limit_min_x end if final_x > limit_max_x then final_x = limit_max_x end -- Hedef boşsa (ki limit hesabı doğruysa boş olmalı) koy if mget(final_x, drag_start_y) == EMPTY then mset(final_x, drag_start_y, drag_tile) state = STATE_FALLING -- Koyar koymaz düşme kontrolü yap anim_timer = 0 sfx(SFX_GRAB, "E-4", 8, 0) else -- Çok nadir hata durumu (Yine de güvenli olsun diye) mset(drag_start_x, drag_start_y, drag_tile) end drag_tile = EMPTY end end end -- Yerçekimi kontrolü (Sürükleme yokken) if not dragging and (anim_timer % 10 == 0) then if apply_gravity_step() then state = STATE_FALLING end end elseif state == STATE_FALLING then if anim_timer % 5 == 0 then if not apply_gravity_step() then sfx(SFX_LAND, "A-2", 6, 0) state = STATE_MATCHING; anim_timer = 0 end end elseif state == STATE_MATCHING then if anim_timer > 5 then local found = find_matches() if found then state = STATE_ANIM_EXPLODE; anim_timer = 0 else if check_level_clear() then state = STATE_WIN; sfx(SFX_WIN, "C-5", 60, 2); music(MUS_WIN); anim_timer = 0 local bonus = 100 score = score + bonus table.insert(floating_scores, {x = 110, y = 85, val = bonus, timer = 120, c = 11}) win_particles = {} for i = 1, 50 do table.insert(win_particles, {x = 80, y = 68, vx = math.random(-30, 30)/10.0, vy = math.random(-40, -10)/10.0, c = math.random(1, 15)}) end else state = STATE_IDLE end end end elseif state == STATE_ANIM_EXPLODE then if anim_timer > 30 then remove_exploded_blocks() state = STATE_FALLING; anim_timer = 0 end elseif state == STATE_WIN then for _, p in ipairs(win_particles) do p.x = p.x + p.vx; p.y = p.y + p.vy; p.vy = p.vy + 0.1 end if anim_timer > 180 then load_level(current_level + 1) end end for i = #floating_scores, 1, -1 do local fs = floating_scores[i] fs.y = fs.y - 0.5; fs.timer = fs.timer - 1 if fs.timer <= 0 then table.remove(floating_scores, i) end end draw() end end