173 lines
5.5 KiB
GDScript
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
|