diff options
| author | Anson Bridges <bridges.anson@gmail.com> | 2025-08-19 12:38:02 -0700 |
|---|---|---|
| committer | Anson Bridges <bridges.anson@gmail.com> | 2025-08-19 12:38:02 -0700 |
| commit | 255fbf19cc9499ef384d41f68515da5e49e8a3ce (patch) | |
| tree | 13c838229198383b24644f613787e34842ea7ab2 /scripts/Board.gd | |
| parent | f087c6a98b1da55525a6e3c1d7c82477f82eb5cd (diff) | |
added menus, reworking GC client architecture
Diffstat (limited to 'scripts/Board.gd')
| -rw-r--r-- | scripts/Board.gd | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/scripts/Board.gd b/scripts/Board.gd new file mode 100644 index 0000000..f18ca74 --- /dev/null +++ b/scripts/Board.gd @@ -0,0 +1,213 @@ +extends Spatial + +enum { Y, X } + +# 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: Array = [] # 2D Array of JSON objects describing the board, which can be turned into objects +var board_display: Array = [] +var available_board_coords: Array = [] # for population purposes +var airports = {} # id : HexSpace of cell_type airport + +var side_len: int + + +# 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) ] +enum { NUMBER, COLOR } + +onready var hex_space = preload("res://objects/HexSpace.tscn") + +# cell types +enum { PLAIN, HILLS, MOUNTAINS, AIRPORT } + +# 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: Array= [ [0, 1, 2, 3, 4, 5], [0,1,3,4], [0,3] ] + + +func _ready(): + pass + +func reset_board(): + for node in get_children(): + node.queue_free() + board.clear() + board_display.clear() + available_board_coords.clear() + +func create_board_base(hex_side_length : int): + side_len = hex_side_length + var number_of_cells = 3*( pow(hex_side_length, 2) - hex_side_length) + 1 + + reset_board() + + 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 + + var offset : int = 0 + if r > (hex_side_length - 1): offset = r - (hex_side_length - 1) + for i in range(row_length): + row[offset+i] = { "cell_type" : PLAIN, "pos" : [r, offset+i] } # ground cell + available_board_coords.push_back( [r, offset+i] ) + + board.append(row) + + +func display_board(): + 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_display = [] + row_display.resize(board_diam) + row_display.fill(null) + 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)) + new_cell.set_up(row[c]) + add_child(new_cell) + row_display[c] = new_cell + board_display.push_back(row_display) + + +# populate board with airports, hills, and mountains +# depending on game settings +func populate_board(num_mountains : int, num_hills : int, num_airports : int, runway_count : int, use_names : bool = false) -> bool: + var board_diam:int = len(board) + + for _m in range(num_mountains): + if len(available_board_coords) < 1: return false + var spot_i:int = randi() % len(available_board_coords) + var spot = available_board_coords[ spot_i ] + var args = {"cell_type" : MOUNTAINS, "orientation" : randi() % 6, "pos" : [spot[Y], spot[X]]} + board[spot[Y]][spot[X]] = args + available_board_coords.pop_at(spot_i) + + for _h in range(num_hills): + if len(available_board_coords) < 1: return false + var spot_i:int = randi() % len(available_board_coords) + var spot = available_board_coords[ spot_i ] + var args = { "cell_type" : HILLS, "orientation" : randi() % 6, "pos" : [spot[Y], spot[X]] } + board[spot[Y]][spot[X]] = args + available_board_coords.pop_at(spot_i) + + # airport identification + var used_airports : Array = [] + + var airport_id:int = 0 + for a in range(num_airports): + var airport_display + if use_names: + airport_display = Globals.get_random_airport_name(used_airports) + else: + airport_display = [ randi() % 9 + 1, randi() % 4 ] # number, color + while airport_display in used_airports: + airport_display = [ randi() % 9 + 1, randi() % 4 ] + # 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 = [] + var runways = (randi() % 3 + 1) if (runway_count == 0) else runway_count + 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[Y] + spot_c = spot[X] + + var has_adjacent_airport = false + for offset in adjacent_offsets: # away from other airports + var new_r: int = spot_r + offset[Y] + var new_c: int = spot_c + offset[X] + 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["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[runways]: + 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]["cell_type"] in [HILLS, MOUNTAINS]: 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: + return false # could not form valid map + + var args = {"cell_type" : AIRPORT , "pos" : [spot_r, spot_c], "orientation" : rot, "airport_id" : airport_id, "runways" : runways, 'valid_approach_offsets' : valid_approaches, "use_names" : use_names} + if use_names: + args["airport_name"] = airport_display + else: + args["airport_color"] = airport_colors[airport_display[COLOR]] + args["airport_number"] = airport_display[NUMBER] + board[spot_r][spot_c] = args + available_board_coords.pop_at(spot_i) + airport_id += 1 + return true + +func get_json(): + return board + +func generate_board(hex_side_len: int, num_mountains : int, num_hills : int, num_airports : int, runway_count : int, use_names : bool = false) -> bool: + create_board_base(hex_side_len) + if not populate_board(num_mountains, num_hills, num_airports, runway_count, use_names): + reset_board() + print("Invalid board creation parameters") + return false + display_board() + return true |
