@tool extends TileTransform class_name Building var triangle_points = PackedVector2Array([ Vector2(0, -20) * 0.85 + Vector2.DOWN * 3, Vector2(-20, 15) * 0.85 + Vector2.DOWN * 3, Vector2(20, 15) * 0.85 + Vector2.DOWN * 3, Vector2(0, -20) * 0.85 + Vector2.DOWN * 3, ]) var history: Array[BuildingData] = [] var data: BuildingData = null var upgrade_timer: int = 0 const max_upgrade_timer: int = 10 func attempt_upgrade(new_data: BuildingData) -> bool: var old_data = data for resource_requirement in new_data.resource_requirements: var resource = resource_requirement.resource var required = resource_requirement.amount var current = ResourceController.get_resource_value(resource) if current < required: return false for field_requirement in new_data.field_requirements: if !field_requirement.is_satisfied_at_position(self.grid, self.tile_pos): return false for resource_requirement in new_data.resource_requirements: var resource = resource_requirement.resource var required = resource_requirement.amount ResourceController.consume_resource(resource, required) grid.unregister_building(self) for storage in data.resource_stockpiles: ResourceController.remove_storage(storage) data = new_data grid.register_building(self) for storage in data.resource_stockpiles: ResourceController.add_storage(storage) queue_redraw() history.push_front(old_data) return true func attempt_upgrades() -> bool: if randf() > 0.1: return false for upgrade_path in data.upgrade_paths: if attempt_upgrade(upgrade_path): return true return false func _init(_tile_pos: Vector2i, _size: Vector2i, building_data: BuildingData): self.data = building_data self.tile_pos = _tile_pos self.size = _size func _ready(): super._ready() grid.register_building(self) for storage in data.resource_stockpiles: ResourceController.add_storage(storage) ResourceController.upgrade.connect(_upgrade_downgrade) ResourceController.produce.connect(_resource_produce) ResourceController.consume.connect(_resource_consume) func _downgrade_or_die(): while history.size() > 0: var downgrade_data = history.pop_front() if attempt_upgrade(downgrade_data): history.pop_front() return queue_free() func _upgrade_downgrade(): attempt_upgrades() if death_timer >= max_death: _downgrade_or_die() var death_timer = 0 var max_death = 5 func _resource_produce(): for resource_data in data.resource_prouction: ResourceController.add_resource(resource_data.resource, resource_data.amount) func _resource_consume(): var good_cycle = true for resource_data in data.resource_consumption: good_cycle = good_cycle and ResourceController.consume_resource( resource_data.resource, resource_data.amount ) # i know it says resource consumption but this is also where we make sure # our fields still make sense, okay? for field_requirement in data.field_requirements: if !field_requirement.is_satisfied_at_position(self.grid, self.tile_pos): good_cycle = false #var field_value = grid.get_field_value_at(field_requirement.field, tile_pos) #if field_requirement.enforce_min and field_value < field_requirement.minimum: #good_cycle = false #if field_requirement.enforce_max and field_value > field_requirement.maximum: #good_cycle = false if !good_cycle: death_timer += 1 queue_redraw() elif death_timer != 0: death_timer = 0 queue_redraw() func _draw(): seed(get_instance_id()) match data.style: BuildingData.RenderStyle.RandomBuilding: _draw_building() BuildingData.RenderStyle.Full: _render_full() BuildingData.RenderStyle.Outline: _render_outline() BuildingData.RenderStyle.Triangle: _render_triangle() BuildingData.RenderStyle.Circles: _render_circles() if death_timer > 0: _draw_death_timer_overlay() func _exit_tree(): grid.unregister_building(self) for storage in data.resource_stockpiles: ResourceController.remove_storage(storage) ResourceController.upgrade.disconnect(_upgrade_downgrade) ResourceController.produce.disconnect(_resource_produce) ResourceController.consume.disconnect(_resource_consume) func randf_norm(): return (randf() + randf() + randf() + randf() + randf()) / 5.0 func random_box_within(bounds: Rect2, min_size: float = 0.2, max_size: float = 0.6) -> Rect2: var size = bounds.size * Vector2( randf_norm() * (max_size - min_size) + min_size, randf_norm() * (max_size - min_size) + min_size ) var position = (bounds.size - size) * Vector2(randf(), randf()) return Rect2(bounds.position + position, size) func _get_render_bounds() -> Rect2: var dimensions = self.size * (self.grid.cell_size if self.grid != null else 100) return Rect2(dimensions / -2.0, dimensions) func _draw_building(): var render_bounds = _get_render_bounds() var bottom_box = random_box_within(render_bounds, 0.2, 0.6) #draw_rect(_get_render_bounds(), data.color.darkened(0.5), true) draw_rect(bottom_box, self.data.color, true) #draw_rect(render_bounds, self.data.color, false, 2) _draw_rect_inset(render_bounds, data.color, 4) func _render_full(): draw_rect(_get_render_bounds(), data.color, true) func _render_outline(): var bounds = _get_render_bounds().grow(-8) var left = bounds.grow_side(SIDE_RIGHT, -(bounds.size.y - 4)) var right = bounds.grow_side(SIDE_LEFT, -(bounds.size.y - 4)) var top = bounds.grow_side(SIDE_BOTTOM, -(bounds.size.y - 4)) var bottom = bounds.grow_side(SIDE_TOP, -(bounds.size.y - 4)) draw_dashed_line(bounds.position, bounds.position + Vector2.RIGHT * bounds.size.x, data.color, 4, 6) draw_dashed_line(bounds.position, bounds.position + Vector2.DOWN * bounds.size.y, data.color, 4, 6) draw_dashed_line(bounds.position + bounds.size, bounds.position + bounds.size + Vector2.LEFT * bounds.size.x, data.color, 4, 6) draw_dashed_line(bounds.position + bounds.size, bounds.position + bounds.size + Vector2.UP * bounds.size.y, data.color, 4, 6) func _render_triangle(): draw_colored_polygon(triangle_points, data.color) func _render_circles(): var bounds = _get_render_bounds() for idx in range(3): var radius = min(bounds.size.x, bounds.size.y) / 4.0 * randf_norm() var inner_bounds = bounds.grow(-radius) var point = inner_bounds.position \ + Vector2(randf(), randf()) * inner_bounds.size draw_circle(point, radius, data.color, true, -1, true) func _draw_rect_inset(rect: Rect2, color: Color, width: float): var left = rect.grow_side(SIDE_RIGHT, -(rect.size.y - width)) var right = rect.grow_side(SIDE_LEFT, -(rect.size.y - width)) var top = rect.grow_side(SIDE_BOTTOM, -(rect.size.y - width)) var bottom = rect.grow_side(SIDE_TOP, -(rect.size.y - width)) draw_rect(left, color, true) draw_rect(right, color, true) draw_rect(top, color, true) draw_rect(bottom, color, true) func _draw_death_timer_overlay(): var bounds = _get_render_bounds() var font_size = 18 var color = Color.GOLDENROD if death_timer < max_death * 0.8 else Color("ee6464") var outline_color = Color.BLACK if death_timer < max_death * 0.8 else Color.BLACK draw_colored_polygon(triangle_points, color) draw_polyline(triangle_points, outline_color, 3.0, true) draw_polyline(triangle_points, color, 1.0, true) var height = ThemeDB.fallback_font.get_height(font_size) draw_string( ThemeDB.fallback_font, Vector2.LEFT * 5.0 + Vector2.DOWN * 11.5, "!", HORIZONTAL_ALIGNMENT_CENTER, 10.5, font_size, outline_color )