TowerGame/scripts/building_components/building.gd

173 lines
5.5 KiB
GDScript

extends Node3D
class_name Building
@export var hologram_material: Material = preload("res://shaders/hologram_material.tres")
@export var hologram_build_min: float = -1
@export var hologram_build_max: float = 1
@export_group("Construction", "build")
@export var build_time: float = 5.0 ## Worker-time taken for 1 citizen to finish the building, in citizen-seconds.
@export var build_materials_needed: Dictionary[Item, int] = {}
@export_group("Defence")
@export var max_hp: int = 100 ## Amount of damage this building can sustain before being destroyed.
@export_group("Stacking")
@export var can_stack: bool = true ## Whether this building can be stacked on top of other buildings.
@export var can_be_stacked_on: bool = true ## Whether this building will accept other buildings being stacked on it.
@export var stack_position: Vector3 = Vector3(0,2,0) ## The local position that stacked buildings will be placed at.
@onready var build_position: Vector3 = global_position
@onready var nav_obstacle: NavObstable = $NavObstacle
@onready var consumer: Consumer = $Consumer
@onready var producer: Producer = $Producer
@onready var collision_shape: CollisionShape3D = $CollisionShape3D
signal functional_changed(functional: bool)
enum BuildState {
UNPLACED,
BUILDING,
READY,
DESTROYED
}
const PLACEMENT_POSITION_OK: int = 0b0001
const PLACEMENT_FOUNDATION_REQUIRED: int = 0b0010
const PLACEMENT_PART_ADDED: int = 0b0100
const PLACEMENT_COMPLETED: int = 0b1000
var hp: int = max_hp
var build_progress: float = 0.0:
set(val):
build_progress = val
if build_progress >= build_time:
build_state = BuildState.READY
var build_percent: float = build_progress / build_time
set_visual_build_progress(build_percent)
var stacked_buildings: Array[Building] = []
var build_state: BuildState = BuildState.READY:
set(state):
if state != build_state:
build_state = state
functional_changed.emit(is_functional())
if build_state == BuildState.BUILDING:
for item in build_materials_needed.keys():
for i in range(build_materials_needed.get(item)):
var task: Task.FetchItemTask = Task.FetchItemTask.new()
task.building = self
task.item = item
CitizenManager._instance.add_task(task)
check_buildable()
set_visual_build_progress(0.0)
elif build_state == BuildState.READY:
set_visual_build_progress(1.0)
var build_materials_used: Dictionary[Item, int] = {}
func _ready() -> void:
if nav_obstacle != null:
functional_changed.connect(func(enable:bool): nav_obstacle.enabled = enable)
if consumer != null:
functional_changed.connect(func(enable:bool): consumer.enabled = enable)
if producer != null:
functional_changed.connect(func(enable:bool): producer.enabled = enable)
if collision_shape != null:
functional_changed.connect(func(enable:bool): collision_shape.disabled = !enable)
func _process(delta: float) -> void:
if build_state == BuildState.UNPLACED:
global_position = global_position.lerp(build_position, 0.4)
var debug_text: String = ""
debug_text += "State: %s\n" % build_state
if consumer != null:
var consumer_state: String
if consumer.enabled:
consumer_state = "OK"
else:
consumer_state = "Off"
debug_text += "Input: %s \nStorage: %d\n" % [consumer_state, consumer.storage_total]
if producer != null:
var producer_state = "OK"
if !producer.enabled:
producer_state = "Off"
elif !producer.can_produce():
producer_state = "Blocked"
debug_text += "Output: %s\n" % producer_state
$Label3D.text = debug_text
func is_functional() -> bool:
return build_state == BuildState.READY
func _start_placement() -> void:
build_state = BuildState.UNPLACED
func _end_placement() -> void:
build_state = BuildState.BUILDING
func _placement_select_building(building: Building, confirmed: bool) -> int:
while !building.stacked_buildings.is_empty():
building = building.stacked_buildings[0]
var stack_ok: bool = can_stack and building.can_be_stacked_on
var ret: int = 0
if stack_ok:
build_position = building.global_position + building.stack_position
ret |= PLACEMENT_POSITION_OK
if confirmed and stack_ok:
global_position = build_position
building.stacked_buildings.append(self)
ret |= PLACEMENT_COMPLETED
return ret
func _placement_select_position(pos: Vector3, confirmed: bool) -> int:
var ret: int = 0
ret |= PLACEMENT_POSITION_OK
build_position = Vector3(roundf(pos.x), ceilf(pos.y-0.01), roundf(pos.z))
if confirmed:
build_state = BuildState.BUILDING
ret |= PLACEMENT_COMPLETED
return ret
func check_buildable() -> void:
if can_build():
var task: Task.BuildTask = Task.BuildTask.new()
task.building = self
CitizenManager._instance.add_task(task)
func _add_build_material(item: Item) -> void:
build_materials_used.set(item, build_materials_used.get(item, 0) + 1)
check_buildable()
func can_build() -> bool:
for item in build_materials_needed.keys():
if build_materials_used.get(item,0) < build_materials_needed.get(item,0):
return false
return true
func set_visual_build_progress(ratio: float) -> void:
var geometries: Array[Node] = find_children("", "GeometryInstance3D", true)
for node in geometries:
var geometry: GeometryInstance3D = node as GeometryInstance3D
if geometry != null:
if ratio >= 1.0:
geometry.material_override = null
else:
geometry.material_override = hologram_material
var built_amount: float = remap(ratio, 0, 1, hologram_build_min, hologram_build_max)
geometry.set_instance_shader_parameter("built_amount", built_amount)
#var opacity: float = 0.5 + (ratio * 0.5)
#geometry.transparency = 1.0 - opacity