From d558a9add0e183219a7a9ff482807bdcd677e21a Mon Sep 17 00:00:00 2001 From: Anson Bridges Date: Mon, 11 Aug 2025 22:42:00 -0700 Subject: Initialize repo from local files --- scripts/GameTable.gd | 207 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 scripts/GameTable.gd (limited to 'scripts/GameTable.gd') diff --git a/scripts/GameTable.gd b/scripts/GameTable.gd new file mode 100644 index 0000000..cbee40f --- /dev/null +++ b/scripts/GameTable.gd @@ -0,0 +1,207 @@ +tool +extends Spatial + +const num_mountains = {"easy" : 0, "medium" : 3, "hard" : 6} +const num_hills = {"easy" : 4, "medium" : 6, "hard" : 8} + +export var hex_side_length = 6 setget set_hex_side_len +export var airports_per_color = 6 setget set_airports_per_color +export var num_airport_colors = 3 setget set_num_airport_colors +export var _generate_board_editor: bool = false setget generate_board_editor + +export (String, "easy", "medium", "hard") var game_difficulty = "easy" + +# hex board represented in square-grid form like so (e.g., 3-length-side hex grid): +# x x x +# x x x x +# x x x x x +# x x x x +# x x x +# going up and to the right is done by decreasing the row by 1 +# going up and to the left is done by decreasing the row by 1 and the column by 1 +var board = [] +var available_board_coords = [] +enum { GROUND_LAYER, WEATHER_LAYER, PLANES_LAYER } + +# Y R B G +var airport_colors = [ Color(1, 1, 0), Color(1, 0, 0), Color(0.3, 0.3, 1), Color(0, 0.8, 0) ] +var airports = {} # id : HexSpace of cell_type airport + +onready var hex_space = preload("res://objects/HexSpace.tscn") + +# directions: E, NE, NW, W, SW, SE +const adjacent_offsets = [ [0,1] , [-1, 0], [-1, -1], [0, -1], [1, 0], [1, 1] ] + +# indices of the offsets that are valid cells to approach from +const approaches_i = {"easy": [0, 1, 2, 3, 4, 5], "medium" : [0,1,3,4], "hard" : [0,3]} + + +func _ready(): + if not Engine.editor_hint: + generate_hex_board() + generate_board_cells() + populate_board() + +func set_hex_side_len(side_length): + hex_side_length = side_length + +func set_airports_per_color(num_airports): + airports_per_color = num_airports + +func set_num_airport_colors(num_colors): + num_airport_colors = num_colors + +func generate_hex_board(): + var number_of_cells = 3*( pow(hex_side_length, 2) - hex_side_length) + 1 + var player_spaces = number_of_cells - 1 # center should always be a mountain + for node in $Board.get_children(): + $Board.remove_child(node) + board = [] # reset board + contents + available_board_coords = [] + var board_diameter = hex_side_length * 2 - 1 + for r in range(board_diameter): + var row_length: int = board_diameter - abs(r-(hex_side_length-1)) + + var row = [] + row.resize(board_diameter) + row.fill(null) # not in hex grid + + if r <= (hex_side_length - 1): + for i in range(row_length): + row[i] = [ 1, [], [] ] # ground cell, weather effects, planes + else: + for i in range(row_length): + row[board_diameter-1-i] = [ 1, [], [] ] # ground cell, weather effects, planes + + board.append(row) + + +func generate_board_cells(): + var cell_size_x = 1 # distance between center of two adjacent hex cells + var row_offset_y:float = cos(deg2rad(30)) * cell_size_x + var board_diam:int = len(board) + var side_len:int = ( board_diam + 1 ) / 2 + + for r in range(board_diam): + var row = board[r] + var z = row_offset_y * (r - board_diam/2) + var offset_x = abs(side_len - (r+1)) * (cell_size_x / 2.0) if (r+1) <= side_len else -1*abs(side_len - (r+1)) * (cell_size_x/2.0) + offset_x -= board_diam/2 * cell_size_x + for c in range(board_diam): + if row[c] == null: continue + var x = offset_x + c * cell_size_x + + var new_cell = hex_space.instance() + new_cell.call_deferred("set", "global_position", Vector3(x, randf()/15, z)) + $Board.add_child(new_cell) + + board[r][c][GROUND_LAYER] = new_cell + if (r == c) and (r == (board_diam/2)): # central cell always a mountain + var cell_type = "mountain" + var args = {} + args["rotation"] = randi() % 6 + new_cell.set_up(cell_type, args) + else: + available_board_coords.push_back( [r, c] ) + +# populate board with airports, hills, and mountains +# depending on game settings +func populate_board(): + var board_diam:int = len(board) + + for _m in range(num_mountains[game_difficulty]): + if len(available_board_coords) < 1: return null + var spot_i:int = randi() % len(available_board_coords) + var spot = available_board_coords[ spot_i ] + var args = {"rotation" : randi() % 6} + board[spot[0]][spot[1]][GROUND_LAYER].set_up("mountain", args) + available_board_coords.pop_at(spot_i) + + for _h in range(num_hills[game_difficulty]): + if len(available_board_coords) < 1: return null + var spot_i:int = randi() % len(available_board_coords) + var spot = available_board_coords[ spot_i ] + var args = {"rotation" : randi() % 6} + board[spot[0]][spot[1]][GROUND_LAYER].set_up("hills", args) + available_board_coords.pop_at(spot_i) + + var airport_id:int = 0 + for c in range(num_airport_colors): + for a in range(airports_per_color): + # find valid spot + var spot_okay:bool = false + var rot:int + var spot_r:int + var spot_c:int + var spot_i:int + var valid_approaches = [] + while (not spot_okay) and (len(available_board_coords) > 0): + spot_i = randi() % len(available_board_coords) + var spot = available_board_coords[ spot_i ] + spot_r = spot[0] + spot_c = spot[1] + + # should no longer be necessary + #if board[spot_r][spot_c] == null: continue + + var has_adjacent_airport = false + for offset in adjacent_offsets: # away from other airports + var new_r: int = spot_r + offset[0] + var new_c: int = spot_c + offset[1] + if new_r < 0 or new_c < 0 or new_r >= board_diam or new_c >= board_diam: # offset out of square grid + continue + var adjacent_cell = board[new_r][new_c] + if adjacent_cell != null and adjacent_cell[GROUND_LAYER].cell_type == "airport": + has_adjacent_airport = true + break + if has_adjacent_airport: + available_board_coords.pop_at(spot_i) + continue + + spot_okay = true + + # find rotation that leaves at least 1 runway open + rot = randi() % 3 + var rot_okay = false + for _i in range(3): + var rot_approaches = adjacent_offsets.slice(rot, 5) + if rot != 0: rot_approaches += adjacent_offsets.slice(0, rot - 1) + + var possible_approaches = [] + for approach_index in approaches_i[game_difficulty]: + possible_approaches.push_back(rot_approaches[approach_index]) + + var has_runway = false + for approach in possible_approaches: + var app_r: int = spot_r + approach[0] + var app_c: int = spot_c + approach[1] + if app_r < 0 or app_r >= board_diam or app_c < 0 or app_c >= board_diam: continue # out of square map + if board[app_r][app_c] == null: continue # out of hex map + if board[app_r][app_c][GROUND_LAYER].cell_type in ["hills", "mountain"]: continue # invalid approach square + has_runway = true + valid_approaches.push_back(approach) + + if has_runway: + rot_okay = true + break + else: + rot += 1 # rotate 60 deg (effectively) + if not rot_okay: + available_board_coords.pop_at(spot_i) + continue + + if not spot_okay: + print('couldnt find spot') + return null # could not form valid map + #print(c, " ", a, "(", spot_r, ", ", spot_c, ")") + var args = {"rotation" : rot, "airport_color" : airport_colors[c], "airport_number" : a+1, "airport_id" : airport_id, "difficulty" : game_difficulty, 'valid_approaches' : valid_approaches} + board[spot_r][spot_c][GROUND_LAYER].set_up("airport", args) + available_board_coords.pop_at(spot_i) + airport_id += 1 + + + +func generate_board_editor(_gbe): + generate_hex_board() + generate_board_cells() + populate_board() -- cgit v1.2.3