extends Node2D onready var Grid = get_node("Grid") onready var GridHighlight = get_node("GridHighlight") onready var Editor = get_node("../Editor") onready var Islands = get_node("Islands") onready var DigSites = get_node("DigSites") onready var EditIslandButton = get_node("UI/DebugContainer/EditIslandButton") onready var WorldCamera = get_node("Camera") onready var OffsetValueLabel = get_node("UI/DebugContainer/OffsetValue") onready var ZoomValueLabel = get_node("UI/DebugContainer/ZoomValue") onready var HexCoordValueLabel = get_node("UI/DebugContainer/HexCoordValue") onready var WorldCoordValueLabel = get_node("UI/DebugContainer/WorldCoordValue") onready var ScreenCoordValueLabel = get_node("UI/DebugContainer/ScreenCoordValue") onready var TileTypeValueLabel = get_node("UI/DebugContainer/TileTypeValue") onready var RepeatButton = get_node("UI/HBoxContainer/RepeatButton") onready var SuccessMessage = get_node("UI/SuccessMessage") onready var PlayerChar = get_node("PlayerChar") onready var PlayerBoat = get_node("PlayerBoat") onready var FPSValueLabel = get_node("UI/DebugContainer/FPSValue") onready var IslandMap = get_node("UI/IslandMap") onready var IslandMapRenderer = get_node("../IslandMapRenderer") onready var MapButton = get_node("UI/ActionButtons/MapButton") onready var BirdyButton = get_node("UI/ActionButtons/BirdyButton") onready var DigButton = get_node("UI/ActionButtons/DigButton") onready var CoinScoreLabel = get_node("UI/GameScoreHud/CoinScoreLabel") onready var BirdyTimer = get_node("Birdy/Timer") onready var MapTimer = get_node("UI/IslandMap/Timer") var Island = preload("Island.gd") var SpringDamper = preload("res://SpringDamper.gd") var CoinSpawner = preload("res://scenes/CoinSpawner.tscn").instance() var DigSiteSprite = preload("res://assets/digsite.svg") var DigSiteTreasureSprite = preload("res://assets/treasuredigsite.svg") var hex_grid_bbox = [[0,0], [10,10]] var hex_hover = Vector2.ZERO var is_dragging = false var drag_start = null var target = Vector2() var tile_data = {} var current_island = null var anchor_tile = null var landing_tile = null var player_navigation_path = [] var player_path_plan_start = null var player_path_plan_end = null var hex_line_path = [] var treasure_island = null var treasure_map_rendered = false var bird_flying = false var birdy_spring = null var birdy_spring_x = Vector2.ONE var birdy_spring_v = Vector2.ZERO var birdy_spring_xt = Vector2.ONE * Globals.zoom_sailing var birdy_duration = 4.0 var map_duration = 4.0 signal digging_started signal world_generation_triggered signal wrong_digsite signal treasure_found signal bird_flight_start signal bird_flight_end signal map_opened signal map_closed signal level_started # # Godot Functions # func _ready(): Grid.view_camera = WorldCamera GridHighlight.view_camera = WorldCamera birdy_spring = SpringDamper.new(2, 0.99, 0.5) generate() # Set player starting position PlayerChar.position = Globals.HexGrid.get_hex_center(Vector2(0,0)) PlayerChar.connect("dig_stopped", self, "on_dig_stopped") self.connect("treasure_found", self, "on_treasure_found") self.connect("bird_flight_start", self, "on_bird_flight_started") self.connect("bird_flight_end", self, "on_bird_flight_ended") self.connect("map_opened", self, "on_map_opened") self.connect("map_closed", self, "on_map_closed") # We're starting on the water DigButton.disabled = true func _process(delta): if is_editor_active(): WorldCamera.offset = PlayerChar.position WorldCamera.zoom = birdy_spring_x if len(player_navigation_path) > 1: var player_coord = Globals.WorldToHexCenter(PlayerChar.transform.origin) if (player_coord - player_navigation_path[0]).length_squared() < 0.1: player_navigation_path.remove(0) if len(player_navigation_path) > 0: PlayerChar.target = player_navigation_path[0] update_current_island() if current_island: PlayerBoat.transform.origin = Globals.HexToWorld(anchor_tile) else: PlayerBoat.transform.origin = PlayerChar.transform.origin var res = birdy_spring.calc(birdy_spring_x, birdy_spring_v, birdy_spring_xt, delta) birdy_spring_x = res[0] birdy_spring_v = res[1] if BirdyTimer.time_left == 0: birdy_spring_xt = Vector2.ONE * Globals.zoom_sailing if birdy_spring_x.x > Globals.zoom_sailing * 1.2: if bird_flying == false: bird_flying = true emit_signal("bird_flight_start") elif birdy_spring_x.x < Globals.zoom_sailing * 1.1: if bird_flying == true: bird_flying = false emit_signal("bird_flight_end") if MapTimer.time_left == 0: emit_signal("map_closed") func draw_hex_path (path: Array, color: Color): var path_len = len(path) if path_len > 0: var last_point = path[0] draw_circle(last_point, 5, color) for i in range (1, path_len): var cur_point = path[i] draw_line (last_point, cur_point, color) draw_circle(cur_point, 5, color) last_point = cur_point func _draw(): if Globals.debug_nav: draw_hex_path (hex_line_path, "#00f2f2") draw_hex_path (player_navigation_path, "#f200f2") if player_path_plan_start != null and player_path_plan_end != null: draw_circle (player_path_plan_start, 12, "#2288f2") draw_circle (player_path_plan_end, 12, "#2288f2") var obstacles = [] if current_island != null: obstacles = Globals.IslandNavGrid.get_obstacles() else: obstacles = Globals.OceanNavGrid.get_obstacles() for coords in obstacles: draw_set_transform(Globals.HexToWorld(coords), 0, Vector2.ONE) draw_polygon(HexTileDrawer.HexPoints, HexTileDrawer.create_color_array("#929")) # # World Modification/Query # func clear_islands(): for island in Islands.get_children(): Islands.remove_child(island) island.queue_free() func clear_digsites(): for digsite in DigSites.get_children(): DigSites.remove_child(digsite) digsite.queue_free() func get_tile_type(world_coord: Vector2): for island in Islands.get_children(): var tile = island.get_tile_by_world_coord(world_coord) if tile != null: return tile return null func add_island_at(file_name, offset_world: Vector2): var island = Island.new() island.load_island(file_name) island.set_offset_world(offset_world) Islands.add_child(island) func is_editor_active(): return Editor == null or not Editor.is_active() func check_player_on_treasure(): if current_island == null: return false return current_island.is_point_on_treasure_site(Globals.HexToWorld(PlayerChar.cur_tile)) func check_island_location_valid(new_island): var grid_origin_world_coord = Globals.HexToWorld(Vector2(0,0)) if new_island.get_tile_by_world_coord(grid_origin_world_coord) != null: return false var islands = Islands.get_children() for island in islands: if island.check_overlap(new_island): return false return true func place_treasure(): assert (treasure_island != null) var island_tile_coords = treasure_island.tiles.keys() var grass_tiles = [] for coord in island_tile_coords: if treasure_island.tiles[coord] == "Grass": grass_tiles.append(coord) var treasure_tile_index = randi() % len(grass_tiles) treasure_island.treasure_local_coords = grass_tiles[treasure_tile_index] print ("treasure_tile_index: ", treasure_tile_index, " num tiles: ", len(grass_tiles)) if Globals.debug_nav: treasure_island.highlight_treasure = true treasure_island.update() func render_treasure_map(): IslandMapRenderer.render_target_update_mode = Viewport.UPDATE_ONCE IslandMapRenderer.render_target_clear_mode = Viewport.CLEAR_MODE_ONLY_NEXT_FRAME var camera = IslandMapRenderer.get_node("Camera2D") camera.current = true camera.offset = treasure_island.center_world_coord var island = Island.new() island.tiles = treasure_island.tiles.duplicate() island.treasure_local_coords = treasure_island.treasure_local_coords island.highlight_treasure = true island.name = "island" camera.zoom = Vector2.ONE * (treasure_island.radius_world / 100.0 + 3) for child in IslandMapRenderer.get_children(): if child.name == "island": print ("removing ", child) IslandMapRenderer.remove_child(child) child.queue_free() break IslandMapRenderer.add_child(island) IslandMap.texture = IslandMapRenderer.get_texture() func reset(): PlayerChar.transform.origin = Vector2.ZERO PlayerChar.position = Vector2.ZERO PlayerChar.target = Vector2.ZERO hex_line_path = [] player_navigation_path = [] player_path_plan_start = null player_path_plan_end = null current_island = null treasure_island = null clear_islands() clear_digsites() SuccessMessage.visible = false CoinScoreLabel.text = "0" func generate(): reset() var rng = RandomNumberGenerator.new() if Globals.game_fixed_seed != 0: rng.set_seed(0) rng.randomize() randomize() var radius = 800 var num_islands = Globals.game_num_islands var island_files = [] for i in range (10): island_files.append("res://islands/pirate_game_island_" + str(i) + ".island") island_files.shuffle() for i in range (num_islands): var island = Island.new() island.generate() var rand_coord = Vector2(rng.randi_range(-radius, radius), rng.randi_range(-radius, radius)) island.set_offset_world(Globals.WorldToHexCenter(rand_coord)) var location_valid = check_island_location_valid(island) var overlap_retry_num = 0 var overlap_retry_max = 10 while !location_valid and overlap_retry_num < overlap_retry_max: if overlap_retry_num % 4 == 0: radius = radius + 200 overlap_retry_num = overlap_retry_num + 1 rand_coord = Vector2(rng.randi_range(-radius, radius), rng.randi_range(-radius, radius)) island.set_offset_world(Globals.WorldToHexCenter(rand_coord)) location_valid = check_island_location_valid(island) if !location_valid: print ("Could not place island! steps: " + str(overlap_retry_num)) else: print ("Placed after " + str(overlap_retry_num) + " retries.") # prerender_island(island) Islands.add_child(island) num_islands = Islands.get_child_count() treasure_island = Islands.get_child(rng.randi() % num_islands) place_treasure() render_treasure_map() populate_ocean_nav_grid() emit_signal("level_started") # # Navigation # func populate_ocean_nav_grid(): var obstacles = Globals.OceanNavGrid.get_obstacles() Globals.OceanNavGrid.remove_obstacles(obstacles.keys()) Globals.OceanNavGrid.set_bounds(Vector2.ONE * -500, Vector2.ONE * 500) for island in Islands.get_children(): for tile in island.tiles.keys(): var grid_coords = Globals.WorldToHex(tile + island.offset_world) Globals.OceanNavGrid.add_obstacles(grid_coords, 0) func populate_island_nav_grid(): var obstacles = Globals.IslandNavGrid.get_obstacles() Globals.IslandNavGrid.remove_obstacles(obstacles.keys()) Globals.IslandNavGrid.set_bounds(Vector2.ONE * -500, Vector2.ONE * 500) if current_island == null: print ("Error: cannot populate island nav grid: no island") return var landing_site_coords = Globals.WorldToHex(current_island.landing_site_world) for tile in current_island.obstacles_local_coords.keys(): var grid_coords = Globals.WorldToHex(tile + current_island.offset_world) # Allow navigation to the anchor tile if (grid_coords - anchor_tile).length() < 0.1: continue Globals.IslandNavGrid.add_obstacles(grid_coords, 0) func update_current_island(): var islands = Islands.get_children() var last_current_island = current_island current_island = null for island in islands: if island.get_tile_by_world_coord(PlayerChar.position) != null: current_island = island break if last_current_island != current_island: if last_current_island != null: on_leave_island(last_current_island) if current_island != null: on_enter_island(current_island) func on_enter_island(island): print ("Entering island") PlayerChar.on_enter_island() current_island = island anchor_tile = PlayerChar.prev_tile landing_tile = PlayerChar.cur_tile island.landing_site_world = Globals.WorldToHexCenter(PlayerChar.position) island.landing_site_local_coord = island.get_local_coord_by_world_coord(PlayerChar.position) island.is_active = true populate_island_nav_grid() island.update() DigButton.disabled = false if Globals.debug_nav: update() func on_leave_island(island): print ("Leaving island") PlayerChar.on_leave_island() island.is_active = false island.landing_site_local_coord = null island.update() DigButton.disabled = true if Globals.debug_nav: update() func on_dig_stopped(): print ("Dig stopped!") var dig_site = Sprite.new() dig_site.transform.origin = Globals.HexToWorld(PlayerChar.cur_tile) + Vector2(0, 32.0) if check_player_on_treasure(): emit_signal("treasure_found") var coins = CoinSpawner.create_coins(20, dig_site.transform.origin) for coin in coins: coin.z_index = PlayerChar.z_index + 1 add_child(coin) dig_site.texture = DigSiteTreasureSprite dig_site.z_index = PlayerChar.z_index + 2 else: emit_signal("wrong_digsite") dig_site.texture = DigSiteSprite DigSites.add_child(dig_site) func on_treasure_opened(): pass func on_treasure_found(tile): RepeatButton.disabled = false pass func on_map_opened(): BirdyButton.disabled = true IslandMap.visible = true MapTimer.one_shot = true MapTimer.start(map_duration) func on_map_closed(): BirdyButton.disabled = false IslandMap.visible = false func on_bird_flight_started(): print ("flight started") MapButton.disabled = true func on_bird_flight_ended(): print ("flight ended") MapButton.disabled = false func check_player_near_anchor(): if current_island == null: return false var anchor_world = Globals.HexToWorld(anchor_tile) return (PlayerChar.position - anchor_world).length() < Globals.hex_size func update_navigation_target_ocean(start_world: Vector2, target_world: Vector2): var start_coord = Globals.WorldToHex(start_world) var goal_coord = Globals.WorldToHex(target_world) var island_landing_site_world = null player_path_plan_start = null player_path_plan_end = null var direct_path = Globals.WorldLineToHexTiles(start_world, target_world) if get_tile_type(start_world) != null and current_island != null and len(direct_path) > 1: # print ("on landing site: ", current_island.is_point_on_landing_site (start_world)) if current_island.is_point_on_landing_site (start_world): if get_tile_type(direct_path[1]) == null: # print ("starting from landing site") direct_path.pop_front() start_coord = Globals.WorldToHex(direct_path.front()) else: print ("Invalid start") return # In case target is on an island we find both a landing site and # the first point on the ocean that we can reach. if get_tile_type(target_world) != null: var last_removed = null while len(direct_path) > 0 and get_tile_type(direct_path.back()) != null: last_removed = direct_path.back() direct_path.pop_back() if len(direct_path) == 0: print ("Could not find path!") return # print ("Using ", Globals.WorldToHex(direct_path.back()), " instead of ", goal_coord, " as goal.") goal_coord = Globals.WorldToHex(direct_path.back()) island_landing_site_world = last_removed player_path_plan_start = Globals.HexToWorld(start_coord) player_path_plan_end = Globals.HexToWorld(goal_coord) var path = Globals.OceanNavGrid.find_path(start_coord, goal_coord) for target in path.slice(0,-1): var target_world_coord = Globals.HexToWorld(target.axial_coords) var target_type = get_tile_type(target_world_coord) player_navigation_path.append(target_world_coord) if target_type == "Sand": break if island_landing_site_world != null: player_navigation_path.append(island_landing_site_world) if len(player_navigation_path) > 0: PlayerChar.target = player_navigation_path[0] func update_navigation_target_island(start_world: Vector2, target_world: Vector2): var start_coord = Globals.WorldToHex(start_world) var goal_coord = Globals.WorldToHex(target_world) var path = Globals.IslandNavGrid.find_path(start_coord, goal_coord) for target in path.slice(0,-1): var target_world_coord = Globals.HexToWorld(target.axial_coords) var target_type = get_tile_type(target_world_coord) player_navigation_path.append(target_world_coord) func update_player_navigation_target(mouse_pos: Vector2): var target_tile = Globals.HexGrid.get_hex_center(Globals.ScreenToHex(mouse_pos, WorldCamera)) var target_world = Globals.ScreenToWorld(mouse_pos, WorldCamera) var start_world = PlayerChar.transform.origin player_navigation_path = [] var start_timestamp = OS.get_system_time_msecs() var player_near_anchor = check_player_near_anchor() if current_island != null: update_navigation_target_island(start_world, target_tile) if current_island.get_tile_by_world_coord(target_tile) != null: player_navigation_path.append(target_world) if len(player_navigation_path) == 0 and player_near_anchor: start_world = Globals.HexToWorld(anchor_tile) if current_island == null or (len(player_navigation_path) == 0 and player_near_anchor): update_navigation_target_ocean(start_world, target_tile) player_navigation_path.append(target_world) var planning_duration_msec = OS.get_system_time_msecs() - start_timestamp if Globals.debug_nav: update() # # Input & Events # func handle_game_event(event): if Editor and Editor.is_active(): return false if bird_flying: return false if event is InputEventMouseButton: # var input_tile = Globals.HexGrid.get_hex_center(Globals.ScreenToHex(mouse_pos, WorldCamera)) # Move main character if event.pressed and event.button_index == BUTTON_LEFT: update_player_navigation_target (get_global_mouse_position()) return false func update_hex_line_path(target: Vector2): var start = PlayerChar.position hex_line_path = Globals.WorldLineToHexTiles(start, target) func _unhandled_input(event): if event is InputEventMouseButton: if handle_game_event(event): return # Move camera if event.pressed and event.button_index == 2: is_dragging = true drag_start = (WorldCamera.offset / WorldCamera.zoom.x + event.position) else: is_dragging = false # Zoom Camera if event.pressed and event.button_index == BUTTON_WHEEL_DOWN and event.pressed and WorldCamera.zoom.y < 5.5: WorldCamera.zoom = WorldCamera.zoom * 1.0 / 0.8 elif event.button_index == BUTTON_WHEEL_UP and event.pressed: WorldCamera.zoom = WorldCamera.zoom * 0.8 if 'position' in event: hex_hover = Globals.ScreenToHex(get_global_mouse_position(), WorldCamera) GridHighlight.pos = hex_hover HexCoordValueLabel.text = str(hex_hover) var world_coord = Globals.ScreenToWorld(get_global_mouse_position(), WorldCamera) var tile_type = get_tile_type(world_coord) if tile_type != null: TileTypeValueLabel.text = tile_type else: TileTypeValueLabel.text = "None" WorldCoordValueLabel.text = str(world_coord) ScreenCoordValueLabel.text = str(event.position) update_hex_line_path(world_coord) if is_dragging: WorldCamera.offset = (drag_start - event.position) * WorldCamera.zoom.x OffsetValueLabel.text = str(WorldCamera.offset) ZoomValueLabel.text = str(WorldCamera.zoom) func _on_MapButton_pressed(): if IslandMap.visible: emit_signal("map_closed") else: emit_signal("map_opened") func _on_BirdyButton_pressed(): if birdy_spring_xt == Vector2.ONE * Globals.zoom_sailing: birdy_spring_xt = Vector2.ONE * Globals.zoom_birdy BirdyTimer.one_shot = true BirdyTimer.start(birdy_duration) else: BirdyTimer.stop() birdy_spring_xt = Vector2.ONE * Globals.zoom_sailing func _on_DigButton_pressed(): print ("dig pressed") if PlayerChar.state == PlayerChar.State.Walking: emit_signal("digging_started") PlayerChar.on_dig_start() func _on_IslandMap_visibility_changed(): if IslandMap.visible: emit_signal("map_opened") else: emit_signal("map_closed") func _on_GenerateButton_pressed(): emit_signal("world_generation_triggered") RepeatButton.disabled = true generate() func _on_BackButton_pressed(): get_tree().change_scene("res://Menu.tscn") func _on_PlayerChar_coin_collected(): CoinScoreLabel.text = str(int (CoinScoreLabel.text) + 1)