126 lines
3.9 KiB
GDScript
126 lines
3.9 KiB
GDScript
extends "res://scripts/building/piece.gd"
|
|
## A charcoal kiln or a smelter: E opens it like a chest. Put what it works
|
|
## on inside and it turns it into something else over time, on its own,
|
|
## while you're away (docs/PROGRESSION_DESIGN.md §2). It glows while it works.
|
|
##
|
|
## - Kiln: 2 wood -> 1 charcoal, 20 s.
|
|
## - Smelter: 1 iron ore + 1 charcoal -> 1 iron bar, 30 s; or 3 iron
|
|
## nuggets + 1 charcoal -> 1 iron bar.
|
|
##
|
|
## The output goes into the same slots, for you to take out. On a server it
|
|
## runs there (step() is skipped on players' copies) and the contents reach
|
|
## everyone like a chest's. Progress is saved.
|
|
|
|
const SLOTS := 6
|
|
const RECIPES := {
|
|
"charcoal_kiln": [{"inputs": {"wood": 2}, "output": "charcoal", "seconds": 20.0}],
|
|
"smelter": [
|
|
{"inputs": {"iron_ore": 1, "charcoal": 1}, "output": "iron_bar", "seconds": 30.0},
|
|
{"inputs": {"iron_nugget": 3, "charcoal": 1}, "output": "iron_bar", "seconds": 30.0},
|
|
],
|
|
}
|
|
|
|
var inventory := Inventory.new(SLOTS)
|
|
var progress := 0.0 ## seconds into the current batch
|
|
var _light: OmniLight3D
|
|
var _glow: MeshInstance3D
|
|
var _t := 0.0
|
|
|
|
func _build() -> void:
|
|
add_to_group("processor")
|
|
inventory.changed.connect(_on_changed)
|
|
if DisplayServer.get_name() == "headless":
|
|
return
|
|
_light = OmniLight3D.new()
|
|
_light.light_color = Color(1.0, 0.55, 0.25)
|
|
_light.omni_range = 5.0
|
|
_light.light_energy = 0.0
|
|
_light.position = Vector3(0, 0.6, 0.5)
|
|
add_child(_light)
|
|
# The fire showing through the mouth.
|
|
_glow = MeshInstance3D.new()
|
|
var q := QuadMesh.new()
|
|
q.size = Vector2(0.36, 0.26)
|
|
_glow.mesh = q
|
|
var m := StandardMaterial3D.new()
|
|
m.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
|
|
m.albedo_color = Color(1.0, 0.45, 0.12)
|
|
m.emission_enabled = true
|
|
m.emission = Color(1.0, 0.45, 0.12)
|
|
m.emission_energy_multiplier = 3.0
|
|
_glow.material_override = m
|
|
_glow.position = Vector3(0, 0.3 if item_id == "smelter" else 0.25, 0.58 if item_id == "smelter" else 0.72)
|
|
_glow.visible = false
|
|
add_child(_glow)
|
|
|
|
## The recipe it would work on now, or {} (nothing to do, or no room for
|
|
## what it makes).
|
|
func current() -> Dictionary:
|
|
for r in RECIPES.get(item_id, []):
|
|
if inventory.has_all(r.inputs) and inventory.space_for(r.output) > 0:
|
|
return r
|
|
return {}
|
|
|
|
func working() -> bool:
|
|
return not current().is_empty()
|
|
|
|
func _process(delta: float) -> void:
|
|
if WorldNet.is_client():
|
|
_show(working()) # (the server does the work; we just show it)
|
|
return
|
|
step(delta)
|
|
|
|
## Works for `secs` (several batches if there's time and stuff for them).
|
|
func step(secs: float) -> void:
|
|
var r := current()
|
|
if r.is_empty():
|
|
progress = 0.0
|
|
_show(false)
|
|
return
|
|
progress += secs
|
|
while not r.is_empty() and progress >= float(r.seconds):
|
|
progress -= float(r.seconds)
|
|
for id in r.inputs:
|
|
inventory.remove(id, int(r.inputs[id]))
|
|
inventory.add(r.output, 1)
|
|
r = current()
|
|
if r.is_empty():
|
|
progress = 0.0
|
|
_show(not r.is_empty())
|
|
|
|
func _show(on: bool) -> void:
|
|
if _light == null:
|
|
return
|
|
_t += get_process_delta_time()
|
|
_glow.visible = on
|
|
_light.light_energy = (1.2 + 0.25 * sin(_t * 9.0) * sin(_t * 3.1)) if on else 0.0
|
|
|
|
func _on_changed() -> void:
|
|
if current().is_empty():
|
|
progress = 0.0
|
|
|
|
func dismantle_block_reason() -> String:
|
|
for s in inventory.slots:
|
|
if s != null:
|
|
return "Empty it first"
|
|
return ""
|
|
|
|
func interact_prompt(_player: Node) -> String:
|
|
var r := current()
|
|
var what := "charcoal" if item_id == "charcoal_kiln" else "an iron bar"
|
|
if r.is_empty():
|
|
var needs := "put in wood" if item_id == "charcoal_kiln" else "put in iron ore (or 3 nuggets) and charcoal"
|
|
return "%s (idle: %s) [E] Open" % [display_name(), needs]
|
|
if WorldNet.is_client():
|
|
return "%s (making %s) [E] Open" % [display_name(), what]
|
|
return "%s (making %s, %d s) [E] Open" % [display_name(), what, ceili(float(r.seconds) - progress)]
|
|
|
|
func interact(player: Node) -> void:
|
|
player.open_inventory(self)
|
|
|
|
func save_extra() -> Dictionary:
|
|
return {"progress": progress}
|
|
|
|
func load_extra(d: Dictionary) -> void:
|
|
progress = float(d.get("progress", 0.0))
|