saumwacht-godot/scripts/presentation/sanctuary.gd
Martin Stickelbroeck c2b447610c Baseline: Saumwacht 0.15.0 (Phase 20A) vor dem Umbau zu Champions of Luneraria
Unveränderter Ausgangsstand inklusive Masterprompt und Konzeptbildern
unter assets/. .godot/ und docs/screenshots/ bleiben laut .gitignore
unversioniert; letztere sind unter ../backups gesichert.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 20:00:36 +02:00

81 lines
3 KiB
GDScript

extends Node3D
## The environment has no colliders: board coordinates remain the gameplay source.
const TerrainMaterial = preload("res://scripts/presentation/sanctuary.gdshader")
const WaterMaterial = preload("res://scripts/presentation/river.gdshader")
const Stone = preload("res://assets/materials/phase10/limestone-albedo.png")
var _materials: Dictionary = {}
func _ready() -> void:
name = "VerdantRift"
var landscape: Node3D = preload("res://assets/environment/verdant-rift.glb").instantiate()
add_child(landscape)
_decorate(landscape)
var river := MeshInstance3D.new()
river.name = "LivingRiver"
var surface := PlaneMesh.new()
surface.size = Vector2(180.0, 180.0)
surface.subdivide_width = 1
surface.subdivide_depth = 1
river.mesh = surface
river.position.y = -3.7
var water := ShaderMaterial.new()
water.shader = WaterMaterial
river.material_override = water
add_child(river)
# The embers are deliberately sparse and never cover board cell indicators.
var motes := GPUParticles3D.new()
motes.name = "SanctuaryMotes"
motes.amount = 75
motes.lifetime = 12
motes.visibility_aabb = AABB(Vector3(-32,-5,-34), Vector3(64,18,68))
var motion := ParticleProcessMaterial.new()
motion.emission_shape = ParticleProcessMaterial.EMISSION_SHAPE_BOX
motion.emission_box_extents = Vector3(24,1,28)
motion.gravity = Vector3(.02,.045,.015)
motion.initial_velocity_min = .01
motion.initial_velocity_max = .12
motion.scale_min = .013
motion.scale_max = .035
motes.process_material = motion
var mote := SphereMesh.new()
mote.radius = 1
mote.height = 2
mote.radial_segments = 6
mote.rings = 3
var light := StandardMaterial3D.new()
light.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
light.albedo_color = Color("c6d7a0")
light.emission_enabled = true
light.emission = Color("b3c985")
light.emission_energy_multiplier = 1.5
mote.material = light
motes.draw_pass_1 = mote
add_child(motes)
func _decorate(node: Node) -> void:
if node is MeshInstance3D:
for surface: int in range(node.mesh.get_surface_count()):
var source: StandardMaterial3D = node.mesh.surface_get_material(surface)
if source == null:
continue
var key: String = source.resource_name
if "teal" in key or "coral" in key or "brass" in key:
continue
if not _materials.has(key):
_materials[key] = terrain_material(source)
node.set_surface_override_material(surface, _materials[key])
for child: Node in node.get_children():
_decorate(child)
## Shared Kluft surface for ENV_* materials; also used by the menu diorama.
static func terrain_material(source: StandardMaterial3D) -> ShaderMaterial:
var key: String = source.resource_name
var material := ShaderMaterial.new()
material.shader = TerrainMaterial
material.set_shader_parameter("base_color", source.albedo_color)
material.set_shader_parameter("stone_map", Stone)
material.set_shader_parameter("foliage", "leaf" in key)
material.set_shader_parameter("bark", "bark" in key)
material.set_shader_parameter("soil", "soil" in key)
material.set_shader_parameter("paving", "paving" in key)
return material