game collection (#19179)

* game collection

* no phased usage

* .

* spellcheck

* chesskers

* fixes runtime during del

---------

Co-authored-by: Cameron Lennox <killer65311@gmail.com>
This commit is contained in:
Kashargul
2026-02-21 22:02:32 +01:00
committed by GitHub
parent db0636c8d1
commit 0fc8ccc50e
72 changed files with 6248 additions and 47 deletions
@@ -0,0 +1,87 @@
/obj/structure/casino_table/board_game
name = "board game table"
desc = "A collection of various board games."
icon_state = "gamble_preview"
var/datum/board_game/game_ui
var/static/list/possible_games = list(
GAME_SWEEPER = /datum/board_game/four_row,
GAME_FOUR_ROW = /datum/board_game/vore_sweeper,
GAME_SPACE_BATTLE = /datum/board_game/space_battle,
GAME_RGP_DICE = /datum/board_game/rpg_dice,
GAME_CHESS = /datum/board_game/chess,
GAME_CHECKERS = /datum/board_game/checkers,
GAME_NINE_MENS_MORRIS = /datum/board_game/nine_mens,
GAME_TIC_TAC_TOE = /datum/board_game/four_row/tic_tac_toe
)
/obj/structure/casino_table/board_game/Initialize(mapload)
. = ..()
if(ispath(game_ui))
game_ui = new game_ui(src)
/obj/structure/casino_table/board_game/Destroy()
if(game_ui)
game_ui.parent = null
QDEL_NULL(game_ui)
. = ..()
/obj/structure/casino_table/board_game/attack_hand(mob/user)
. = ..()
if(isliving(user))
if(!game_ui)
pick_game(user)
game_ui.tgui_interact(user)
/obj/structure/casino_table/board_game/click_alt(mob/user)
pick_game(user)
/obj/structure/casino_table/board_game/proc/pick_game(mob/user)
if(game_ui?.game_state != GAME_SETUP)
return
var/datum/board_game/new_game = tgui_input_list(user, "Pick the game to play", "Choose Game", possible_games)
if(!new_game)
return
new_game = possible_games[new_game]
if(game_ui)
QDEL_NULL(game_ui)
game_ui = new new_game(src)
icon_state = game_ui.table_icon
/datum/board_game
var/name
var/atom/parent
var/game_state = GAME_SETUP
var/table_icon = "gamble_preview"
/datum/board_game/tgui_state(mob/user)
return GLOB.tgui_board_game_state
/datum/board_game/New(atom/holder)
. = ..()
parent = holder
/datum/board_game/Destroy(force)
parent = null
. = ..()
/datum/board_game/tgui_host(mob/user)
return parent
/datum/board_game/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
. = ..()
if(.)
return
switch(action)
if("invite_player")
var/list/possible_mobs = ui.user.living_mobs_in_view(1, TRUE, TRUE)
for(var/obj/belly/our_belly in ui.user.vore_organs)
for(var/mob/living/prey in our_belly.contents)
if(prey.client)
possible_mobs += prey
var/mob/living/new_player = tgui_input_list(ui.user, "Invite a nearby player to the game.", "Invite Player", possible_mobs)
if(!new_player)
return FALSE
tgui_interact(new_player)
return TRUE
return FALSE
+523
View File
@@ -0,0 +1,523 @@
#define GAME_PLAYER_ONE 1
#define GAME_PLAYER_TWO 2
#define GAME_OVER 3
#define GAME_OVER_DRAW 4
#define GRID_SIZE 8
#define GAME_ACTION_NONE 0
#define GAME_ACTION_SELECT 1
#define GAME_ACTION_END_TURN 2
/obj/structure/casino_table/board_game/checkers
name = GAME_CHECKERS
desc = "A classic checkers game."
icon_state = "gamble_chess"
game_ui = /datum/board_game/checkers
/datum/board_game/checkers
name = GAME_CHECKERS
table_icon = "gamble_chess"
var/datum/weakref/player_one
var/datum/weakref/player_two
var/player_one_time = 0
var/player_two_time = 0
var/static/list/default_board = list(
list(null, "bM", null, "bM", null, "bM", null, "bM"),
list("bM", null, "bM", null, "bM", null, "bM", null),
list(null, "bM", null, "bM", null, "bM", null, "bM"),
list(null, null, null, null, null, null, null, null),
list(null, null, null, null, null, null, null, null),
list("wM", null, "wM", null, "wM", null, "wM", null),
list(null, "wM", null, "wM", null, "wM", null, "wM"),
list("wM", null, "wM", null, "wM", null, "wM", null)
)
var/list/current_board = list()
var/list/valid_moves = list()
var/list/selected_figure = list()
var/list/possible_jumps = list()
var/turn_start_time = 0
var/winner
/datum/board_game/checkers/Destroy(force)
player_one = null
player_two = null
. = ..()
/datum/board_game/checkers/tgui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "ChessCheckers", name)
ui.open()
/datum/board_game/checkers/tgui_static_data(mob/user)
return list("game_type" = "checkers")
/datum/board_game/checkers/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
var/mob/player_one_mob = player_one?.resolve()
var/mob/player_two_mob = player_two?.resolve()
return list(
"player_one" = player_one_mob,
"player_two" = player_two_mob,
"player_one_time" = player_one_time + (game_state == GAME_PLAYER_ONE ? world.time - turn_start_time : 0),
"player_two_time" = player_two_time + (game_state == GAME_PLAYER_TWO ? world.time - turn_start_time : 0),
"current_board" = current_board,
"selected_figure" = selected_figure,
"valid_moves" = valid_moves,
"game_state" = game_state,
"winner" = winner,
"has_won" = winner == ui.user.name,
"possible_jumps" = possible_jumps
)
/datum/board_game/checkers/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
. = ..()
if(.)
return
switch(action)
if("be_player_one")
if(game_state != GAME_SETUP)
return FALSE
if(player_one?.resolve() == ui.user)
player_one = null
return TRUE
player_one = WEAKREF(ui.user)
return TRUE
if("be_player_two")
if(game_state != GAME_SETUP)
return FALSE
if(player_two?.resolve() == ui.user)
player_two = null
return TRUE
player_two = WEAKREF(ui.user)
return TRUE
if("swap_players")
if(game_state != GAME_SETUP)
return FALSE
if(!player_one?.resolve() || !player_two?.resolve())
return FALSE
var/datum/weakref/temp_player = player_one
player_one = player_two
player_two = temp_player
if("clear_game")
if(game_state == GAME_SETUP)
return FALSE
reset(TRUE)
return TRUE
if("start_game")
if(game_state != GAME_SETUP)
return FALSE
if(!player_one?.resolve() || !player_two?.resolve())
return FALSE
current_board = get_defaultboard()
game_state = GAME_PLAYER_ONE
turn_start_time = world.time
return TRUE
if("play_again")
if(game_state < GAME_OVER)
return FALSE
if(!player_one?.resolve() || !player_two?.resolve())
return FALSE
reset()
turn_start_time = world.time
return TRUE
if("play_again_swapped")
if(game_state < GAME_OVER)
return FALSE
if(!player_one?.resolve() || !player_two?.resolve())
return FALSE
reset()
var/datum/weakref/temp_player = player_one
player_one = player_two
player_two = temp_player
turn_start_time = world.time
return TRUE
if("game_action")
if(ui.user == player_one?.resolve() && game_state == GAME_PLAYER_ONE)
var/game_action = player_actions(params["action"], params["data"], ui.user, "w")
if(game_action)
if(game_state < GAME_OVER && game_action == GAME_ACTION_END_TURN)
game_state = GAME_PLAYER_TWO
turn_start_time = world.time
return TRUE
if(ui.user == player_two?.resolve() && game_state == GAME_PLAYER_TWO)
var/game_action = player_actions(params["action"], params["data"], ui.user, "b")
if(game_action)
if(game_state < GAME_OVER && game_action == GAME_ACTION_END_TURN)
game_state = GAME_PLAYER_ONE
turn_start_time = world.time
return TRUE
return FALSE
/datum/board_game/checkers/proc/reset(full)
winner = null
player_one_time = 0
player_two_time = 0
selected_figure.Cut()
valid_moves.Cut()
if(full)
current_board.Cut()
game_state = GAME_SETUP
player_one = null
player_two = null
else
current_board = get_defaultboard()
game_state = GAME_PLAYER_ONE
/datum/board_game/checkers/proc/player_actions(action, list/params, mob/user, active_color)
switch(action)
if("select_figure")
var/list/validated_data = validate_coords(params)
if (!validated_data)
return GAME_ACTION_NONE
var/piece = current_board[validated_data[2]][validated_data[1]]
if(!piece || piece[1] != active_color)
return GAME_ACTION_NONE
if(has_available_jumps(active_color))
var/list/jumps = generate_valid_moves(validated_data[1], validated_data[2], TRUE)
if (length(jumps) == 0)
return GAME_ACTION_NONE
selected_figure = validated_data
update_valid_moves()
return GAME_ACTION_SELECT
if("move_figure")
var/list/coords = validate_coords(params)
if(!coords || !selected_figure)
return GAME_ACTION_NONE
var/to_x = coords[1]
var/to_y = coords[2]
if(!valid_move(to_x, to_y))
return GAME_ACTION_NONE
var/from_x = selected_figure[1]
var/from_y = selected_figure[2]
var/moving_piece = current_board[from_y][from_x]
if(moving_piece[2] == "M" && ((moving_piece[1] == "w" && to_y == 1) || (moving_piece[1] == "b" && to_y == GRID_SIZE)))
moving_piece = moving_piece[1] + "K"
current_board[to_y][to_x] = moving_piece
current_board[from_y][from_x] = null
var/did_jump = FALSE
if(abs(to_x - from_x) >= 2 && abs(to_y - from_y) >= 2)
var/step_x = (to_x - from_x) / abs(to_x - from_x)
var/step_y = (to_y - from_y) / abs(to_y - from_y)
var/x = from_x + step_x
var/y = from_y + step_y
while(x != to_x && y != to_y)
var/p = current_board[y][x]
if(p && p[1] != moving_piece[1])
current_board[y][x] = null
did_jump = TRUE
break
x += step_x
y += step_y
if(did_jump && piece_can_jump_again(to_x, to_y))
selected_figure = list(to_x, to_y)
update_valid_moves()
validate_victory(active_color)
possible_jumps = get_mandatory_jumps(active_color)
return GAME_ACTION_SELECT
var/turn_duration = world.time - turn_start_time
if(game_state == GAME_PLAYER_ONE)
player_one_time += turn_duration
else if(game_state == GAME_PLAYER_TWO)
player_two_time += turn_duration
selected_figure.Cut()
update_valid_moves()
validate_victory(active_color)
if(game_state != GAME_OVER)
possible_jumps = get_mandatory_jumps(active_color == "w" ? "b" : "w")
else
possible_jumps.Cut()
return GAME_ACTION_END_TURN
/datum/board_game/checkers/proc/get_mandatory_jumps(active_color)
var/list/jumping_pieces = list()
if(!has_available_jumps(active_color))
return jumping_pieces
for(var/row = 1 to GRID_SIZE)
for(var/col = 1 to GRID_SIZE)
var/piece = current_board[row][col]
if(piece && piece[1] == active_color)
var/list/jumps = generate_valid_moves(col, row, TRUE)
if(length(jumps) > 0)
UNTYPED_LIST_ADD(jumping_pieces, list(col, row))
return jumping_pieces
/datum/board_game/checkers/proc/update_valid_moves()
valid_moves.Cut()
if(length(selected_figure))
var/x = selected_figure[1]
var/y = selected_figure[2]
valid_moves = generate_valid_moves(x, y)
/datum/board_game/checkers/proc/piece_can_jump_again(x, y)
var/piece = current_board[y][x]
if(!piece)
return FALSE
for(var/list/move in generate_valid_moves(x, y, TRUE))
if(abs(move[1] - x) >= 2 && abs(move[2] - y) >= 2)
return TRUE
return FALSE
/datum/board_game/checkers/proc/valid_move(to_x, to_y)
for(var/list/move in valid_moves)
if(move[1] == to_x && move[2] == to_y)
return TRUE
return FALSE
/datum/board_game/checkers/proc/validate_victory(active_color)
var/opponent_color = active_color == "w" ? "b" : "w"
var/any_opponent_pieces = FALSE
var/opponent_has_moves = FALSE
var/opponent_has_jumps = has_available_jumps(opponent_color)
for(var/row = 1 to GRID_SIZE)
for(var/col = 1 to GRID_SIZE)
var/piece = current_board[row][col]
if(piece && piece[1] == opponent_color)
any_opponent_pieces = TRUE
var/list/moves
if(opponent_has_jumps)
moves = generate_valid_moves(col, row, TRUE)
else
moves = generate_valid_moves(col, row)
if(length(moves) > 0)
opponent_has_moves = TRUE
break
if(opponent_has_moves)
break
if(!any_opponent_pieces)
var/mob/player_one_mob = player_one?.resolve()
var/mob/player_two_mob = player_two?.resolve()
winner = active_color == "w" ? player_one_mob?.name : player_two_mob?.name
game_state = GAME_OVER
return
if(!opponent_has_moves)
if(any_opponent_pieces)
winner = null
game_state = GAME_OVER_DRAW
return
var/mob/player_one_mob = player_one?.resolve()
var/mob/player_two_mob = player_two?.resolve()
winner = active_color == "w" ? player_one_mob?.name : player_two_mob?.name
game_state = GAME_OVER
/datum/board_game/checkers/proc/generate_valid_moves(x, y, jump_only)
var/piece = current_board[y][x]
var/list/moves = list()
if (!piece)
return moves
var/directions = list()
switch(piece[2])
if("M")
if(piece[1] == "w")
directions = list(list(1, -1), list(-1, -1))
else
directions = list(list(1, 1), list(-1, 1))
if("K")
directions = list(list(1, 1), list(-1, 1), list(1, -1), list(-1, -1))
var/list/jump_moves = list()
add_jumps(directions, x, y, jump_moves)
if(length(jump_moves) || jump_only)
return jump_moves
switch(piece[2])
if("M")
for(var/list/direction in directions)
var/new_x = x + direction[1]
var/new_y = y + direction[2]
if(field_check(new_x, new_y) && current_board[new_y][new_x] == null)
UNTYPED_LIST_ADD(moves, list(new_x, new_y))
if("K")
for(var/list/direction in directions)
var/step = 1
while(TRUE)
var/new_x = x + direction[1] * step
var/new_y = y + direction[2] * step
if(!field_check(new_x, new_y))
break
if(current_board[new_y][new_x])
break
UNTYPED_LIST_ADD(moves, list(new_x, new_y))
step += 1
return moves
/datum/board_game/checkers/proc/has_available_jumps(active_color)
for (var/row = 1 to GRID_SIZE)
for (var/col = 1 to GRID_SIZE)
var/piece = current_board[row][col]
if (piece && piece[1] == active_color)
var/list/jumps = generate_valid_moves(col, row, TRUE)
if (length(jumps) > 0)
return TRUE
return FALSE
/datum/board_game/checkers/proc/already_visited(x, y, list/visited_list)
for(var/list/coord in visited_list)
if(coord[1] == x && coord[2] == y)
return TRUE
return FALSE
/datum/board_game/checkers/proc/add_jumps(var/list/directions, start_x, start_y, list/jump_moves, list/visited = list())
var/piece = current_board[start_y][start_x]
if(!piece)
return
for(var/list/direction in directions)
switch(piece[2])
if("M")
var/tx = start_x + direction[1] * 2
var/ty = start_y + direction[2] * 2
if(!field_check(tx, ty) || already_visited(tx, ty, visited))
continue
if(can_jump_piece(start_x, start_y, tx, ty))
var/list/new_visited = visited.Copy()
UNTYPED_LIST_ADD(new_visited, list(tx, ty))
UNTYPED_LIST_ADD(jump_moves, list(tx, ty))
add_jumps(directions, tx, ty, jump_moves, new_visited)
if("K")
var/step = 1
while(TRUE)
var/tx = start_x + direction[1] * step
var/ty = start_y + direction[2] * step
if(!field_check(tx, ty))
break
if(already_visited(tx, ty, visited))
step++
continue
if(can_jump_piece(start_x, start_y, tx, ty))
var/list/new_visited = visited.Copy()
UNTYPED_LIST_ADD(new_visited, list(tx, ty))
UNTYPED_LIST_ADD(jump_moves, list(tx, ty))
add_jumps(directions, tx, ty, jump_moves, new_visited)
step++
/datum/board_game/checkers/proc/can_jump_piece(from_x, from_y, to_x, to_y)
var/piece = current_board[from_y][from_x]
if(!piece)
return FALSE
var/dx = to_x - from_x
var/dy = to_y - from_y
var/color = piece[1]
switch(piece[2])
if("M")
if(abs(dx) != 2 || abs(dy) != 2)
return FALSE
var/mid_x = from_x + dx / 2
var/mid_y = from_y + dy / 2
var/mid_piece = current_board[mid_y][mid_x]
if(mid_piece && mid_piece[1] != color && current_board[to_y][to_x] == null)
return TRUE
return FALSE
if("K")
if(abs(dx) != abs(dy))
return FALSE
var/step_x = dx / abs(dx)
var/step_y = dy / abs(dy)
var/x = from_x + step_x
var/y = from_y + step_y
var/jumped_piece_found = FALSE
var/jumped_x = 0
var/jumped_y = 0
while(x != to_x && y != to_y)
var/piece_at_square = current_board[y][x]
if(piece_at_square)
if(piece_at_square[1] == color)
return FALSE
if(jumped_piece_found)
return FALSE
jumped_piece_found = TRUE
jumped_x = x
jumped_y = y
x += step_x
y += step_y
if(!jumped_piece_found)
return FALSE
if(current_board[to_y][to_x] != null)
return FALSE
x = jumped_x + step_x
y = jumped_y + step_y
while(x != to_x || y != to_y)
if(current_board[y][x] != null)
return FALSE
x += step_x
y += step_y
return TRUE
/datum/board_game/checkers/proc/field_check(new_x_location, new_y_location)
if(new_x_location < 1 || new_x_location > GRID_SIZE)
return FALSE
if(new_y_location < 1 || new_y_location > GRID_SIZE)
return FALSE
return TRUE
/datum/board_game/checkers/proc/validate_coords(list/params)
var/x_loc = text2num(params["loc_x"])
var/y_loc = text2num(params["loc_y"])
if(!isnum(x_loc) || !isnum(y_loc))
return null
if(!field_check(x_loc, y_loc))
return null
return list(x_loc, y_loc)
/datum/board_game/checkers/proc/get_defaultboard()
var/list/deep_copy = list()
for(var/list/row in default_board)
UNTYPED_LIST_ADD(deep_copy, row.Copy())
return deep_copy
#undef GAME_PLAYER_ONE
#undef GAME_PLAYER_TWO
#undef GAME_OVER
#undef GAME_OVER_DRAW
#undef GRID_SIZE
#undef GAME_ACTION_NONE
#undef GAME_ACTION_SELECT
#undef GAME_ACTION_END_TURN
+566
View File
@@ -0,0 +1,566 @@
#define GAME_PLAYER_ONE 1
#define GAME_PLAYER_TWO 2
#define GAME_OVER 3
#define GAME_OVER_DRAW 4
#define GRID_SIZE 8
#define GAME_FLAG_CHECK_PONE 0x1
#define GAME_FLAG_CHECK_PTWO 0x2
#define GAME_FLAG_CASTLING_USED_PONE 0x4
#define GAME_FLAG_CASTLING_USED_PTWO 0x8
#define GAME_ACTION_NONE 0
#define GAME_ACTION_SELECT 1
#define GAME_ACTION_END_TURN 2
/obj/structure/casino_table/board_game/chess
name = GAME_CHESS
desc = "A classic chess game."
icon_state = "gamble_chess"
game_ui = /datum/board_game/chess
/datum/board_game/chess
name = GAME_CHESS
table_icon = "gamble_chess"
var/datum/weakref/player_one
var/datum/weakref/player_two
var/player_one_time = 0
var/player_two_time = 0
var/static/list/default_board = list(
list("bR","bN","bB","bQ","bK","bB","bN","bR"),
list("bP","bP","bP","bP","bP","bP","bP","bP"),
list(null,null,null,null,null,null,null,null),
list(null,null,null,null,null,null,null,null),
list(null,null,null,null,null,null,null,null),
list(null,null,null,null,null,null,null,null),
list("wP","wP","wP","wP","wP","wP","wP","wP"),
list("wR","wN","wB","wQ","wK","wB","wN","wR")
)
var/list/current_board = list()
var/list/valid_moves = list()
var/list/selected_figure = list()
var/list/last_double_pawn_move = list()
var/game_flags = NONE
var/turn_start_time = 0
var/winner
/datum/board_game/chess/Destroy(force)
player_one = null
player_two = null
. = ..()
/datum/board_game/chess/tgui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "ChessCheckers", name)
ui.open()
/datum/board_game/chess/tgui_static_data(mob/user)
return list("game_type" = "chess")
/datum/board_game/chess/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
var/mob/player_one_mob = player_one?.resolve()
var/mob/player_two_mob = player_two?.resolve()
return list(
"player_one" = player_one_mob,
"player_two" = player_two_mob,
"player_one_time" = player_one_time + (game_state == GAME_PLAYER_ONE ? world.time - turn_start_time : 0),
"player_two_time" = player_two_time + (game_state == GAME_PLAYER_TWO ? world.time - turn_start_time : 0),
"current_board" = current_board,
"selected_figure" = selected_figure,
"valid_moves" = valid_moves,
"game_state" = game_state,
"winner" = winner,
"has_won" = winner == ui.user.name,
"game_flags" = game_flags
)
/datum/board_game/chess/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
. = ..()
if(.)
return
switch(action)
if("be_player_one")
if(game_state != GAME_SETUP)
return FALSE
if(player_one?.resolve() == ui.user)
player_one = null
return TRUE
player_one = WEAKREF(ui.user)
return TRUE
if("be_player_two")
if(game_state != GAME_SETUP)
return FALSE
if(player_two?.resolve() == ui.user)
player_two = null
return TRUE
player_two = WEAKREF(ui.user)
return TRUE
if("swap_players")
if(game_state != GAME_SETUP)
return FALSE
if(!player_one?.resolve() || !player_two?.resolve())
return FALSE
var/datum/weakref/temp_player = player_one
player_one = player_two
player_two = temp_player
if("clear_game")
if(game_state == GAME_SETUP)
return FALSE
reset(TRUE)
return TRUE
if("start_game")
if(game_state != GAME_SETUP)
return FALSE
if(!player_one?.resolve() || !player_two?.resolve())
return FALSE
current_board = get_defaultboard()
game_state = GAME_PLAYER_ONE
turn_start_time = world.time
return TRUE
if("play_again")
if(game_state < GAME_OVER)
return FALSE
if(!player_one?.resolve() || !player_two?.resolve())
return FALSE
reset()
turn_start_time = world.time
return TRUE
if("play_again_swapped")
if(game_state < GAME_OVER)
return FALSE
if(!player_one?.resolve() || !player_two?.resolve())
return FALSE
reset()
var/datum/weakref/temp_player = player_one
player_one = player_two
player_two = temp_player
turn_start_time = world.time
return TRUE
if("game_action")
if(ui.user == player_one?.resolve() && game_state == GAME_PLAYER_ONE)
var/game_action = player_actions(params["action"], params["data"], ui.user, "w")
if(game_action)
if(game_state < GAME_OVER && game_action == GAME_ACTION_END_TURN)
game_state = GAME_PLAYER_TWO
turn_start_time = world.time
return TRUE
if(ui.user == player_two?.resolve() && game_state == GAME_PLAYER_TWO)
var/game_action = player_actions(params["action"], params["data"], ui.user, "b")
if(game_action)
if(game_state < GAME_OVER && game_action == GAME_ACTION_END_TURN)
game_state = GAME_PLAYER_ONE
turn_start_time = world.time
return TRUE
return FALSE
/datum/board_game/chess/proc/reset(full)
winner = null
player_one_time = 0
player_two_time = 0
selected_figure.Cut()
valid_moves.Cut()
last_double_pawn_move.Cut()
game_flags = NONE
if(full)
current_board.Cut()
game_state = GAME_SETUP
player_one = null
player_two = null
else
current_board = get_defaultboard()
game_state = GAME_PLAYER_ONE
/datum/board_game/chess/proc/player_actions(action, list/params, mob/user, active_color)
switch(action)
if("select_figure")
var/list/validated_data = validate_coords(params)
if(!validated_data)
return GAME_ACTION_NONE
var/piece = current_board[validated_data[2]][validated_data[1]]
if(!piece)
return GAME_ACTION_NONE
if(piece[1] != active_color)
return GAME_ACTION_NONE
selected_figure = validated_data
update_valid_moves()
return GAME_ACTION_SELECT
if("move_figure")
var/list/coords = validate_coords(params)
if(!coords || !selected_figure)
return GAME_ACTION_NONE
var/from_x = selected_figure[1]
var/from_y = selected_figure[2]
var/to_x = coords[1]
var/to_y = coords[2]
if(!valid_move(to_x, to_y))
return GAME_ACTION_NONE
var/moving_piece = current_board[from_y][from_x]
var/target_piece = current_board[to_y][to_x]
var/turn_duration = world.time - turn_start_time
if(game_state == GAME_PLAYER_ONE)
player_one_time += turn_duration
else if(game_state == GAME_PLAYER_TWO)
player_two_time += turn_duration
if(moving_piece[2] == "K" && abs(to_x - from_x) == 2)
if(!handle_castling(active_color, from_x, from_y, to_x, to_y))
return GAME_ACTION_NONE
do_castling(active_color, from_x, from_y, to_x, to_y)
if(moving_piece[2] == "P" && abs(to_x - from_x) == 1 && !target_piece)
if(can_en_passant(from_x, from_y, to_x, to_y))
current_board[from_y][to_x] = null
if(!(moving_piece[2] == "K" && abs(to_x - from_x) == 2))
current_board[to_y][to_x] = moving_piece
current_board[from_y][from_x] = null
if(moving_piece[2] == "P" && abs(to_y - from_y) == 2)
last_double_pawn_move = list(to_x, to_y, moving_piece[1])
else
last_double_pawn_move.Cut()
if(moving_piece[2] == "P")
if((moving_piece[1] == "w" && to_y == 1) || (moving_piece[1] == "b" && to_y == GRID_SIZE))
var/promotion = params["promotion_choice"]
if(!(promotion in list("Q", "R", "B", "N")))
promotion = "Q"
current_board[to_y][to_x] = moving_piece[1] + promotion
selected_figure.Cut()
update_valid_moves()
validate_victory(active_color)
return GAME_ACTION_END_TURN
/datum/board_game/chess/proc/valid_move(to_x, to_y)
for(var/list/move in valid_moves)
if(move[1] == to_x && move[2] == to_y)
return TRUE
return FALSE
/datum/board_game/chess/proc/handle_castling(active_color, from_x, from_y, to_x, to_y)
if(active_color == "w" && (game_flags & (GAME_FLAG_CASTLING_USED_PONE|GAME_FLAG_CHECK_PONE)))
return FALSE
if(active_color == "b" && (game_flags & (GAME_FLAG_CASTLING_USED_PTWO|GAME_FLAG_CHECK_PTWO)))
return FALSE
var/king = current_board[from_y][from_x]
if(king != "wK" && king != "bK")
return FALSE
if(abs(to_x - from_x) != 2)
return FALSE
var/row = from_y
var/rook_x
var/rook
var/col_start
var/col_end
if(to_x > from_x)
rook_x = GRID_SIZE
rook = current_board[row][rook_x]
if(rook != "wR" && rook != "bR")
return FALSE
col_start = from_x + 1
col_end = to_x
else
rook_x = 1
rook = current_board[row][rook_x]
if(rook != "wR" && rook != "bR")
return FALSE
col_start = to_x
col_end = from_x - 1
for(var/c = col_start to col_end)
if(current_board[row][c] != null && c != from_x)
return FALSE
var/opponent_color = active_color == "w" ? "b" : "w"
if(!opponent_color)
return FALSE
if(square_under_attack(opponent_color, from_x, from_y))
return FALSE
var/step = (to_x > from_x ? 1 : -1)
var/x = from_x
while(x != to_x + step)
if(x != from_x && x != to_x && square_under_attack(opponent_color, x, row))
return FALSE
x += step
return TRUE
/datum/board_game/chess/proc/do_castling(active_color, from_x, from_y, to_x, to_y)
var/row = from_y
var/king = current_board[from_y][from_x]
var/rook_x
var/rook
var/rook_target_x
if(to_x > from_x)
rook_x = GRID_SIZE
rook = current_board[row][rook_x]
rook_target_x = to_x - 1
else
rook_x = 1
rook = current_board[row][rook_x]
rook_target_x = to_x + 1
current_board[row][to_x] = king
current_board[row][from_x] = null
current_board[row][rook_target_x] = rook
current_board[row][rook_x] = null
if(active_color == "w")
game_flags |= GAME_FLAG_CASTLING_USED_PONE
else
game_flags |= GAME_FLAG_CASTLING_USED_PTWO
return TRUE
/datum/board_game/chess/proc/update_valid_moves()
valid_moves.Cut()
if(length(selected_figure))
var/x = selected_figure[1]
var/y = selected_figure[2]
valid_moves = generate_valid_moves(x, y)
/datum/board_game/chess/proc/square_under_attack(opponent_color, x, y)
for(var/row = 1; row <= GRID_SIZE; row++)
for(var/col = 1; col <= GRID_SIZE; col++)
var/piece = current_board[row][col]
if(!piece)
continue
if(piece[1] != opponent_color)
continue
var/dx = x - col
var/dy = y - row
switch(piece[2])
if("P")
var/dir = (piece[1] == "w" ? -1 : 1)
if(dy == dir && abs(dx) == 1)
return TRUE
if("N")
if(abs(dx) == 2 && abs(dy) == 1 || abs(dx) == 1 && abs(dy) == 2)
return TRUE
if("B")
if(abs(dx) == abs(dy) && path_clear(col, row, x, y))
return TRUE
if("R")
if((dx == 0 || dy == 0) && path_clear(col, row, x, y))
return TRUE
if("Q")
if((dx == 0 || dy == 0 || abs(dx) == abs(dy)) && path_clear(col, row, x, y))
return TRUE
if("K")
if(abs(dx) <= 1 && abs(dy) <= 1)
return TRUE
return FALSE
/datum/board_game/chess/proc/path_clear(from_x, from_y, to_x, to_y)
var/dx = to_x - from_x
var/dy = to_y - from_y
var/step_x = dx == 0 ? 0 : (dx / abs(dx))
var/step_y = dy == 0 ? 0 : (dy / abs(dy))
var/x = from_x + step_x
var/y = from_y + step_y
while(x != to_x || y != to_y)
if(!field_check(x, y))
return FALSE
if(current_board[y][x] != null)
return FALSE
x += step_x
y += step_y
return TRUE
/datum/board_game/chess/proc/validate_victory(active_color)
var/opponent_color = active_color == "w" ? "b" : "w"
var/king_pos = locate_king(opponent_color)
if(!king_pos)
var/mob/winning_player = (active_color == "w" ? player_two?.resolve() : player_one?.resolve())
winner = winning_player?.name
game_state = GAME_OVER
return
var/in_check = square_under_attack(active_color, king_pos[1], king_pos[2])
if(in_check)
game_flags |= (opponent_color == "w" ? GAME_FLAG_CHECK_PONE : GAME_FLAG_CHECK_PTWO)
else
game_flags &= ~(opponent_color == "w" ? GAME_FLAG_CHECK_PONE : GAME_FLAG_CHECK_PTWO)
var/no_moves = TRUE
for(var/row = 1 to GRID_SIZE)
for(var/col = 1 to GRID_SIZE)
var/piece = current_board[row][col]
if(!piece)
continue
if(piece[1] != opponent_color)
continue
var/list/moves = generate_valid_moves(col, row)
if(length(moves) > 0)
no_moves = FALSE
if(in_check && no_moves)
var/mob/winning_player = active_color == "w" ? player_one?.resolve() : player_two?.resolve()
winner = winning_player?.name
game_state = GAME_OVER
return
if(!in_check && no_moves)
winner = null
game_state = GAME_OVER_DRAW
/datum/board_game/chess/proc/locate_king(color)
var/king_symbol = color + "K"
for(var/row = 1 to GRID_SIZE)
for(var/col = 1 to GRID_SIZE)
if(current_board[row][col] == king_symbol)
return list(col, row)
return null
/datum/board_game/chess/proc/generate_valid_moves(x, y)
var/piece = current_board[y][x]
var/moves = list()
if(!piece)
return moves
for(var/row = 1 to GRID_SIZE)
for(var/col = 1 to GRID_SIZE)
if(row == y && col == x)
continue
if(can_move_piece(x, y, col, row))
UNTYPED_LIST_ADD(moves, list(col, row))
return moves
/datum/board_game/chess/proc/can_move_piece(from_x, from_y, to_x, to_y)
var/piece = current_board[from_y][from_x]
if(!piece)
return FALSE
var/dx = to_x - from_x
var/dy = to_y - from_y
var/abs_dx = abs(dx)
var/abs_dy = abs(dy)
if(dx == 0 && dy == 0)
return FALSE
var/color = piece[1]
var/target = current_board[to_y][to_x]
if(target && target[1] == color)
return FALSE
var/can_move = FALSE
switch(piece[2])
if("P")
var/dir = (color == "w" ? -1 : 1)
if(dx == 0 && dy == dir && !target)
can_move = TRUE
else if(dx == 0 && dy == 2*dir && !target && current_board[from_y + dir][from_x] == null && ((color == "w" && from_y == 7) || (color == "b" && from_y == 2)))
can_move = TRUE
else if(abs_dx == 1 && dy == dir && target)
can_move = TRUE
else if(abs_dx == 1 && dy == dir && !target && length(last_double_pawn_move))
if(last_double_pawn_move[1] == to_x && last_double_pawn_move[2] == from_y && last_double_pawn_move[3] == (color == "w" ? "b" : "w"))
can_move = TRUE
if("N")
if((abs_dx == 2 && abs_dy == 1) || (abs_dx == 1 && abs_dy == 2))
can_move = TRUE
if("B")
if(abs_dx == abs_dy && path_clear(from_x, from_y, to_x, to_y))
can_move = TRUE
if("R")
if((dx == 0 || dy == 0) && path_clear(from_x, from_y, to_x, to_y))
can_move = TRUE
if("Q")
if((dx == 0 || dy == 0 || abs_dx == abs_dy) && path_clear(from_x, from_y, to_x, to_y))
can_move = TRUE
if("K")
if(abs_dx <= 1 && abs_dy <= 1)
can_move = TRUE
else if(abs_dx == 2 && dy == 0)
can_move = handle_castling(color, from_x, from_y, to_x, to_y)
if(!can_move)
return FALSE
var/orig_piece = current_board[to_y][to_x]
current_board[to_y][to_x] = piece
current_board[from_y][from_x] = null
var/king_pos = locate_king(color)
if(!king_pos)
current_board[from_y][from_x] = piece
current_board[to_y][to_x] = orig_piece
return FALSE
var/in_check = square_under_attack(color == "w" ? "b" : "w", king_pos[1], king_pos[2])
current_board[from_y][from_x] = piece
current_board[to_y][to_x] = orig_piece
return !in_check
/datum/board_game/chess/proc/can_en_passant(from_x, from_y, to_x, to_y)
if(!last_double_pawn_move)
return FALSE
return last_double_pawn_move[1] == to_x && last_double_pawn_move[2] == from_y && last_double_pawn_move[3] == (current_board[from_y][from_x][1] == "w" ? "b" : "w")
/datum/board_game/chess/proc/field_check(new_x_location, new_y_location)
if(new_x_location < 1 || new_x_location > GRID_SIZE)
return FALSE
if(new_y_location < 1 || new_y_location > GRID_SIZE)
return FALSE
return TRUE
/datum/board_game/chess/proc/validate_coords(list/params)
var/x_loc = text2num(params["loc_x"])
var/y_loc = text2num(params["loc_y"])
if(!isnum(x_loc) || !isnum(y_loc))
return null
if(!field_check(x_loc, y_loc))
return null
return list(x_loc, y_loc)
/datum/board_game/chess/proc/get_defaultboard()
var/list/deep_copy = list()
for(var/list/row in default_board)
UNTYPED_LIST_ADD(deep_copy, row.Copy())
return deep_copy
#undef GAME_PLAYER_ONE
#undef GAME_PLAYER_TWO
#undef GAME_OVER
#undef GAME_OVER_DRAW
#undef GRID_SIZE
#undef GAME_FLAG_CHECK_PONE
#undef GAME_FLAG_CHECK_PTWO
#undef GAME_FLAG_CASTLING_USED_PONE
#undef GAME_FLAG_CASTLING_USED_PTWO
#undef GAME_ACTION_NONE
#undef GAME_ACTION_SELECT
#undef GAME_ACTION_END_TURN
@@ -0,0 +1,330 @@
#define GAME_PLAYER_ONE 1
#define GAME_PLAYER_TWO 2
#define GAME_OVER 3
#define GAME_OVER_DRAW 4
/obj/structure/casino_table/board_game/four_row
name = GAME_FOUR_ROW
desc = "A game where two players need to connect their chips in a row."
icon_state = "gamble_four"
game_ui = /datum/board_game/four_row
/datum/board_game/four_row
name = GAME_FOUR_ROW
table_icon = "gamble_four"
var/datum/weakref/player_one
var/datum/weakref/player_two
var/list/placed_chips_pone = list()
var/list/placed_chips_ptwo = list()
var/list/winning_tiles = list()
var/grid_x_size = 7
var/grid_y_size = 6
var/win_count = 4
var/player_one_color = "yellow"
var/player_two_color = "red"
var/winner
var/static/list/possible_colors = list("red", "yellow", "green", "orange", "blue", "cyan")
/datum/board_game/four_row/Destroy(force)
player_one = null
player_two = null
. = ..()
/datum/board_game/four_row/tgui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "FourInARow", name)
ui.open()
/datum/board_game/four_row/tgui_static_data(mob/user)
return list(
"colors" = possible_colors
)
/datum/board_game/four_row/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
var/mob/player_one_mob = player_one?.resolve()
var/mob/player_two_mob = player_two?.resolve()
return list(
"player_one" = player_one_mob,
"player_two" = player_two_mob,
"placed_chips_pone" = placed_chips_pone,
"placed_chips_ptwo" = placed_chips_ptwo,
"game_state" = game_state,
"grid_x_size" = grid_x_size,
"grid_y_size" = grid_y_size,
"player_one_color" = player_one_color,
"player_two_color" = player_two_color,
"win_count" = win_count,
"winner" = winner,
"has_won" = winner == ui.user.name,
"winning_tiles" = winning_tiles,
)
/datum/board_game/four_row/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
. = ..()
if(.)
return
switch(action)
if("be_player_one")
if(game_state != GAME_SETUP)
return FALSE
if(player_one?.resolve() == ui.user)
player_one = null
return TRUE
player_one = WEAKREF(ui.user)
return TRUE
if("be_player_two")
if(game_state != GAME_SETUP)
return FALSE
if(player_two?.resolve() == ui.user)
player_two = null
return TRUE
player_two = WEAKREF(ui.user)
return TRUE
if("swap_players")
if(game_state != GAME_SETUP)
return FALSE
if(!player_one?.resolve() || !player_two?.resolve())
return FALSE
var/datum/weakref/temp_player = player_one
player_one = player_two
player_two = temp_player
if("set_color_one")
if(game_state != GAME_SETUP)
return FALSE
if(player_one?.resolve() != ui.user)
return FALSE
var/new_color = params["color"]
if(new_color == player_two_color)
return FALSE
if(!(new_color in possible_colors))
return FALSE
player_one_color = new_color
return TRUE
if("set_color_two")
if(game_state != GAME_SETUP)
return FALSE
if(player_two?.resolve() != ui.user)
return FALSE
var/new_color = params["color"]
if(new_color == player_one_color)
return FALSE
if(!(new_color in possible_colors))
return FALSE
player_two_color = new_color
return TRUE
if("change_size")
if(game_state != GAME_SETUP)
return FALSE
var/new_size = text2num(params["size"])
return set_new_size(new_size)
if("change_win")
if(game_state != GAME_SETUP)
return FALSE
return change_win_count(text2num(params["count"]))
if("clear_game")
if(game_state == GAME_SETUP)
return FALSE
reset(TRUE)
return TRUE
if("start_game")
if(game_state != GAME_SETUP)
return FALSE
if(!player_one?.resolve() || !player_two?.resolve())
return FALSE
game_state = GAME_PLAYER_ONE
return TRUE
if("play_again")
if(game_state < GAME_OVER)
return FALSE
if(!player_one?.resolve() || !player_two?.resolve())
return FALSE
reset()
return TRUE
if("play_again_swapped")
if(game_state < GAME_OVER)
return FALSE
if(!player_one?.resolve() || !player_two?.resolve())
return FALSE
reset()
var/datum/weakref/temp_player = player_one
player_one = player_two
player_two = temp_player
return TRUE
if("game_action")
if(ui.user == player_one?.resolve() && game_state == GAME_PLAYER_ONE)
if(player_actions(params["action"], params["data"], ui.user))
if(game_state < GAME_OVER)
game_state = GAME_PLAYER_TWO
return TRUE
if(ui.user == player_two?.resolve() && game_state == GAME_PLAYER_TWO)
if(player_actions(params["action"], params["data"], ui.user))
if(game_state < GAME_OVER)
game_state = GAME_PLAYER_ONE
return TRUE
return FALSE
/datum/board_game/four_row/proc/change_win_count(new_count)
if(!isnum(new_count))
return FALSE
if(new_count < 4 || new_count > 5)
return FALSE
win_count = new_count
return TRUE
/datum/board_game/four_row/proc/reset(full)
placed_chips_pone.Cut()
placed_chips_ptwo.Cut()
winning_tiles.Cut()
winner = null
if(full)
game_state = GAME_SETUP
player_one = null
player_two = null
else
game_state = GAME_PLAYER_ONE
/datum/board_game/four_row/proc/player_actions(action, list/params, mob/user)
switch(action)
if("place_chip")
var/list/validated_data = validate_coords(params)
if(!validated_data)
return FALSE
var/x_loc = validated_data[2]
var/target_y = 0
for(var/y = grid_y_size; y >= 1; y--)
var/key = "[x_loc],[y]"
if(!placed_chips_pone[key] && !placed_chips_ptwo[key])
target_y = y
break
if(target_y == 0)
return FALSE
var/key = "[x_loc],[target_y]"
if(game_state == GAME_PLAYER_ONE)
placed_chips_pone[key] = TRUE
else
placed_chips_ptwo[key] = TRUE
validate_victory(x_loc, target_y, user.name)
return TRUE
/datum/board_game/four_row/proc/has_chip(list/player_list, x, y)
return player_list["[x],[y]"]
/datum/board_game/four_row/proc/collect_direction(list/player_list, start_x, start_y, dx, dy)
var/list/tiles = list()
var/x = start_x
var/y = start_y
while(field_check(x, y) && has_chip(player_list, x, y))
tiles += "[x],[y]"
x += dx
y += dy
return tiles
/datum/board_game/four_row/proc/validate_victory(x, y, user_name)
var/list/current_list
if(game_state == GAME_PLAYER_ONE)
current_list = placed_chips_pone
else
current_list = placed_chips_ptwo
var/list/h1 = collect_direction(current_list, x, y, 1, 0)
var/list/h2 = collect_direction(current_list, x, y, -1, 0)
var/list/horizontal = h1 + h2
horizontal -= "[x],[y]"
if(length(horizontal) >= win_count)
winning_tiles = horizontal
game_state = GAME_OVER
winner = user_name
return
var/list/v1 = collect_direction(current_list, x, y, 0, 1)
var/list/v2 = collect_direction(current_list, x, y, 0, -1)
var/list/vertical = v1 + v2
vertical -= "[x],[y]"
if(length(vertical) >= win_count)
winning_tiles = vertical
game_state = GAME_OVER
winner = user_name
return
var/list/d1 = collect_direction(current_list, x, y, 1, 1)
var/list/d2 = collect_direction(current_list, x, y, -1, -1)
var/list/diag1 = d1 + d2
diag1 -= "[x],[y]"
if(length(diag1) >= win_count)
winning_tiles = diag1
game_state = GAME_OVER
winner = user_name
return
var/list/d3 = collect_direction(current_list, x, y, 1, -1)
var/list/d4 = collect_direction(current_list, x, y, -1, 1)
var/list/diag2 = d3 + d4
diag2 -= "[x],[y]"
if(length(diag2) >= win_count)
winning_tiles = diag2
game_state = GAME_OVER
winner = user_name
return
check_draw()
/datum/board_game/four_row/proc/check_draw()
for(var/x = 1 to grid_x_size)
for(var/y = 1 to grid_y_size)
var/key = "[x],[y]"
if(!placed_chips_pone[key] && !placed_chips_ptwo[key])
return FALSE
winner = null
game_state = GAME_OVER_DRAW
return TRUE
/datum/board_game/four_row/proc/set_new_size(new_size)
if(!isnum(new_size))
return FALSE
if(new_size < 5 || new_size > 10)
return FALSE
grid_x_size = new_size
grid_y_size = new_size - 1
return TRUE
/datum/board_game/four_row/proc/field_check(new_x_location, new_y_location)
if(new_x_location < 1 || new_x_location > grid_x_size)
return FALSE
if(new_y_location < 1 || new_y_location > grid_y_size)
return FALSE
return TRUE
/datum/board_game/four_row/proc/validate_coords(list/params)
var/x_loc = text2num(params["loc_x"])
var/y_loc = text2num(params["loc_y"])
if(!isnum(x_loc) || !isnum(y_loc))
return null
if(!field_check(x_loc, y_loc))
return null
var/key = "[x_loc],[y_loc]"
return list(key, x_loc, y_loc)
#undef GAME_PLAYER_ONE
#undef GAME_PLAYER_TWO
#undef GAME_OVER
#undef GAME_OVER_DRAW
@@ -0,0 +1,421 @@
#define GAME_PLAYER_ONE 1
#define GAME_PLAYER_TWO 2
#define GAME_OVER 3
#define GAME_OVER_DRAW 4
#define NODE_COUNT 24
#define GAME_ACTION_NONE 0
#define GAME_ACTION_SELECT 1
#define GAME_ACTION_END_TURN 2
#define GAME_PHASE_PLACING 0
#define GAME_PHASE_MOVING 1
#define GAME_PHASE_REMOVING 2
#define GAME_PHASE_NONE 3
/obj/structure/casino_table/board_game/nine_mens
name = GAME_NINE_MENS_MORRIS
desc = "A classic nine_mens game."
icon_state = "gamble_ninemen"
game_ui = /datum/board_game/nine_mens
/datum/board_game/nine_mens
name = GAME_NINE_MENS_MORRIS
table_icon = "gamble_ninemen"
var/datum/weakref/player_one
var/datum/weakref/player_two
var/player_one_time = 0
var/player_two_time = 0
var/list/current_board = list(
null, null, null,
null, null, null,
null, null, null,
null, null, null,
null, null, null,
null, null, null,
null, null, null,
null, null, null
)
var/static/list/adjacent = list(
list(2, 10),
list(1, 3, 5),
list(2, 15),
list(5, 11),
list(2, 4, 6, 8),
list(5, 14),
list(8, 12),
list(5, 7, 9),
list(8, 13),
list(1, 11, 22),
list(4, 10, 12, 19),
list(7, 11, 16),
list(9, 14, 18),
list(6, 13, 15, 21),
list(3, 14, 24),
list(12, 17),
list(16, 18, 20),
list(13, 17),
list(11, 20),
list(17, 19, 21, 23),
list(14, 20),
list(10, 23),
list(20, 22, 24),
list(15, 23)
)
var/static/list/mills = list(
list(1,2,3),
list(4,5,6),
list(7,8,9),
list(10,11,12),
list(13,14,15),
list(16,17,18),
list(19,20,21),
list(22,23,24),
list(1,10,22),
list(4,11,19),
list(7,12,16),
list(2,5,8),
list(17,20,23),
list(9,13,18),
list(6,14,21),
list(3,15,24)
)
var/list/valid_moves = list()
var/list/valid_removes = list()
var/selected_node
var/turn_start_time = 0
var/pone_pieces = 9
var/ptwo_pieces = 9
var/winner
var/phase = GAME_PHASE_PLACING
/datum/board_game/nine_mens/Destroy(force)
player_one = null
player_two = null
. = ..()
/datum/board_game/nine_mens/tgui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "NineMen", name)
ui.open()
/datum/board_game/nine_mens/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
var/mob/player_one_mob = player_one?.resolve()
var/mob/player_two_mob = player_two?.resolve()
return list(
"player_one" = player_one_mob,
"player_two" = player_two_mob,
"player_one_time" = player_one_time + (game_state == GAME_PLAYER_ONE ? world.time - turn_start_time : 0),
"player_two_time" = player_two_time + (game_state == GAME_PLAYER_TWO ? world.time - turn_start_time : 0),
"current_board" = current_board,
"selected_node" = selected_node,
"valid_moves" = valid_moves,
"valid_removes" = valid_removes,
"game_state" = game_state,
"winner" = winner,
"has_won" = winner == ui.user.name,
"phase" = phase,
"pone_pieces" = pone_pieces,
"ptwo_pieces" = ptwo_pieces
)
/datum/board_game/nine_mens/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
. = ..()
if(.)
return
switch(action)
if("be_player_one")
if(game_state != GAME_SETUP)
return FALSE
if(player_one?.resolve() == ui.user)
player_one = null
return TRUE
player_one = WEAKREF(ui.user)
return TRUE
if("be_player_two")
if(game_state != GAME_SETUP)
return FALSE
if(player_two?.resolve() == ui.user)
player_two = null
return TRUE
player_two = WEAKREF(ui.user)
return TRUE
if("swap_players")
if(game_state != GAME_SETUP)
return FALSE
if(!player_one?.resolve() || !player_two?.resolve())
return FALSE
var/datum/weakref/temp_player = player_one
player_one = player_two
player_two = temp_player
if("clear_game")
if(game_state == GAME_SETUP)
return FALSE
reset(TRUE)
return TRUE
if("start_game")
if(game_state != GAME_SETUP)
return FALSE
if(!player_one?.resolve() || !player_two?.resolve())
return FALSE
game_state = GAME_PLAYER_ONE
turn_start_time = world.time
return TRUE
if("play_again")
if(game_state < GAME_OVER)
return FALSE
if(!player_one?.resolve() || !player_two?.resolve())
return FALSE
reset()
turn_start_time = world.time
return TRUE
if("play_again_swapped")
if(game_state < GAME_OVER)
return FALSE
if(!player_one?.resolve() || !player_two?.resolve())
return FALSE
reset()
var/datum/weakref/temp_player = player_one
player_one = player_two
player_two = temp_player
turn_start_time = world.time
return TRUE
if("game_action")
if(ui.user == player_one?.resolve() && game_state == GAME_PLAYER_ONE)
var/game_action = player_actions(params["action"], params["data"], ui.user, "w")
if(game_action)
if(game_state < GAME_OVER && game_action == GAME_ACTION_END_TURN)
game_state = GAME_PLAYER_TWO
turn_start_time = world.time
return TRUE
if(ui.user == player_two?.resolve() && game_state == GAME_PLAYER_TWO)
var/game_action = player_actions(params["action"], params["data"], ui.user, "b")
if(game_action)
if(game_state < GAME_OVER && game_action == GAME_ACTION_END_TURN)
game_state = GAME_PLAYER_ONE
turn_start_time = world.time
return TRUE
return FALSE
/datum/board_game/nine_mens/proc/reset(full)
winner = null
player_one_time = 0
player_two_time = 0
selected_node = null
valid_moves.Cut()
valid_removes.Cut()
pone_pieces = 9
ptwo_pieces = 9
phase = GAME_PHASE_PLACING
for(var/i = 1 to NODE_COUNT)
current_board[i] = null
if(full)
game_state = GAME_SETUP
player_one = null
player_two = null
else
game_state = GAME_PLAYER_ONE
/datum/board_game/nine_mens/proc/player_actions(action, list/params, mob/user, active_color)
switch(action)
if("select_figure")
var/node = validate_node(params)
if(!node)
return GAME_ACTION_NONE
var/piece = current_board[node]
if(!piece || piece[1] != active_color)
return GAME_ACTION_NONE
selected_node = node
update_valid_moves()
return GAME_ACTION_SELECT
if("move_figure")
var/target_node = validate_node(params)
if(!target_node)
return GAME_ACTION_NONE
switch(phase)
if(GAME_PHASE_PLACING)
if(current_board[target_node])
return GAME_ACTION_NONE
current_board[target_node] = active_color
if(active_color == "w")
if(pone_pieces > 0)
pone_pieces--
else
if(ptwo_pieces > 0)
ptwo_pieces--
if(check_for_mill(target_node, active_color))
phase = GAME_PHASE_REMOVING
update_valid_removals(active_color == "w" ? "b" : "w")
else
if((ptwo_pieces && active_color == "w") || (pone_pieces && active_color == "b"))
phase = GAME_PHASE_PLACING
else
phase = GAME_PHASE_MOVING
return phase == GAME_PHASE_REMOVING ? GAME_ACTION_SELECT : GAME_ACTION_END_TURN
if(GAME_PHASE_MOVING)
if(!selected_node)
return GAME_ACTION_NONE
if(!valid_move(active_color, selected_node, target_node))
return GAME_ACTION_NONE
current_board[target_node] = current_board[selected_node]
current_board[selected_node] = null
selected_node = null
valid_moves.Cut()
validate_victory(active_color)
if(game_state < GAME_OVER)
if(check_for_mill(target_node, active_color))
phase = GAME_PHASE_REMOVING
update_valid_removals(active_color == "w" ? "b" : "w")
else
phase = GAME_PHASE_MOVING
else
phase = GAME_PHASE_NONE
return phase == GAME_PHASE_REMOVING ? GAME_ACTION_SELECT : GAME_ACTION_END_TURN
if(GAME_PHASE_REMOVING)
if(!valid_remove(target_node))
return GAME_ACTION_NONE
current_board[target_node] = null
valid_removes.Cut()
validate_victory(active_color)
if(game_state < GAME_OVER)
if((ptwo_pieces && active_color == "w") || (pone_pieces && active_color == "b"))
phase = GAME_PHASE_PLACING
else
phase = GAME_PHASE_MOVING
else
phase = GAME_PHASE_NONE
return GAME_ACTION_END_TURN
return GAME_ACTION_NONE
/datum/board_game/nine_mens/proc/update_valid_moves()
valid_moves.Cut()
if(selected_node)
valid_moves = generate_valid_moves(selected_node)
/datum/board_game/nine_mens/proc/update_valid_removals(opponent_color)
valid_removes.Cut()
for(var/i = 1 to NODE_COUNT)
if(current_board[i] && current_board[i][1] == opponent_color)
if(!check_for_mill(i, opponent_color))
valid_removes += i
if(!length(valid_removes))
for(var/i = 1 to NODE_COUNT)
if(current_board[i] && current_board[i][1] == opponent_color)
valid_removes += i
/datum/board_game/nine_mens/proc/valid_remove(picked_node)
if(!picked_node || !current_board[picked_node] || !(picked_node in valid_removes))
return FALSE
return TRUE
/datum/board_game/nine_mens/proc/check_for_mill(node, color)
for(var/mill in mills)
if(node in mill)
var/mill_complete = TRUE
for(var/mill_node in mill)
if(!current_board[mill_node] || current_board[mill_node][1] != color)
mill_complete = FALSE
break
if(mill_complete)
return TRUE
return FALSE
/datum/board_game/nine_mens/proc/valid_move(active_color, from_node, to_node)
if(current_board[to_node])
return FALSE
if(count_pieces(active_color) == 3)
return TRUE
for(var/adj in adjacent[from_node])
if(adj == to_node)
return TRUE
return FALSE
/datum/board_game/nine_mens/proc/validate_victory(active_color)
var/opponent = (active_color == "w") ? "b" : "w"
if(count_pieces(opponent) < 3 || !has_moves(opponent))
var/mob/winning_player = (active_color == "w" ? player_one?.resolve() : player_two?.resolve())
winner = winning_player?.name
game_state = GAME_OVER
/datum/board_game/nine_mens/proc/generate_valid_moves(node)
var/list/moves = list()
if(!current_board[node])
return moves
var/color = current_board[node][1]
if(count_pieces(color) == 3)
for(var/i = 1 to NODE_COUNT)
if(!current_board[i])
moves += i
return moves
for(var/adj in adjacent[node])
if(!current_board[adj])
moves += adj
return moves
/datum/board_game/nine_mens/proc/count_pieces(color)
var/count = color == "w" ? pone_pieces : ptwo_pieces
for(var/i = 1 to NODE_COUNT)
if(current_board[i] && current_board[i][1] == color)
count++
return count
/datum/board_game/nine_mens/proc/has_moves(color)
for(var/i = 1 to NODE_COUNT)
if(current_board[i] && current_board[i][1] == color)
if(length(generate_valid_moves(i)))
return TRUE
return FALSE
/datum/board_game/nine_mens/proc/validate_node(list/params)
var/node = text2num(params["node_number"])
if(!isnum(node))
return null
if(node < 1 || node > 24)
return null
return node
#undef GAME_PLAYER_ONE
#undef GAME_PLAYER_TWO
#undef GAME_OVER
#undef GAME_OVER_DRAW
#undef NODE_COUNT
#undef GAME_ACTION_NONE
#undef GAME_ACTION_SELECT
#undef GAME_ACTION_END_TURN
#undef GAME_PHASE_PLACING
#undef GAME_PHASE_MOVING
#undef GAME_PHASE_REMOVING
#undef GAME_PHASE_NONE
@@ -0,0 +1,72 @@
/obj/structure/casino_table/board_game/rpg_dice
name = GAME_RGP_DICE
desc = "A set of dice to roll with your friends."
icon_state = "gamble_dice"
game_ui = /datum/board_game/rpg_dice
/datum/board_game/rpg_dice
name = GAME_RGP_DICE
table_icon = "gamble_dice"
var/list/last_rolls = list()
/datum/board_game/rpg_dice/tgui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "RpgDice", name)
ui.open()
/datum/board_game/rpg_dice/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
return list(
"last_rolls" = last_rolls,
)
/datum/board_game/rpg_dice/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
. = ..()
if(.)
return
switch(action)
if("roll_dice")
var/dice_size = params["dice_size"]
if(!isnum(dice_size) || dice_size > 10000)
return FALSE
var/dice_count = params["dice_count"]
if(!isnum(dice_count) || dice_count < 1 || dice_count > 10)
dice_count = 1
var/modifier = params["dice_mod"]
var/list/results = list()
var/sum = 0
if(!isnum(modifier))
modifier = 0
var/apply_to_all = params["mod_all"]
for(var/dice in 1 to dice_count)
var/result = rand(1, dice_size)
UNTYPED_LIST_ADD(results, list("result" = result, "state" = check_crit(1, dice_size, result)))
sum += result
sum += apply_to_all ? modifier * dice_count : modifier
UNTYPED_LIST_ADD(last_rolls, list("player" = ui.user, "count" = dice_count, "size" = dice_size, "results" = results, "mod" = modifier, "apply_to_all" = apply_to_all, "sum" = sum))
return TRUE
/* Requires rust g dice
if("custom_roll")
var/input = params["custom"]
if(length(input) > 200)
to_chat(ui.user, span_warning("Your input was too long."))
return FALSE
var/static/regex/valid_dice_roll = regex(@"^(\d+d\d+(\s*[\+\-\*\/]\s*\d+)?(\s*[\+\-\*\/]\s*\d+d\d+(\s*[\+\-\*\/]\s*\d+)?)*)$")
if(!findtext(input, valid_dice_roll))
to_chat(ui.user, span_warning("Invalid input, please follow the common pattern e.g.: 2d6 + 3d10 + 5"))
return FALSE
var/result = rustg_roll_dice("[input]")
UNTYPED_LIST_ADD(last_rolls, list("player" = ui.user, "count" = input, "sum" = result))
return TRUE
*/
if("clear_history")
last_rolls.Cut()
return TRUE
/datum/board_game/rpg_dice/proc/check_crit(low, max, result)
if(result == low)
return 1
if(result == max)
return 2
return 0
@@ -0,0 +1,436 @@
#define GAME_PLACE_SHIPS 1
#define GAME_PLAYER_ONE 2
#define GAME_PLAYER_TWO 3
#define GAME_OVER 4
#define GRID_SIZE 10
#define PLAYER_ONE_PLACED_SHIPS 0x1
#define PLAYER_TWO_PLACED_SHIPS 0x2
/obj/structure/casino_table/board_game/space_battle
name = GAME_SPACE_BATTLE
desc = "A game with the goal to destroy the opponent's ships."
icon_state = "gamble_space"
game_ui = /datum/board_game/space_battle
/datum/board_game/space_battle
name = GAME_SPACE_BATTLE
table_icon = "gamble_space"
var/datum/weakref/player_one
var/datum/weakref/player_two
var/list/ship_count_pone = list()
var/list/ship_count_ptwo = list()
var/list/shots_fired_pone = list()
var/list/shots_fired_ptwo = list()
var/list/ships_placed_pone = list()
var/list/ships_placed_ptwo = list()
var/list/destroyed_ships_pone = list()
var/list/destroyed_ships_ptwo = list()
var/static/list/total_ships = list(
"Carrier" = 1,
"Cruiser" = 2,
"Corvette" = 3,
"Figher" = 4,
)
var/static/list/ship_sizes = list(
"Carrier" = 6,
"Cruiser" = 4,
"Corvette" = 3,
"Figher" = 2,
)
var/winner
var/ships_have_been_placed = NONE
/datum/board_game/space_battle/Destroy(force)
player_one = null
player_two = null
. = ..()
/datum/board_game/space_battle/tgui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "SpaceBattle", name)
ui.open()
/datum/board_game/space_battle/tgui_static_data(mob/user)
return list(
"ship_sizes" = ship_sizes,
"total_ships" = total_ships
)
/datum/board_game/space_battle/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
var/mob/player_one_mob = player_one?.resolve()
var/mob/player_two_mob = player_two?.resolve()
var/list/visible_ships = list()
if(ui.user == player_one_mob || game_state == GAME_OVER)
visible_ships += ships_placed_pone
if(ui.user == player_two_mob || game_state == GAME_OVER)
visible_ships += ships_placed_ptwo
return list(
"current_player" = ui.user,
"player_one" = player_one_mob,
"player_two" = player_two_mob,
"all_placed" = ships_have_been_placed == (PLAYER_ONE_PLACED_SHIPS | PLAYER_TWO_PLACED_SHIPS),
"shots_fired_pone" = shots_fired_pone,
"shots_fired_ptwo" = shots_fired_ptwo,
"destroyed_ships_pone" = destroyed_ships_pone,
"destroyed_ships_ptwo" = destroyed_ships_ptwo,
"visible_ships" = visible_ships,
"ship_count_pone" = ship_count_pone,
"ship_count_ptwo" = ship_count_ptwo,
"game_state" = game_state,
"winner" = winner,
"has_won" = winner == ui.user.name
)
/datum/board_game/space_battle/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
. = ..()
if(.)
return
switch(action)
if("be_player_one")
if(game_state != GAME_SETUP)
return FALSE
if(player_one?.resolve() == ui.user)
player_one = null
return TRUE
player_one = WEAKREF(ui.user)
return TRUE
if("be_player_two")
if(game_state != GAME_SETUP)
return FALSE
if(player_two?.resolve() == ui.user)
player_two = null
return TRUE
player_two = WEAKREF(ui.user)
return TRUE
if("swap_players")
if(game_state != GAME_SETUP)
return FALSE
if(!player_one?.resolve() || !player_two?.resolve())
return FALSE
var/datum/weakref/temp_player = player_one
player_one = player_two
player_two = temp_player
if("clear_game")
if(game_state == GAME_SETUP)
return FALSE
reset(TRUE)
return TRUE
if("prepare_game")
if(game_state != GAME_SETUP)
return FALSE
var/mob/player_one_mob = player_one?.resolve()
var/mob/player_two_mob = player_two?.resolve()
if(!player_one_mob || !player_two_mob)
return FALSE
game_state = GAME_PLACE_SHIPS
ship_count_pone = get_remaining_ships(1)
ship_count_ptwo = get_remaining_ships(2)
return TRUE
if("start_game")
if(game_state != GAME_PLACE_SHIPS)
return FALSE
if(!(ships_have_been_placed == (PLAYER_ONE_PLACED_SHIPS | PLAYER_TWO_PLACED_SHIPS)))
return FALSE
var/mob/player_one_mob = player_one?.resolve()
var/mob/player_two_mob = player_two?.resolve()
if(!player_one_mob || !player_two_mob)
return FALSE
ship_count_pone = get_alive_ships(1)
ship_count_ptwo = get_alive_ships(2)
game_state = GAME_PLAYER_ONE
return TRUE
if("play_again")
if(game_state < GAME_OVER)
return FALSE
if(!player_one?.resolve() || !player_two?.resolve())
return FALSE
reset()
return TRUE
if("play_again_swapped")
if(game_state < GAME_OVER)
return FALSE
if(!player_one?.resolve() || !player_two?.resolve())
return FALSE
reset()
var/datum/weakref/temp_player = player_one
player_one = player_two
player_two = temp_player
return TRUE
if("place_ship")
if(game_state != GAME_PLACE_SHIPS)
return FALSE
var/mob/player_one_mob = player_one?.resolve()
var/mob/player_two_mob = player_two?.resolve()
if(!player_one_mob || !player_two_mob)
return FALSE
var/list/ship_data = params["ship"]
if(!ship_data["name"] || !ship_data["coords"])
return FALSE
var/player = ship_data["player"]
if(!player)
return FALSE
if(player == 1 && ui.user != player_one_mob)
return FALSE
if(player == 2 && ui.user != player_two_mob)
return FALSE
var/allowed = total_ships[ship_data["name"]]
if(!allowed)
return FALSE
var/list/current_ships
if(player == 1)
current_ships = ships_placed_pone
else
current_ships = ships_placed_ptwo
var/count = 0
for(var/list/existing in current_ships)
if(existing["name"] == ship_data["name"])
count++
if(count >= allowed)
return FALSE
var/list/new_coords = ship_data["coords"]
for(var/list/new_coord in new_coords)
if(!isnum(new_coord[1]) || !isnum(new_coord[2]))
return FALSE
if(!field_check(new_coord[1], new_coord[2]))
return FALSE
for(var/list/existing_ship in current_ships)
for(var/list/coord in existing_ship["coords"])
for(var/list/new_coord in new_coords)
if(coord[1] == new_coord[1] && coord[2] == new_coord[2])
return FALSE
UNTYPED_LIST_ADD(current_ships, ship_data)
if(player == 1)
ship_count_pone = get_remaining_ships(1)
else
ship_count_ptwo = get_remaining_ships(2)
return TRUE
if("remove_ship")
if(game_state != GAME_PLACE_SHIPS)
return FALSE
var/mob/player_one_mob = player_one?.resolve()
var/mob/player_two_mob = player_two?.resolve()
if(!player_one_mob || !player_two_mob)
return FALSE
var/player = params["player"]
if(player == 1 && ui.user != player_one_mob)
return FALSE
if(player == 2 && ui.user != player_two_mob)
return FALSE
var/list/ships
if(player == 1)
ships = ships_placed_pone
else
ships = ships_placed_ptwo
var/loc_x = params["loc_x"]
var/loc_y = params["loc_y"]
for(var/i in length(ships) to 1 step -1)
var/list/ship = ships[i]
for(var/list/coord in ship["coords"])
if(coord[1] == loc_x && coord[2] == loc_y)
ships.Cut(i, i + 1)
if(player == 1)
ship_count_pone = get_remaining_ships(1)
else
ship_count_ptwo = get_remaining_ships(2)
return TRUE
return FALSE
if("game_action")
if(ui.user == player_one?.resolve() && game_state == GAME_PLAYER_ONE)
if(params["data"]["player"] == 1)
return FALSE
if(player_actions(params["action"], params["data"], ui.user))
if(game_state < GAME_OVER)
game_state = GAME_PLAYER_TWO
return TRUE
if(ui.user == player_two?.resolve() && game_state == GAME_PLAYER_TWO)
if(params["data"]["player"] == 2)
return FALSE
if(player_actions(params["action"], params["data"], ui.user))
if(game_state < GAME_OVER)
game_state = GAME_PLAYER_ONE
return TRUE
return FALSE
/datum/board_game/space_battle/proc/reset(full)
ship_count_pone.Cut()
ship_count_ptwo.Cut()
shots_fired_pone.Cut()
shots_fired_ptwo.Cut()
ships_placed_pone.Cut()
ships_placed_ptwo.Cut()
destroyed_ships_pone.Cut()
destroyed_ships_ptwo.Cut()
winner = null
ships_have_been_placed = NONE
if(full)
game_state = GAME_SETUP
player_one = null
player_two = null
else
game_state = GAME_PLACE_SHIPS
/datum/board_game/space_battle/proc/player_actions(action, list/params, mob/user)
switch(action)
if("fire_shot")
var/list/validated_data = validate_coords(params)
if(!validated_data)
return FALSE
var/key = validated_data[1]
var/list/opponent_ships
var/list/current_shots
if(game_state == GAME_PLAYER_ONE)
current_shots = shots_fired_pone
opponent_ships = ships_placed_ptwo
else
current_shots = shots_fired_ptwo
opponent_ships = ships_placed_pone
if(!isnull(current_shots[key]))
return FALSE
var/hit = 0
for(var/list/ship in opponent_ships)
for(var/coord in ship["coords"])
if(coord[1] == validated_data[2] && coord[2] == validated_data[3])
hit = 1
break
if(hit)
break
current_shots[key] = hit
if(hit)
validate_victory(opponent_ships, current_shots, user)
return TRUE
/datum/board_game/space_battle/proc/validate_victory(list/opponent_ships, list/current_shots, mob/user)
for(var/list/ship in opponent_ships)
var/ship_destroyed = TRUE
for(var/coord in ship["coords"])
var/key = "[coord[1]],[coord[2]]"
if(!current_shots[key])
ship_destroyed = FALSE
break
if(ship_destroyed)
if(game_state == GAME_PLAYER_ONE)
if(!(destroyed_ships_pone.Find(ship)))
UNTYPED_LIST_ADD(destroyed_ships_pone, ship)
ship_count_pone = get_alive_ships(1)
else
if(!(destroyed_ships_ptwo.Find(ship)))
UNTYPED_LIST_ADD(destroyed_ships_ptwo, ship)
ship_count_ptwo = get_alive_ships(2)
for(var/list/ship in opponent_ships)
var/key
for(var/coord in ship["coords"])
key = "[coord[1]],[coord[2]]"
if(!current_shots[key])
return
winner = user.name
game_state = GAME_OVER
/datum/board_game/space_battle/proc/field_check(new_x_location, new_y_location)
if(new_x_location < 1 || new_x_location > GRID_SIZE)
return FALSE
if(new_y_location < 1 || new_y_location > GRID_SIZE)
return FALSE
return TRUE
/datum/board_game/space_battle/proc/validate_coords(list/params)
var/x_loc = text2num(params["loc_x"])
var/y_loc = text2num(params["loc_y"])
if(!isnum(x_loc) || !isnum(y_loc))
return null
if(!field_check(x_loc, y_loc))
return null
var/key = "[x_loc],[y_loc]"
return list(key, x_loc, y_loc)
/datum/board_game/space_battle/proc/get_remaining_ships(player)
var/list/remaining_ships = list()
var/list/placed_ships
var/ship_placed_flag
if(player == 1)
placed_ships = ships_placed_pone
ship_placed_flag = PLAYER_ONE_PLACED_SHIPS
else if(player == 2)
placed_ships = ships_placed_ptwo
ship_placed_flag = PLAYER_TWO_PLACED_SHIPS
else
return remaining_ships
for(var/ship_name in ship_sizes)
var/allowed_count = total_ships[ship_name]
var/placed_count = 0
for(var/list/placed_ship in placed_ships)
if(placed_ship["name"] == ship_name)
placed_count++
var/remaining_count = allowed_count - placed_count
if(remaining_count > 0)
remaining_ships[ship_name] = remaining_count
if(length(remaining_ships))
ships_have_been_placed &= ~ship_placed_flag
else
ships_have_been_placed |= ship_placed_flag
return remaining_ships
/datum/board_game/space_battle/proc/get_alive_ships(player)
var/list/alive_ships = list()
var/list/ships
if(player == 1)
ships = ships_placed_pone
else if(player == 2)
ships = ships_placed_ptwo
else
return alive_ships
for(var/list/ship in ships)
if(game_state == GAME_PLAYER_ONE && !(destroyed_ships_pone.Find(ship)))
alive_ships[ship["name"]] = length(alive_ships) ? alive_ships[ship["name"]] + 1 : 1
if(game_state == GAME_PLAYER_TWO && !(destroyed_ships_ptwo.Find(ship)))
alive_ships[ship["name"]] = length(alive_ships) ? alive_ships[ship["name"]] + 1 : 1
return alive_ships
#undef GAME_PLACE_SHIPS
#undef GAME_PLAYER_ONE
#undef GAME_PLAYER_TWO
#undef GAME_OVER
#undef GRID_SIZE
#undef PLAYER_ONE_PLACED_SHIPS
#undef PLAYER_TWO_PLACED_SHIPS
@@ -0,0 +1,51 @@
#define GAME_PLAYER_ONE 1
#define GRID_SIZE 3
/obj/structure/casino_table/board_game/tic_tac_toe
name = GAME_TIC_TAC_TOE
desc = "A small tic-tac-toe board."
icon_state = "gamble_toe"
game_ui = /datum/board_game/four_row/tic_tac_toe
/datum/board_game/four_row/tic_tac_toe
name = GAME_TIC_TAC_TOE
table_icon = "gamble_toe"
grid_x_size = GRID_SIZE
grid_y_size = GRID_SIZE
win_count = GRID_SIZE
/datum/board_game/four_row/tic_tac_toe/tgui_static_data(mob/user)
return list(
"colors" = possible_colors - "blue"
)
/datum/board_game/four_row/tic_tac_toe/player_actions(action, list/params, mob/user)
switch(action)
if("place_chip")
var/list/validated_data = validate_coords(params)
if(!validated_data)
return FALSE
var/key = validated_data[1]
if(placed_chips_pone[key] || placed_chips_ptwo[key])
return FALSE
var/x_loc = validated_data[2]
var/y_loc = validated_data[3]
if(game_state == GAME_PLAYER_ONE)
placed_chips_pone[key] = TRUE
else
placed_chips_ptwo[key] = TRUE
validate_victory(x_loc, y_loc, user.name)
return TRUE
/datum/board_game/four_row/tic_tac_toe/set_new_size(new_size)
return FALSE
/datum/board_game/four_row/change_win_count(new_count)
return FALSE
#undef GAME_PLAYER_ONE
#undef GRID_SIZE
@@ -0,0 +1,321 @@
#define GAME_PLAYING 1
#define GAME_LOST 2
#define GAME_WON 3
#define MAX_MINE_RATE 0.8
/obj/structure/casino_table/board_game/vore_sweeper
name = GAME_SWEEPER
desc = "A game about avoiding the mines"
icon_state = "gamble_sweeper"
game_ui = /datum/board_game/vore_sweeper
/datum/board_game/vore_sweeper
name = GAME_SWEEPER
table_icon = "gamble_sweeper"
var/grid_size = 8
var/mine_count = 10
var/datum/weakref/dealer
var/list/placed_mines = list()
var/list/revealed_fields = list()
var/list/placed_flags = list()
/datum/board_game/vore_sweeper/New(atom/holder)
. = ..()
parent = holder
/datum/board_game/vore_sweeper/Destroy(force)
dealer = null
parent = null
. = ..()
/datum/board_game/vore_sweeper/tgui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "VoreSweeper", name)
ui.open()
/datum/board_game/vore_sweeper/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
var/mob/dealer_mob = dealer?.resolve()
var/placed_mine_data = game_state > GAME_PLAYING || (ui.user == dealer_mob) ? placed_mines : null
var/total_tiles = grid_size * grid_size
return list(
"grid_size" = grid_size,
"mine_count" = mine_count,
"max_mines" = round(total_tiles * MAX_MINE_RATE),
"dealer" = dealer_mob,
"placed_mines" = placed_mine_data,
"revealed_fields" = revealed_fields,
"placed_flags" = placed_flags,
"game_state" = game_state,
"is_dealer" = dealer_mob == ui.user
)
/datum/board_game/vore_sweeper/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
. = ..()
if(.)
return
switch(action)
if("be_dealer")
if(game_state == GAME_PLAYING)
return FALSE
dealer = WEAKREF(ui.user)
return TRUE
if("clear_dealer")
var/mob/dealer_mob = dealer?.resolve()
if(!dealer_mob)
return FALSE
if(dealer_mob == ui.user)
parent.atom_say("[ui.user] stopped dealing.")
dealer = null
return TRUE
if(get_dist(ui.user, dealer_mob) > 3)
parent.atom_say("Dealer has been cleared by [ui.user].")
dealer = null
return TRUE
return FALSE
if("restart_game")
var/mob/dealer_mob = dealer?.resolve()
if(game_state < GAME_PLAYING)
return FALSE
placed_mines.Cut()
revealed_fields.Cut()
placed_flags.Cut()
if(!dealer_mob && game_state > GAME_PLAYING)
auto_place_mines(ui.user, TRUE)
return TRUE
game_state = GAME_SETUP
return TRUE
if("game_action")
if(player_actions(params["action"], params["data"], ui.user))
return TRUE
return FALSE
if("setup_action")
if(dealer_actions(params["action"], params["data"], ui.user))
return TRUE
return FALSE
/datum/board_game/vore_sweeper/proc/player_actions(action, list/params, mob/user)
if(user == dealer?.resolve())
return FALSE
if(game_state != GAME_PLAYING)
return FALSE
switch(action)
if("open_field")
var/list/validated_data = validate_coords(params)
if(!validated_data)
return FALSE
var/key = validated_data[1]
if(placed_flags[key])
return FALSE
if(revealed_fields[key])
return FALSE
if(placed_mines[key])
game_state = GAME_LOST
revealed_fields[key] = "M"
return TRUE
var/mine_count = count_surrounding_mines(validated_data[2], validated_data[3])
revealed_fields[key] = mine_count
if(!mine_count)
reveal_empty_area(validated_data[2], validated_data[3])
validate_victory()
return TRUE
if("toggle_flag")
var/list/validated_data = validate_coords(params)
if(!validated_data)
return FALSE
var/key = validated_data[1]
if(revealed_fields[key])
return FALSE
if(placed_flags[key])
placed_flags -= key
return TRUE
placed_flags[key] = TRUE
validate_flag_victory()
return TRUE
/datum/board_game/vore_sweeper/proc/validate_victory()
var/total_tiles = grid_size * grid_size
var/safe_tiles = total_tiles - length(placed_mines)
if(length(revealed_fields) >= safe_tiles)
game_state = GAME_WON
/datum/board_game/vore_sweeper/proc/validate_flag_victory()
var/all_flagged = TRUE
for(var/mine_key in placed_mines)
if(placed_mines[mine_key] && !placed_flags[mine_key])
all_flagged = FALSE
break
for(var/flag_key in placed_flags)
if(!placed_mines[flag_key])
all_flagged = FALSE
break
if(!all_flagged)
return
for(var/x = 1 to grid_size)
for(var/y = 1 to grid_size)
var/key = "[x],[y]"
if(placed_mines[key])
continue
revealed_fields[key] = count_surrounding_mines(x, y)
game_state = GAME_WON
/datum/board_game/vore_sweeper/proc/dealer_actions(action, list/params, mob/user)
if(user != dealer?.resolve())
return FALSE
if(game_state != GAME_SETUP)
return FALSE
switch(action)
if("change_grid_size")
var/new_grid_size = text2num(params["new_grid"])
if(!new_grid_size)
return FALSE
if(new_grid_size < 4 || new_grid_size > 16)
return FALSE
validate_mine_count(mine_count, new_grid_size)
grid_size = new_grid_size
return TRUE
if("change_mine_count")
var/new_mine_count = text2num(params["new_mines"])
if(!new_mine_count)
return FALSE
validate_mine_count(new_mine_count, grid_size)
return TRUE
if("place_mine")
if(length(placed_mines) >= mine_count)
return FALSE
var/list/validated_data = validate_coords(params)
if(!validated_data)
return FALSE
var/key = validated_data[1]
if(placed_mines[key])
return FALSE
placed_mines[key] = TRUE
return TRUE
if("remove_mine")
if(game_state != GAME_SETUP)
return FALSE
if(length(placed_mines) <= 0)
return FALSE
var/list/validated_data = validate_coords(params)
if(!validated_data)
return FALSE
var/key = validated_data[1]
placed_mines -= key
return TRUE
if("auto_place_mines")
return auto_place_mines(user)
if("auto_place_mines_self")
return auto_place_mines(user, TRUE)
if("clear_all_mines")
placed_mines.Cut()
return TRUE
if("start_game")
game_state = GAME_PLAYING
return TRUE
/datum/board_game/vore_sweeper/proc/reveal_empty_area(x, y)
var/list/to_check = list(list(x, y))
var/list/checked = list()
var/i = 1
while(i <= length(to_check))
var/current = to_check[i]
i += 1
var/cx = current[1]
var/cy = current[2]
var/key = "[cx],[cy]"
if(checked[key])
continue
checked[key] = TRUE
if(revealed_fields[key] || placed_flags[key])
continue
var/adjacent_mines = count_surrounding_mines(cx, cy)
revealed_fields[key] = adjacent_mines
if(adjacent_mines == 0)
for(var/dx = -1 to 1)
for(var/dy = -1 to 1)
if(dx == 0 && dy == 0)
continue
var/nx = cx + dx
var/ny = cy + dy
if(field_check(nx, ny))
to_check += list(list(nx, ny))
/datum/board_game/vore_sweeper/proc/auto_place_mines(mob/user, play)
var/placed = length(placed_mines)
if(placed && play)
to_chat(user, span_warning("You can't do this while there are mines placed."))
while(placed < mine_count)
var/x = rand(1, grid_size)
var/y = rand(1, grid_size)
var/key = "[x],[y]"
if(!placed_mines[key])
placed_mines[key] = TRUE
placed++
if(play)
dealer = null
game_state = GAME_PLAYING
return TRUE
/datum/board_game/vore_sweeper/proc/field_check(new_x_location, new_y_location)
if(new_x_location < 1 || new_x_location > grid_size)
return FALSE
if(new_y_location < 1 || new_y_location > grid_size)
return FALSE
return TRUE
/datum/board_game/vore_sweeper/proc/count_surrounding_mines(x, y)
var/count = 0
for(var/dx = -1 to 1)
for(var/dy = -1 to 1)
if(dx == 0 && dy == 0)
continue
var/check_x = x + dx
var/check_y = y + dy
if(placed_mines["[check_x],[check_y]"])
count++
return count
/datum/board_game/vore_sweeper/proc/validate_mine_count(mines, size)
var/total_tiles = size * size
var/max_mines = round(total_tiles * MAX_MINE_RATE)
if(mines <= max_mines)
mine_count = mines
return
parent.atom_say("The grid with [total_tiles] tiles only supports a maximum of [max_mines] mines.")
mine_count = max_mines
/datum/board_game/vore_sweeper/proc/validate_coords(list/params)
var/x_loc = text2num(params["loc_x"])
var/y_loc = text2num(params["loc_y"])
if(!isnum(x_loc) || !isnum(y_loc))
return null
if(!field_check(x_loc, y_loc))
return null
var/key = "[x_loc],[y_loc]"
return list(key, x_loc, y_loc)
#undef GAME_PLAYING
#undef GAME_LOST
#undef GAME_WON
#undef MAX_MINE_RATE
+15 -8
View File
@@ -767,19 +767,26 @@ var/global/image/backplane
return TRUE
/atom/proc/living_mobs_in_view(var/range = world.view, var/count_held = FALSE)
/atom/proc/living_mobs_in_view(var/range = world.view, var/count_held = FALSE, var/needs_client = FALSE)
var/list/viewers = oviewers(src, range)
if(count_held)
viewers = viewers(src,range)
var/list/living = list()
for(var/mob/living/L in viewers)
if(L.is_incorporeal())
for(var/mob/living/living_in_view in viewers)
if(living_in_view.is_incorporeal())
continue
living += L
if(count_held)
for(var/obj/item/holder/H in L.contents)
if(istype(H.held_mob, /mob/living))
living += H.held_mob
if(needs_client && !living_in_view.client)
continue
living += living_in_view
if(!count_held)
continue
for(var/obj/item/holder/mob_holder in living_in_view.contents)
if(!isliving(mob_holder.held_mob))
continue
var/mob/living/held_living = mob_holder.held_mob
if(needs_client && !held_living.client)
continue
living += held_living
return living
/proc/censor_swears(t)
+3 -3
View File
@@ -72,7 +72,7 @@
pda.current_app = src
return 1
/datum/data/pda/app/proc/update_ui(mob/user as mob, list/data)
/datum/data/pda/app/proc/update_ui(mob/user, list/data)
// Utilities just have a button on the home screen, but custom code when clicked
@@ -104,6 +104,6 @@
pda.update_shortcuts()
return 1
/datum/data/pda/utility/scanmode/proc/scan_mob(mob/living/C as mob, mob/living/user as mob)
/datum/data/pda/utility/scanmode/proc/scan_mob(mob/living/C, mob/living/user)
/datum/data/pda/utility/scanmode/proc/scan_atom(atom/A as mob|obj|turf|area, mob/user as mob)
/datum/data/pda/utility/scanmode/proc/scan_atom(atom/A, mob/user)
+8 -8
View File
@@ -7,7 +7,7 @@
var/message1 // used for status_displays
var/message2
/datum/data/pda/app/status_display/update_ui(mob/user as mob, list/data)
/datum/data/pda/app/status_display/update_ui(mob/user, list/data)
data["records"] = list(
"message1" = message1 ? message1 : "(none)",
"message2" = message2 ? message2 : "(none)")
@@ -63,7 +63,7 @@
template = "pda_signaller"
category = "Utilities"
/datum/data/pda/app/signaller/update_ui(mob/user as mob, list/data)
/datum/data/pda/app/signaller/update_ui(mob/user, list/data)
if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/radio/integrated/signal))
var/obj/item/radio/integrated/signal/R = pda.cartridge.radio
data["frequency"] = R.frequency
@@ -112,7 +112,7 @@
QDEL_NULL(power_monitor)
return ..()
/datum/data/pda/app/power/update_ui(mob/user as mob, list/data)
/datum/data/pda/app/power/update_ui(mob/user, list/data)
data.Add(power_monitor.tgui_data(user))
/datum/data/pda/app/power/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
@@ -128,7 +128,7 @@
/datum/data/pda/app/crew_records
var/datum/data/record/general_records = null
/datum/data/pda/app/crew_records/update_ui(mob/user as mob, list/data)
/datum/data/pda/app/crew_records/update_ui(mob/user, list/data)
var/list/records[0]
if(general_records && (general_records in GLOB.data_core.general))
@@ -169,7 +169,7 @@
var/datum/data/record/medical_records = null
/datum/data/pda/app/crew_records/medical/update_ui(mob/user as mob, list/data)
/datum/data/pda/app/crew_records/medical/update_ui(mob/user, list/data)
var/list/records = ..()
if(!records)
return
@@ -194,7 +194,7 @@
var/datum/data/record/security_records = null
/datum/data/pda/app/crew_records/security/update_ui(mob/user as mob, list/data)
/datum/data/pda/app/crew_records/security/update_ui(mob/user, list/data)
var/list/records = ..()
if(!records)
return
@@ -217,7 +217,7 @@
template = "pda_supply"
category = "Quartermaster"
/datum/data/pda/app/supply/update_ui(mob/user as mob, list/data)
/datum/data/pda/app/supply/update_ui(mob/user, list/data)
var/supplyData[0]
var/datum/shuttle/autodock/ferry/supply/shuttle = SSsupply.shuttle
if (shuttle)
@@ -254,7 +254,7 @@
template = "pda_janitor"
category = "Utilities"
/datum/data/pda/app/janitor/update_ui(mob/user as mob, list/data)
/datum/data/pda/app/janitor/update_ui(mob/user, list/data)
var/JaniData[0]
var/turf/cl = get_turf(pda)
+3 -3
View File
@@ -32,15 +32,15 @@
hold.max_storage_space = slots * 2
hold.max_w_class = ITEMSIZE_SMALL
/obj/item/cartridge/storage/attack_hand(mob/user as mob)
/obj/item/cartridge/storage/attack_hand(mob/user)
if (hold.handle_attack_hand(user)) //otherwise interact as a regular storage item
..(user)
/obj/item/cartridge/storage/attackby(obj/item/W as obj, mob/user as mob)
/obj/item/cartridge/storage/attackby(obj/item/W, mob/user)
..()
return hold.attackby(W, user)
/obj/item/cartridge/storage/MouseDrop(obj/over_object as obj)
/obj/item/cartridge/storage/MouseDrop(obj/over_object)
if (hold.handle_mousedrop(usr, over_object))
..(over_object)
+5 -5
View File
@@ -3,7 +3,7 @@
template = "pda_main_menu"
hidden = 1
/datum/data/pda/app/main_menu/update_ui(mob/user as mob, list/data)
/datum/data/pda/app/main_menu/update_ui(mob/user, list/data)
title = pda.name
data["app"]["is_home"] = 1
@@ -63,7 +63,7 @@
note = "Thank you for choosing the [pda.model_name]!"
notetitle = "Congratulations!"
/datum/data/pda/app/notekeeper/update_ui(mob/user as mob, list/data)
/datum/data/pda/app/notekeeper/update_ui(mob/user, list/data)
data["note"] = note // current pda notes
data["notename"] = "Note [GLOB.alphabet_upper[currentnote]] : [notetitle]"
@@ -206,7 +206,7 @@
icon = "user"
template = "pda_manifest"
/datum/data/pda/app/manifest/update_ui(mob/user as mob, list/data)
/datum/data/pda/app/manifest/update_ui(mob/user, list/data)
if(GLOB.data_core)
GLOB.data_core.get_manifest_list()
data["manifest"] = GLOB.PDA_Manifest
@@ -221,7 +221,7 @@
template = "pda_atmos_scan"
category = "Utilities"
/datum/data/pda/app/atmos_scanner/update_ui(mob/user as mob, list/data)
/datum/data/pda/app/atmos_scanner/update_ui(mob/user, list/data)
data["aircontents"] = get_gas_mixture_default_scan_data(get_turf(user))
/datum/data/pda/app/news
@@ -231,7 +231,7 @@
var/newsfeed_channel
/datum/data/pda/app/news/update_ui(mob/user as mob, list/data)
/datum/data/pda/app/news/update_ui(mob/user, list/data)
data["feeds"] = compile_news()
data["latest_news"] = get_recent_news()
if(newsfeed_channel)
+125
View File
@@ -0,0 +1,125 @@
/datum/data/pda/app/game_launcher
name = "Game Launcher"
icon = "dice"
notify_icon = "dice-d20"
title = "Game Launcher V1.0"
template = "pda_game_launcher"
var/datum/board_game/vore_sweeper/voresweeper
var/datum/board_game/four_row/fourrow
var/datum/board_game/space_battle/spacebattle
var/datum/board_game/rpg_dice/rpgdice
var/datum/board_game/chess/chess
var/datum/board_game/checkers/checkers
var/datum/board_game/nine_mens/ninemens
var/datum/board_game/four_row/tic_tac_toe/tictactoe
/datum/data/pda/app/game_launcher/update_ui(mob/user, list/data)
data["available_games"] = list(GAME_SWEEPER = voresweeper, GAME_FOUR_ROW = fourrow, GAME_SPACE_BATTLE = spacebattle, GAME_RGP_DICE = rpgdice, GAME_CHESS = chess, GAME_CHECKERS = checkers, GAME_NINE_MENS_MORRIS = ninemens, GAME_TIC_TAC_TOE = tictactoe)
/datum/data/pda/app/game_launcher/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
. = ..()
if(.)
return
switch(action)
if(GAME_SWEEPER)
if(params["close"])
if(!voresweeper)
return FALSE
QDEL_NULL(voresweeper)
return TRUE
if(!voresweeper)
voresweeper = new(pda)
voresweeper.tgui_interact(ui.user)
return TRUE
if(GAME_FOUR_ROW)
if(params["close"])
if(!fourrow)
return FALSE
QDEL_NULL(fourrow)
return TRUE
if(!fourrow)
fourrow = new(pda)
fourrow.tgui_interact(ui.user)
return TRUE
if(GAME_SPACE_BATTLE)
if(params["close"])
if(!spacebattle)
return FALSE
QDEL_NULL(spacebattle)
return TRUE
if(!spacebattle)
spacebattle = new(pda)
spacebattle.tgui_interact(ui.user)
return TRUE
if(GAME_RGP_DICE)
if(params["close"])
if(!rpgdice)
return FALSE
QDEL_NULL(rpgdice)
return TRUE
if(!rpgdice)
rpgdice = new(pda)
rpgdice.tgui_interact(ui.user)
return TRUE
if(GAME_CHESS)
if(params["close"])
if(!chess)
return FALSE
QDEL_NULL(chess)
return TRUE
if(!chess)
chess = new(pda)
chess.tgui_interact(ui.user)
return TRUE
if(GAME_CHECKERS)
if(params["close"])
if(!checkers)
return FALSE
QDEL_NULL(checkers)
return TRUE
if(!checkers)
checkers = new(pda)
checkers.tgui_interact(ui.user)
return TRUE
if(GAME_NINE_MENS_MORRIS)
if(params["close"])
if(!ninemens)
return FALSE
QDEL_NULL(ninemens)
return TRUE
if(!ninemens)
ninemens = new(pda)
ninemens.tgui_interact(ui.user)
return TRUE
if(GAME_TIC_TAC_TOE)
if(params["close"])
if(!tictactoe)
return FALSE
QDEL_NULL(tictactoe)
return TRUE
if(!tictactoe)
tictactoe = new(pda)
tictactoe.tgui_interact(ui.user)
return TRUE
return TRUE
/datum/data/pda/app/game_launcher/Destroy()
if(voresweeper)
QDEL_NULL(voresweeper)
if(fourrow)
QDEL_NULL(fourrow)
if(spacebattle)
QDEL_NULL(spacebattle)
if(rpgdice)
QDEL_NULL(rpgdice)
if(chess)
QDEL_NULL(chess)
if(checkers)
QDEL_NULL(checkers)
if(checkers)
QDEL_NULL(ninemens)
if(tictactoe)
QDEL_NULL(tictactoe)
. = ..()
+1 -1
View File
@@ -18,7 +18,7 @@
. = ..()
unnotify()
/datum/data/pda/app/messenger/update_ui(mob/user as mob, list/data)
/datum/data/pda/app/messenger/update_ui(mob/user, list/data)
data["silent"] = notify_silent // does the pda make noise when it receives a message?
data["toff"] = toff // is the messenger function turned off?
data["active_conversation"] = active_conversation // Which conversation are we following right now?
+5 -5
View File
@@ -1,13 +1,13 @@
/datum/data/pda/messenger_plugin
var/datum/data/pda/app/messenger/messenger
/datum/data/pda/messenger_plugin/proc/user_act(mob/user as mob, obj/item/pda/P)
/datum/data/pda/messenger_plugin/proc/user_act(mob/user, obj/item/pda/P)
/datum/data/pda/messenger_plugin/virus
name = "*Send Virus*"
/datum/data/pda/messenger_plugin/virus/user_act(mob/user as mob, obj/item/pda/P)
/datum/data/pda/messenger_plugin/virus/user_act(mob/user, obj/item/pda/P)
var/datum/data/pda/app/messenger/M = P.find_program(/datum/data/pda/app/messenger)
if(M && !M.toff && pda.cartridge.charges > 0)
@@ -19,7 +19,7 @@
/datum/data/pda/messenger_plugin/virus/clown
icon = "star"
/datum/data/pda/messenger_plugin/virus/clown/user_act(mob/user as mob, obj/item/pda/P)
/datum/data/pda/messenger_plugin/virus/clown/user_act(mob/user, obj/item/pda/P)
. = ..(user, P)
if(.)
user.show_message(span_notice("Virus sent!"), 1)
@@ -30,7 +30,7 @@
/datum/data/pda/messenger_plugin/virus/mime
icon = "arrow-circle-down"
/datum/data/pda/messenger_plugin/virus/mime/user_act(mob/user as mob, obj/item/pda/P)
/datum/data/pda/messenger_plugin/virus/mime/user_act(mob/user, obj/item/pda/P)
. = ..(user, P)
if(.)
user.show_message(span_notice("Virus sent!"), 1)
@@ -44,7 +44,7 @@
name = "*Detonate*"
icon = "exclamation-circle"
/datum/data/pda/messenger_plugin/virus/detonate/user_act(mob/user as mob, obj/item/pda/P)
/datum/data/pda/messenger_plugin/virus/detonate/user_act(mob/user, obj/item/pda/P)
. = ..(user, P)
if(.)
var/difficulty = 0
+1 -1
View File
@@ -89,7 +89,7 @@
LAZYADD(serialized_guesses, list(out)) // Wrap it in a list so it stays a list
/datum/data/pda/app/nerdle/update_ui(mob/user as mob, list/data)
/datum/data/pda/app/nerdle/update_ui(mob/user, list/data)
data["guesses"] = serialized_guesses
data["guesses_raw"] = guesses
data["max"] = max_guesses
+6 -5
View File
@@ -47,6 +47,7 @@
new/datum/data/pda/app/manifest,
new/datum/data/pda/app/atmos_scanner,
new/datum/data/pda/app/nerdle,
new/datum/data/pda/app/game_launcher,
new/datum/data/pda/utility/scanmode/notes,
new/datum/data/pda/utility/flashlight)
var/list/shortcut_cache = list()
@@ -177,7 +178,7 @@
/obj/item/pda/GetID()
return id
/obj/item/pda/MouseDrop(obj/over_object as obj, src_location, over_location)
/obj/item/pda/MouseDrop(obj/over_object, src_location, over_location)
var/mob/M = usr
if((!istype(over_object, /atom/movable/screen)) && can_use(usr))
return attack_self(M)
@@ -389,7 +390,7 @@
start_program(find_program(/datum/data/pda/app/main_menu))
/obj/item/pda/proc/id_check(mob/user as mob, choice as num)//To check for IDs; 1 for in-pda use, 2 for out of pda use.
/obj/item/pda/proc/id_check(mob/user, choice)//To check for IDs; 1 for in-pda use, 2 for out of pda use.
if(choice == 1)
if (id)
remove_id()
@@ -411,7 +412,7 @@
return 0
// access to status display signals
/obj/item/pda/attackby(obj/item/C as obj, mob/user)
/obj/item/pda/attackby(obj/item/C, mob/user)
..()
if(istype(C, /obj/item/cartridge) && !cartridge)
cartridge = C
@@ -456,11 +457,11 @@
add_overlay("pda-pen")
return
/obj/item/pda/attack(mob/living/C as mob, mob/living/user as mob)
/obj/item/pda/attack(mob/living/C, mob/living/user)
if (istype(C, /mob/living/carbon) && scanmode)
scanmode.scan_mob(C, user)
/obj/item/pda/afterattack(atom/A as mob|obj|turf|area, mob/user as mob, proximity)
/obj/item/pda/afterattack(atom/A, mob/user, proximity)
if(proximity && scanmode)
scanmode.scan_atom(A, user)
+1 -1
View File
@@ -213,7 +213,7 @@
name = "Civilian Services Department (Relay)"
cartridges_to_send_to = GLOB.civilian_cartridges
/obj/item/pda/clown/Crossed(atom/movable/AM as mob|obj) //Clown PDA is slippery.
/obj/item/pda/clown/Crossed(atom/movable/AM) //Clown PDA is slippery.
if(AM.is_incorporeal())
return
if (isliving(AM))
+7 -7
View File
@@ -44,7 +44,7 @@
base_name = "Med Scanner"
icon = "heart-o"
/datum/data/pda/utility/scanmode/medical/scan_mob(mob/living/C as mob, mob/living/user as mob)
/datum/data/pda/utility/scanmode/medical/scan_mob(mob/living/C, mob/living/user)
C.visible_message(span_warning("[user] has analyzed [C]'s vitals!"))
user.show_message(span_notice("Analyzing Results for [C]:"))
if(C.status_flags & FAKEDEATH)
@@ -79,7 +79,7 @@
base_name = "DNA Scanner"
icon = "link"
/datum/data/pda/utility/scanmode/dna/scan_mob(mob/living/C as mob, mob/living/user as mob)
/datum/data/pda/utility/scanmode/dna/scan_mob(mob/living/C, mob/living/user)
if(ishuman(C))
var/mob/living/carbon/human/H = C
if(!istype(H.dna, /datum/dna))
@@ -88,7 +88,7 @@
to_chat(user, span_notice("[H]'s Fingerprints: [md5(H.dna.uni_identity)]"))
scan_blood(C, user)
/datum/data/pda/utility/scanmode/dna/scan_atom(atom/A as mob|obj|turf|area, mob/user as mob)
/datum/data/pda/utility/scanmode/dna/scan_atom(atom/A, mob/user)
scan_blood(A, user)
/datum/data/pda/utility/scanmode/dna/proc/scan_blood(atom/A, mob/user)
@@ -105,7 +105,7 @@
base_name = "Halogen Counter"
icon = "exclamation-circle"
/datum/data/pda/utility/scanmode/halogen/scan_mob(mob/living/C as mob, mob/living/user as mob)
/datum/data/pda/utility/scanmode/halogen/scan_mob(mob/living/C, mob/living/user)
C.visible_message(span_warning("[user] has analyzed [C]'s radiation levels!"))
user.show_message(span_notice("Analyzing Results for [C]:"))
@@ -118,7 +118,7 @@
base_name = "Reagent Scanner"
icon = "flask"
/datum/data/pda/utility/scanmode/reagent/scan_atom(atom/A as mob|obj|turf|area, mob/user as mob)
/datum/data/pda/utility/scanmode/reagent/scan_atom(atom/A, mob/user)
if(!isnull(A.reagents))
if(A.reagents.reagent_list.len > 0)
var/reagents_length = A.reagents.reagent_list.len
@@ -134,7 +134,7 @@
base_name = "Gas Scanner"
icon = "tachometer-alt"
/datum/data/pda/utility/scanmode/gas/scan_atom(atom/A as mob|obj|turf|area, mob/user as mob)
/datum/data/pda/utility/scanmode/gas/scan_atom(atom/A, mob/user)
pda.analyze_gases(A, user)
/datum/data/pda/utility/scanmode/notes
@@ -146,7 +146,7 @@
. = ..()
notes = pda.find_program(/datum/data/pda/app/notekeeper)
/datum/data/pda/utility/scanmode/notes/scan_atom(atom/A as mob|obj|turf|area, mob/user as mob)
/datum/data/pda/utility/scanmode/notes/scan_atom(atom/A, mob/user)
if(notes && istype(A, /obj/item/paper))
var/obj/item/paper/P = A
var/list/brlist = list("p", "/p", "br", "hr", "h1", "h2", "h3", "h4", "/h1", "/h2", "/h3", "/h4")
+26
View File
@@ -0,0 +1,26 @@
/**
* tgui state: board_game_state
*
* Checks that the default living handling or if the user or the object are inside a belly
**/
GLOBAL_DATUM_INIT(tgui_board_game_state, /datum/tgui_state/board_game_state, new)
/datum/tgui_state/board_game_state/can_use_topic(atom/src_object, mob/user)
if(!isliving(user))
return STATUS_UPDATE
var/mob/living/living_user = user
if(isbelly(living_user.loc) || isbelly(src_object.loc))
return living_user.board_game_can_use_tgui_topic(src_object)
return living_user.default_can_use_tgui_topic(src_object)
/mob/proc/board_game_can_use_tgui_topic(atom/src_object)
return STATUS_CLOSE
/mob/living/board_game_can_use_tgui_topic(atom/src_object)
if(is_incorporeal())
return STATUS_CLOSE
var/dist = get_dist(get_turf(src_object), get_turf(src))
if(dist <= 1)
return STATUS_INTERACTIVE
return STATUS_CLOSE