93 lines
3.3 KiB
GDScript
93 lines
3.3 KiB
GDScript
extends Node
|
|
|
|
const BUILDING_SCENE: PackedScene = preload("res://scenes/entities/building/building.tscn")
|
|
const GRID_SIZE: float = 1.0
|
|
|
|
@onready var inventory_system: Node = get_node("../InventorySystem")
|
|
|
|
var blueprints: Array = []
|
|
|
|
func _ready() -> void:
|
|
blueprints = [
|
|
{"id": &"floor", "name": "Floor", "size": Vector3(1, 0.2, 1), "color": Color(0.55, 0.4, 0.25), "material": &"wood", "cost": 1},
|
|
{"id": &"wall", "name": "Wall", "size": Vector3(1, 2, 0.2), "color": Color(0.7, 0.6, 0.45), "material": &"wood", "cost": 1},
|
|
{"id": &"door", "name": "Door", "size": Vector3(1, 2, 0.15), "color": Color(0.4, 0.25, 0.15), "material": &"wood", "cost": 2},
|
|
{"id": &"roof", "name": "Roof", "size": Vector3(1, 0.2, 1), "color": Color(0.5, 0.3, 0.2), "material": &"wood", "cost": 1}
|
|
]
|
|
|
|
func _building_root() -> Node3D:
|
|
var n: Node = get_node_or_null("/root/World/EntityRoot/Buildings")
|
|
if n == null:
|
|
n = get_node_or_null("/root/Dungeon/EntityRoot/Buildings")
|
|
return n
|
|
|
|
func get_blueprints() -> Array:
|
|
return blueprints
|
|
|
|
func find_blueprint(id: StringName) -> Dictionary:
|
|
for b in blueprints:
|
|
if b.id == id:
|
|
return b
|
|
return {}
|
|
|
|
func snap_position(pos: Vector3) -> Vector3:
|
|
return Vector3(round(pos.x / GRID_SIZE) * GRID_SIZE, max(0.0, pos.y), round(pos.z / GRID_SIZE) * GRID_SIZE)
|
|
|
|
func place(player: Node, id: StringName, pos: Vector3, rot: float) -> bool:
|
|
if not (multiplayer.is_server() or multiplayer.multiplayer_peer == null):
|
|
request_place.rpc_id(1, player.get_path(), id, pos, rot)
|
|
return false
|
|
var bp: Dictionary = find_blueprint(id)
|
|
if bp.is_empty():
|
|
return false
|
|
var mat: StringName = bp.material
|
|
var cost: int = bp.cost
|
|
if inventory_system.get_amount(player, mat) < cost:
|
|
return false
|
|
inventory_system.remove_item(player, mat, cost)
|
|
var root := _building_root()
|
|
if root == null:
|
|
return false
|
|
var b: StaticBody3D = BUILDING_SCENE.instantiate()
|
|
b.building_id = id
|
|
b.name = "B_%s_%d" % [str(id), Time.get_ticks_msec() + randi() % 1000]
|
|
root.add_child(b, true)
|
|
b.global_position = snap_position(pos)
|
|
b.rotation.y = rot
|
|
b.apply_building(id)
|
|
_apply_building_visual.rpc(b.get_path(), id)
|
|
EventBus.building_placed.emit(b)
|
|
return true
|
|
|
|
func remove(player: Node, b_path: NodePath) -> bool:
|
|
if not (multiplayer.is_server() or multiplayer.multiplayer_peer == null):
|
|
request_remove.rpc_id(1, player.get_path(), b_path)
|
|
return false
|
|
var node: Node = get_node_or_null(b_path)
|
|
if node == null:
|
|
return false
|
|
var bp: Dictionary = find_blueprint(node.building_id)
|
|
if not bp.is_empty():
|
|
inventory_system.add_item(player, bp.material, max(1, int(float(bp.cost) * 0.5)))
|
|
EventBus.building_removed.emit(node)
|
|
node.queue_free()
|
|
return true
|
|
|
|
@rpc("any_peer", "reliable")
|
|
func request_place(player_path: NodePath, id: StringName, pos: Vector3, rot: float) -> void:
|
|
var p: Node = get_node_or_null(player_path)
|
|
if p:
|
|
place(p, id, pos, rot)
|
|
|
|
@rpc("any_peer", "reliable")
|
|
func request_remove(player_path: NodePath, b_path: NodePath) -> void:
|
|
var p: Node = get_node_or_null(player_path)
|
|
if p:
|
|
remove(p, b_path)
|
|
|
|
@rpc("authority", "reliable", "call_local")
|
|
func _apply_building_visual(b_path: NodePath, id: StringName) -> void:
|
|
var node: Node = get_node_or_null(b_path)
|
|
if node and node.has_method("apply_building"):
|
|
node.apply_building(id)
|