Files
ai-game-2/GameScript.gd
2026-03-09 11:57:48 -07:00

481 lines
11 KiB
GDScript

extends Node
class ScriptNode:
var scene
func step_type():
return ""
func get_scene():
return scene
func init(scene):
print("starting step " + step_type())
self.scene = scene
pass
func do(delta):
pass
func is_done():
return true
func interrupt():
return false
func handle_input(event: InputEvent) -> bool:
return false
class Say:
extends ScriptNode
var text
var subject : Node2D = null
var done = false
var stop = true
var started = false
var t
func step_type():
return "Say " + text
func init(scene):
super(scene)
#subject.play_animation("talk", 0)
func do(delta):
if !started:
started = true
t = Timer.new()
t.autostart = true
t.wait_time = 5.0
subject.add_child(t)
var label: Label = subject.find_child("talk-label")
#label.set_text(text)
#subject.find_child("label-root").show()
await scene.find_child("dialogue").say(text)
await t.timeout
subject.remove_child(t)
if stop:
await scene.find_child("dialogue").done_say()
#subject.find_child("label-root").hide()
#subject.stop_animation()
#subject.play_animation_raw("idle_" + subject.facing)
done = true
started = true
func is_done():
return done
func interrupt():
done = true
if stop:
await scene.find_child("dialogue").done_say()
subject.stop_animation()
subject.play_animation_raw("idle_" + subject.facing)
subject.find_child("label-root").hide()
class Narrate:
extends ScriptNode
var text
var done = false
var started = false
var dismissed_by_click = false
var fade_in_duration = 0.3
var fade_out_duration = 0.3
var chars_per_second = 20.0 # Reading speed
var min_duration = 2.0
var max_duration = 10.0
func step_type():
return "Narrate " + text.substr(0, 20)
func calculate_duration() -> float:
var duration = text.length() / chars_per_second
return clamp(duration, min_duration, max_duration)
func do(delta):
if !started:
started = true
dismissed_by_click = false
# Show narrator overlay with fade in
var narrator_overlay = scene.find_child("NarratorOverlay")
if narrator_overlay:
var panel = narrator_overlay.find_child("Panel")
var label = panel.find_child("Label")
if label:
label.text = text
if panel:
panel.modulate = Color(1, 1, 1, 0)
panel.show()
# Fade in
var tween = scene.create_tween()
tween.tween_property(panel, "modulate", Color(1, 1, 1, 1), fade_in_duration)
await tween.finished
# Set global flag that narrator is active
scene.set_meta("narrator_active", true)
# Calculate display duration
var display_duration = calculate_duration()
# Wait for either timeout or click
var timer = scene.get_tree().create_timer(display_duration)
while timer.time_left > 0 and not dismissed_by_click:
await scene.get_tree().process_frame
# Fade out (keep narrator_active flag true during fade to prevent walk trigger)
var overlay = scene.find_child("NarratorOverlay")
if overlay:
var p = overlay.find_child("Panel")
if p and p.visible:
var tween = scene.create_tween()
tween.tween_property(p, "modulate", Color(1, 1, 1, 0), fade_out_duration)
await tween.finished
p.hide()
# Clear global flag AFTER fade completes
scene.set_meta("narrator_active", false)
done = true
started = true
func is_done():
return done
func dismiss():
dismissed_by_click = true
func interrupt():
done = true
var overlay = scene.find_child("NarratorOverlay")
if overlay:
var p = overlay.find_child("Panel")
if p:
p.hide()
scene.set_meta("narrator_active", false)
func handle_input(event: InputEvent) -> bool:
if event is InputEventMouseButton and Input.is_action_just_released("interact"):
if not dismissed_by_click and not done:
dismissed_by_click = true
return true
return false
class WalkTo:
extends ScriptNode
var path = []
var subject : Node2D = null
var script_fn = null
func step_type():
return "WalkTo " + subject.get_name()
func do(delta):
# Calculate the movement distance for this frame
var distance_to_walk = 1500 * delta * (subject.get_transform().get_scale().y)
var p = subject.position
if path.size()> 0:
# Move the player along the path until he has run out of movement or the path ends.
while distance_to_walk > 0 and path.size() > 0:
var dir = snapped(subject.position.angle_to_point(path[0]), PI/4) / (PI/4)
dir = wrapi(dir, 0, 8)
var anim
# seek = animation_player.current_animation_position
#animation_player.play(anim)
#animation_player.seek(seek, true)
#subject.find_node("AnimationPlayer").playback_speed=1.8
var distance_to_next_point = p.distance_to(path[0])
if distance_to_walk <= distance_to_next_point:
var facing = ""
if dir == 4:
facing="W"
if dir == 5:
facing ="NW"
elif dir == 6:
facing="N"
elif dir ==7:
facing="NE"
elif dir == 0:
facing="E"
elif dir == 1:
facing="SE"
elif dir == 2:
facing = "S"
elif dir == 3:
facing = "SW"
if facing:
var seek = 0
subject.facing = facing
var sprite = subject.play_animation_maintain("walk")
# The player does not have enough movement left to get to the next point.
p += p.direction_to(path[0]) * distance_to_walk
else:
# The player get to the next point
p = path[0]
path = path.slice(1)
# Update the distance to walk
distance_to_walk -= distance_to_next_point
subject.position = p;
func is_done():
if path.size() == 0:
subject.play_animation("idle", 0)
#subject.find_child("AnimatedSprite2D").pause()
return path.size() == 0
class WalkToDeferred:
extends WalkTo
var named_to
var named_from
var subject_name
func step_type():
return "Walk to " + named_to
func init(scene):
super(scene)
print("SCENE IS", scene)
subject = scene.get_node(subject_name)
var s = scene.get_node("SceneViewport/background")
var g = s.get_children()
path = NavigationServer2D.map_get_path(s.map, s.pathfind.to_local(s.get_node(named_from).global_position), s.pathfind.to_local(s.get_node(named_to).global_position), true)
print(" PATH IS", path)
#[Vector2(0,0), Vector2(300,300)]
class Transition:
extends ScriptNode
var path = []
var subject : Node2D = null
var next : Resource = null
var script_fn = null
var position = null
var transitioned : String
var running = false
var done = false
func step_type():
return "transition"
func do(delta):
if not running:
running = true
var parent = subject.get_parent()
var fade_player = subject.get_parent().get_parent().find_child("FadePlayer", true)
fade_player.play("fade-out",0.0, 1.5)
await fade_player.animation_finished
var new_scene = next.instantiate()
new_scene.name="background"
parent.remove_child(subject)
var pos : Node2D = new_scene.get_node(position)
var c = new_scene.get_children()
if new_scene is Scene:
new_scene.starting_point = pos.global_position
parent.add_child(new_scene)
subject.emit_signal("transitioned", new_scene)
subject.queue_free()
fade_player.play("fade-in",0.0, 1.5)
await fade_player.animation_finished
done = true
parent
func is_done():
return done
class TriggerSignal:
extends ScriptNode
var path = []
var subject : Node2D = null
var next : Resource = null
var script_fn = null
var running = false
var s :String = ""
func do(delta):
pass
# get_tree().find_child("Node2D/background").emit_signal(s)
func is_done():
true
class SwitchCamera:
extends ScriptNode
var path = ""
var d = false
var t: SceneTreeTimer
func init(scene: Node2D):
var s = scene.get_node("SceneViewport/background")
var g = s.get_children()
CameraTransition.transition_camera2D(scene.get_tree().root.get_node("Node2D/SceneViewport/PlayerTracker/Camera2D"), s.find_child(path))
t = scene.get_tree().create_timer(2.0)
func do(delta):
await t.timeout
d = true
# get_tree().find_child("Node2D/background").emit_signal(s)
func is_done():
return d
class ResetCamera:
extends ScriptNode
var path = ""
var d = false
var t: SceneTreeTimer
func init(scene: Node2D):
var s = scene.get_node("SceneViewport/background")
CameraTransition.transition_camera2D(scene.get_viewport().get_camera_2d(), scene.get_node("SceneViewport/PlayerTracker/Camera2D"))
t = scene.get_tree().create_timer(2.0)
func do(delta):
await t.timeout
d = true
# get_tree().find_child("Node2D/background").emit_signal(s)
func is_done():
return d
class ScriptEdge:
var from : ScriptNode
var to : ScriptNode
class ScriptGraph:
var initial: ScriptNode
var current = []
var nodes = []
var edges = []
var can_interrupt = false
var current_scene
var last_node
signal script_complete
func step(delta, scene):
for c in range(current.size()):
current[c].do(delta)
var to_add = []
for current_index in range(current.size()):
var current_step = current[-current_index]
if current_step.is_done():
print("Stopping step", current_step.step_type())
current.remove_at(-current_index)
for edge in edges:
if edge.from == current_step:
to_add.push_back(edge.to)
edge.to.init(scene)
current.append_array(to_add)
if current.size() == 0:
emit_signal("script_complete")
func interrupt():
for c in current:
c.interrupt()
return can_interrupt
func handle_input(event: InputEvent) -> bool:
for c in current:
if c.handle_input(event):
return true
return false
var script_graph: ScriptGraph
#var last_node: ScriptNode
func init(step: ScriptNode):
script_graph = ScriptGraph.new()
script_graph.initial = step
step.init(get_node("/root/Node2D"))
script_graph.current = [step]
script_graph.last_node = step
#last_node = step
return self
func and_then(step: ScriptNode):
script_graph.nodes.push_back(step)
var edge = ScriptEdge.new()
edge.from = script_graph.last_node
edge.to = step
script_graph.edges.push_back(edge)
script_graph.last_node=step
return self
func can_interrupt():
script_graph.can_interrupt = true
return self
func build(subject, on_complete):
script_graph.connect("script_complete", Callable(subject, on_complete))
script_graph.connect("script_complete", self.on_complete)
return script_graph
func on_complete():
current_script=null
func walk_path(subject, path):
var walk_to = WalkTo.new()
walk_to.subject = subject
walk_to.path = path
return walk_to
func say(subject, text, stop=true):
var say = Say.new()
say.subject = subject
say.text = text
say.stop = stop
return say
func narrate(text):
var narrate = Narrate.new()
narrate.text = text
return narrate
func dismiss_current_narrator():
if current_script:
for node in current_script.current:
if node is Narrate:
node.dismiss()
return true
return false
func walk_to_deferred(named_from, named_to):
var say = WalkToDeferred.new()
say.subject_name = "SceneViewport/background/Graham"
say.named_from = named_from
say.named_to = named_to
return say
func trigger_signal(s):
var thing = TriggerSignal.new()
thing.s = s
return thing
func transition(subject, scene, position_identifier):
var t = Transition.new()
t.subject = subject
t.next = scene
t.position = position_identifier
return t
func switch_camera(path):
var thing = SwitchCamera.new()
thing.path = path
return thing
func reset_camera():
var thing = ResetCamera.new()
return thing
var current_script : ScriptGraph = null