207 lines
7.1 KiB
GDScript
207 lines
7.1 KiB
GDScript
|
|
@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
|
||
|
|
|
||
|
|
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
|
||
|
|
)
|