P1 iron: nuggets, ore, clay, kiln, smelter, forge, iron tools and arrows, lantern, tool wear and repair
This commit is contained in:
20
scripts/building/forge.gd
Normal file
20
scripts/building/forge.gd
Normal file
@@ -0,0 +1,20 @@
|
||||
extends "res://scripts/building/piece.gd"
|
||||
## Forge: an anvil by a stone hearth. Unlocks "forge" recipes (iron tools,
|
||||
## nails, a lantern) within 6 m, and repairs iron tools. E opens crafting.
|
||||
|
||||
func _build() -> void:
|
||||
add_to_group("station:forge")
|
||||
if DisplayServer.get_name() == "headless":
|
||||
return
|
||||
var l := OmniLight3D.new()
|
||||
l.light_color = Color(1.0, 0.5, 0.2)
|
||||
l.omni_range = 4.0
|
||||
l.light_energy = 0.8
|
||||
l.position = Vector3(-0.55, 0.9, 0.2)
|
||||
add_child(l)
|
||||
|
||||
func interact_prompt(_player: Node) -> String:
|
||||
return "Forge [E] Craft"
|
||||
|
||||
func interact(player: Node) -> void:
|
||||
player.open_inventory(null)
|
||||
125
scripts/building/processor.gd
Normal file
125
scripts/building/processor.gd
Normal file
@@ -0,0 +1,125 @@
|
||||
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))
|
||||
Reference in New Issue
Block a user