summaryrefslogtreecommitdiff
path: root/scripts/Board.gd
diff options
context:
space:
mode:
authorAnson Bridges <bridges.anson@gmail.com>2025-08-19 12:38:02 -0700
committerAnson Bridges <bridges.anson@gmail.com>2025-08-19 12:38:02 -0700
commit255fbf19cc9499ef384d41f68515da5e49e8a3ce (patch)
tree13c838229198383b24644f613787e34842ea7ab2 /scripts/Board.gd
parentf087c6a98b1da55525a6e3c1d7c82477f82eb5cd (diff)
added menus, reworking GC client architecture
Diffstat (limited to 'scripts/Board.gd')
-rw-r--r--scripts/Board.gd213
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