#define MINESWEEPER_BEGINNER 1 #define MINESWEEPER_INTERMEDIATE 2 #define MINESWEEPER_EXPERT 3 #define MINESWEEPER_CUSTOM 4 #define MINESWEEPER_CONTINUE 0 #define MINESWEEPER_DEAD 1 #define MINESWEEPER_VICTORY 2 #define MINESWEEPER_IDLE 3 /datum/computer_file/program/minesweeper filename = "minesweeper" filedesc = "Nanotrasen Micro Arcade: Minesweeper" program_icon_state = "arcade" extended_desc = "A port of the classic game 'Minesweeper', redesigned to run on tablets." requires_ntnet = FALSE network_destination = "arcade network" size = 6 tgui_id = "NtosMinesweeper" program_icon = "gamepad" var/datum/minesweeper/board /datum/computer_file/program/minesweeper/New(obj/item/modular_computer/comp) . = ..() board = new /datum/minesweeper() board.emaggable = FALSE board.host = comp /datum/computer_file/program/minesweeper/Destroy() board.host = null QDEL_NULL(board) . = ..() /datum/computer_file/program/minesweeper/ui_assets(mob/user) return list( get_asset_datum(/datum/asset/simple/minesweeper), ) /datum/computer_file/program/minesweeper/ui_data(mob/user) var/list/data = get_header_data() data["board_data"] = board.board_data data["game_status"] = board.game_status data["difficulty"] = board.diff_text(board.difficulty) data["current_difficulty"] = board.current_difficulty data["emagged"] = FALSE data["flag_mode"] = board.flag_mode data["tickets"] = board.ticket_count data["flags"] = board.flags data["current_mines"] = board.current_mines data["custom_height"] = board.custom_height data["custom_width"] = board.custom_width data["custom_mines"] = board.custom_mines var/display_time = (board.time_frozen ? board.time_frozen : REALTIMEOFDAY - board.starting_time) / 10 data["time_string"] = board.starting_time ? "[add_leading(num2text(FLOOR(display_time / 60,1)), 2, "0")]:[add_leading(num2text(display_time % 60), 2, "0")]" : "00:00" return data /datum/computer_file/program/minesweeper/ui_act(action, list/params, mob/user) if(..()) return TRUE if(!board) return if(!board.host && computer) board.host = computer var/obj/item/computer_hardware/printer/printer if(istype(board.host, /obj/item/modular_computer)) var/obj/item/modular_computer/comp = board.host printer = comp.all_components[MC_PRINT] switch(action) if("PRG_do_tile") var/x = params["x"] var/y = params["y"] var/flagging = params["flag"] if(!x || !y) return return board.do_tile(x,y,flagging,user) if("PRG_new_game") board.play_snd('yogstation/sound/arcade/minesweeper_boardpress.ogg') return board.new_game() if("PRG_difficulty") var/diff = params["difficulty"] if(!diff) return board.play_snd('yogstation/sound/arcade/minesweeper_boardpress.ogg') return board.change_difficulty(diff) if("PRG_height") var/cin = params["height"] if(!cin) return return board.set_custom_height(cin) if("PRG_width") var/cin = params["width"] if(!cin) return cin = text2num(cin) if(cin < 5 || cin > 30) cin = clamp(cin, 5, 30) board.custom_width = cin board.custom_mines = min(board.custom_mines, FLOOR(board.custom_width*board.custom_height/2,1)) board.difficulty = MINESWEEPER_CUSTOM return TRUE if("PRG_mines") var/cin = params["mines"] if(!cin) return cin = text2num(cin) if(cin < 5 || cin > FLOOR(board.custom_width*board.custom_height/2,1)) cin = clamp(cin, 5, FLOOR(board.custom_width*board.custom_height/2,1)) board.custom_mines = cin board.difficulty = MINESWEEPER_CUSTOM return TRUE if("PRG_toggle_flag") board.play_snd('yogstation/sound/arcade/minesweeper_boardpress.ogg') board.flag_mode = !board.flag_mode return TRUE if("PRG_tickets") board.play_snd('yogstation/sound/arcade/minesweeper_boardpress.ogg') if(!printer && istype(board.host, /obj/item/modular_computer)) computer.visible_message(span_notice("Hardware error: A printer is required to redeem tickets.")) return if(printer.stored_paper <= 0 && istype(board.host, /obj/item/modular_computer)) computer.visible_message(span_notice("Hardware error: Printer is out of paper.")) return else computer.visible_message(span_notice("\The [computer] prints out paper.")) if(board.ticket_count >= 1) new /obj/item/stack/arcadeticket((get_turf(computer)), 1) to_chat(user, span_notice("[src] dispenses a ticket!")) board.ticket_count -= 1 printer.stored_paper -= 1 else to_chat(user, span_notice("You don't have any stored tickets!")) return TRUE /datum/minesweeper var/ticket_count = 0 var/flag_mode = FALSE var/flags = 0 var/current_mines = 10 var/difficulty = MINESWEEPER_BEGINNER var/value = MINESWEEPER_BEGINNER var/current_difficulty = "Beginner" var/starting_time = 0 var/time_frozen = 0 var/custom_height = 10 var/custom_width = 10 var/custom_mines = 10 var/game_status = MINESWEEPER_IDLE var/board_data[31][18] var/mine_spots = list() var/height = 10 var/width = 10 var/mines = 10 var/tiles_left = 100 var/obj/host var/emaggable = FALSE COOLDOWN_DECLARE(new_game_cd) /datum/minesweeper/proc/play_snd(sound) if(istype(host, /obj/item/modular_computer)) var/obj/item/modular_computer/comp = host comp.play_computer_sound(sound, 50, 0) else playsound(get_turf(host), sound, 50, 0, extrarange = -3, falloff = 10) /datum/minesweeper/proc/vis_msg(msg, local_msg) if(istype(host, /obj/item/modular_computer)) var/obj/item/modular_computer/comp = host comp.visible_message(msg) else host.visible_message(msg, local_msg) /datum/minesweeper/proc/set_custom_height(cin) cin = text2num(cin) if(cin < 5 || cin > 17) cin = clamp(cin, 5, 17) custom_height = cin custom_mines = min(custom_mines, FLOOR(custom_width*custom_height/2,1)) difficulty = MINESWEEPER_CUSTOM return TRUE /datum/minesweeper/proc/change_difficulty(diff) difficulty = diff return TRUE /datum/minesweeper/proc/new_game() if(!COOLDOWN_FINISHED(src, new_game_cd)) host.say("Please wait [COOLDOWN_TIMELEFT(src, new_game_cd)/10] more seconds before starting a new game.") return COOLDOWN_START(src, new_game_cd, 1.5 SECONDS) generate_new_board(difficulty) current_difficulty = diff_text(difficulty) current_mines = mines flags = 0 starting_time = 0 return TRUE /datum/minesweeper/proc/do_tile(x,y,flagging,mob/user) if(game_status) return if(board_data[x][y] != "minesweeper_hidden.png" && !flag_mode && !flagging) return if(flag_mode || flagging) if(board_data[x][y] == "minesweeper_hidden.png") board_data[x][y] = "minesweeper_flag.png" flags++ play_snd('yogstation/sound/arcade/minesweeper_boardpress.ogg') else if(board_data[x][y] == "minesweeper_flag.png") board_data[x][y] = "minesweeper_hidden.png" flags-- play_snd('yogstation/sound/arcade/minesweeper_boardpress.ogg') else return return TRUE play_snd('yogstation/sound/arcade/minesweeper_boardpress.ogg') if(current_difficulty != diff_text(difficulty)) generate_new_board(difficulty) x = min(x,width) y = min(y,height) current_difficulty = diff_text(difficulty) current_mines = mines flags = 0 time_frozen = 0 if(width * height == tiles_left) current_mines = mines if(!is_blank_tile_start(x,y)) move_bombs(x,y) // The first selected tile will always be a blank one. time_frozen = 0 starting_time = REALTIMEOFDAY if(difficulty == MINESWEEPER_CUSTOM) switch(mines/(height*width)) if(0.1 to 0.14999) value = 1 if(0.14999 to 0.19999) if(height >= 13 && width >= 13) value = 4 else value = 1 if(0.19999 to 0.29999) if(height >= 13 && width >= 25) value = 20 else value = 1 if(0.29999 to 1) if(height >= 13 && width >= 25) value = 25 else value = 2 else value = 0 else switch(difficulty) if(MINESWEEPER_BEGINNER) value = 1 if(MINESWEEPER_INTERMEDIATE) value = 4 if(MINESWEEPER_EXPERT) value = 20 var/result = select_square(x,y) game_status = result if(result == MINESWEEPER_VICTORY) play_snd('yogstation/sound/arcade/minesweeper_win.ogg') host.say("You cleared the board of all mines! Congratulations!") if(emaggable && host.obj_flags & EMAGGED && value >= 1) var/itemname switch(rand(1,3)) if(1) itemname = "a syndicate bomb beacon" new /obj/item/sbeacondrop/bomb(host.loc) if(2) itemname = "a rocket launcher" new /obj/item/gun/ballistic/rocketlauncher/unrestricted(host.loc) new /obj/item/ammo_casing/caseless/rocket/hedp(host.loc) new /obj/item/ammo_casing/caseless/rocket/hedp(host.loc) new /obj/item/ammo_casing/caseless/rocket/hedp(host.loc) if(3) itemname = "two bags of c4" new /obj/item/storage/backpack/duffelbag/syndie/c4(host.loc) new /obj/item/storage/backpack/duffelbag/syndie/x4(host.loc) message_admins("[key_name_admin(user)] won emagged Minesweeper and got [itemname]!") vis_msg(span_notice("[host] dispenses [itemname]!"), span_notice("You hear a chime and a clunk.")) else ticket_count += value if(result == MINESWEEPER_DEAD && emaggable && (host.obj_flags & EMAGGED)) // One crossed wire, one wayward pinch of potassium chlorate, ONE ERRANT TWITCH // AND KABLOOEY() if(result) time_frozen = REALTIMEOFDAY - starting_time return TRUE /datum/minesweeper/proc/generate_new_board(diff) board_data = new /list(31,18) // Fresh board mine_spots = list() switch(diff) if(MINESWEEPER_BEGINNER) // 10x10, 10 mines width = 10 height = 10 mines = 10 if(MINESWEEPER_INTERMEDIATE) // 17x17, 40 mines width = 17 height = 17 mines = 40 if(MINESWEEPER_EXPERT) // 30x16, 99 mines width = 30 height = 16 mines = 99 if(MINESWEEPER_CUSTOM) width = custom_width height = custom_height mines = custom_mines tiles_left = width * height mines = min(FLOOR(tiles_left/2,1), mines) // Crash protection for(var/i=1, i