Some changes

This commit is contained in:
2026-06-11 19:59:31 -05:00
parent 2f2ea060b1
commit eec429147b
150 changed files with 16615 additions and 262 deletions
-6
View File
@@ -43,12 +43,6 @@ func addCallables(params:Dictionary) -> Array[int]:
indexes.append(addCallable(newDict))
return indexes
func addConversation(resources:Array[ConversationResource]) -> Array[int]:
var callables:Array[Dictionary] = []
for resource in resources:
callables.append(resource.toCallable())
return addCallables({ 'functions': callables })
func start() -> void:
if queue.size() == 0:
return
+65 -42
View File
@@ -1,51 +1,84 @@
class_name BattleCutsceneAction
const DialogueAction = preload("res://cutscene/dialogue/DialogueAction.gd")
static func battleDecisionCallable(_params:Dictionary) -> int:
print("Executing battle action...")
await UI.TEXTBOX.setTextAndWait("Performing battle decision")
var decision:BattleDecision = _params["decision"]
static var NARRATION:DialogueResource = preload("res://dialogue/battle/narration.dialogue")
# State object passed as extra_game_states so {{variable}} tokens resolve in the dialogue file.
class BattleNarrationState:
var fighter_name:String
var user_name:String
var target_name:String
var move_name:String
var damage:int
func _init(params:Dictionary) -> void:
fighter_name = params.get('fighter_name', '')
user_name = params.get('user_name', '')
target_name = params.get('target_name', '')
move_name = params.get('move_name', '')
damage = params.get('damage', 0)
# Narrates and executes a single fighter's decision.
static func battleDecisionCallable(params:Dictionary) -> int:
var decision:BattleDecision = params['decision']
var state = BattleNarrationState.new({
'user_name': decision.user.name if decision.user is PartyMember else 'Enemy',
'move_name': decision.action.handle,
'target_name': decision.targets[0].name if decision.targets[0] is PartyMember else 'Enemy',
})
var cutscene:Cutscene = params['cutscene']
cutscene.addCallable(
DialogueAction.getDialogueCallable(NARRATION, 'move_perform', [state]).merged(
{'position': Cutscene.CUTSCENE_ADD_NEXT}, false
)
)
decision.action.perform({'user': decision.user, 'targets': decision.targets})
return Cutscene.CUTSCENE_CONTINUE
static func getBattleDecisionCallable(decision:BattleDecision) -> Dictionary:
return {
"function": battleDecisionCallable,
"decision": decision
'function': battleDecisionCallable,
'decision': decision,
}
static func playerDecisionCallable(_params:Dictionary) -> int:
# First, are all enemies, or all players, defeated?
var allPlayersDead:bool = false
var allEnemiesDead:bool = false
static func playerDecisionCallable(params:Dictionary) -> int:
# Check end conditions
var allPlayersDead:bool = true
var allEnemiesDead:bool = true
for fighter:BattleFighter in BATTLE.fighterMap.values():
if fighter == null:
continue
if fighter.status != BattleFighter.Status.DEAD:
if fighter.status == BattleFighter.Status.DEAD:
continue
if fighter.isPlayerControlled():
allPlayersDead = false
else:
allEnemiesDead = false
# If all players are dead, game over unfortunately.
if allPlayersDead:
print("All players defeated! Game Over.")
assert(false)
params['cutscene'].addCallable(
DialogueAction.getDialogueCallable(NARRATION, 'battle_defeat').merged(
{'position': Cutscene.CUTSCENE_ADD_NEXT}, false
)
)
return Cutscene.CUTSCENE_END
# If all enemies are dead, victory!
if allEnemiesDead:
print("All enemies defeated! Victory!")
assert(false)
params['cutscene'].addCallable(
DialogueAction.getDialogueCallable(NARRATION, 'battle_victory').merged(
{'position': Cutscene.CUTSCENE_ADD_NEXT}, false
)
)
return Cutscene.CUTSCENE_END
# Determine fighters and whether they're AI or player controlled
# Collect fighters
var playerFighters:Array[BattleFighter] = []
var aiFighters:Array[BattleFighter] = []
for fighter:BattleFighter in BATTLE.fighterMap.values():
if !fighter || !fighter.canPlayerMakeDecision():
continue
playerFighters.append(fighter)
for fighter:BattleFighter in BATTLE.fighterMap.values():
if !fighter || !fighter.canMakeDecision():
continue
@@ -53,42 +86,32 @@ static func playerDecisionCallable(_params:Dictionary) -> int:
continue
aiFighters.append(fighter)
# Get decisions
# Gather decisions
var decisions:Array[BattleDecision] = []
var playerDecisions = await BATTLE.battleScene.getBattleDecisions(playerFighters)
decisions.append_array(playerDecisions)
for fighter in aiFighters:
var decision = fighter.getAIDecision()
if decision != null:
decisions.append(decision)
# Here I could do something like cutscene specific logic?
# Prioritize moves
decisions.shuffle()# Randomizes for moves that have equal chance of happening
# Sort by priority
decisions.shuffle()
decisions.sort_custom(func(a:BattleDecision, b:BattleDecision) -> int:
var priorityA = a.getPriority()
var priorityB = b.getPriority()
if priorityA > priorityB:
return -1
elif priorityA < priorityB:
return 1
else:
return 0
var pa = a.getPriority()
var pb = b.getPriority()
if pa > pb: return -1
elif pa < pb: return 1
else: return 0
)
# Turn into cutscene actions.
for decision in decisions:
print("Adding decision to cutscene: %s" % decision)
_params['cutscene'].addCallable(BattleCutsceneAction.getBattleDecisionCallable(decision))
params['cutscene'].addCallable(getBattleDecisionCallable(decision))
# Then send to next decision
_params['cutscene'].addCallable(BattleCutsceneAction.getPlayerDecisionCallable())
params['cutscene'].addCallable(getPlayerDecisionCallable())
return Cutscene.CUTSCENE_CONTINUE
static func getPlayerDecisionCallable() -> Dictionary:
return {
"function": playerDecisionCallable
'function': playerDecisionCallable,
}
@@ -1,12 +0,0 @@
class_name ConversationAction
static func textboxCallable(params:Dictionary) -> int:
assert(params.has('label'))
await UI.TEXTBOX.setTextAndWait(params['label'])
return Cutscene.CUTSCENE_CONTINUE
static func getTextboxCallable(label:String) -> Dictionary:
return {
"function": textboxCallable,
"label": label
}
@@ -1 +0,0 @@
uid://dng7tgnex55wp
@@ -1 +0,0 @@
uid://b40rstjkpompc
@@ -1,9 +0,0 @@
extends Resource
class_name ConversationResource
const ConversationAction = preload("res://cutscene/conversation/ConversationAction.gd")
@export_node_path("Entity") var entity:NodePath
@export_multiline var label: String
func toCallable() -> Dictionary:
return ConversationAction.getTextboxCallable(label)
@@ -1 +0,0 @@
uid://yn7kxdargafx
+43
View File
@@ -0,0 +1,43 @@
class_name DialogueAction
# Runs a .dialogue file through the VNTextbox and returns CUTSCENE_CONTINUE when
# the last line is dismissed. Mutations in the .dialogue file are executed
# automatically by DialogueManager before the line is returned.
#
# extra_game_states: additional objects/dicts whose properties and methods are
# accessible inside the .dialogue file (alongside all autoloads).
static func dialogueCallable(params:Dictionary) -> int:
assert(params.has('resource'))
var resource:DialogueResource = params['resource']
var title:String = params.get('title', 'start')
var extraStates:Array = params.get('extraStates', [])
var line:DialogueLine = await DialogueManager.get_next_dialogue_line(resource, title, extraStates)
while line != null:
var text:String = line.text
if line.character:
text = line.character + ": " + text
if line.responses.size() > 0:
# Show text then auto-pick the first allowed response.
# Replace this block with a real response UI when branching dialogue is needed.
await UI.TEXTBOX.setTextAndWait(text)
var nextId:String = ""
for response:DialogueResponse in line.responses:
if response.is_allowed:
nextId = response.next_id
break
line = await DialogueManager.get_next_dialogue_line(resource, nextId, extraStates)
else:
await UI.TEXTBOX.setTextAndWait(text)
line = await DialogueManager.get_next_dialogue_line(resource, line.next_id, extraStates)
return Cutscene.CUTSCENE_CONTINUE
static func getDialogueCallable(resource:DialogueResource, title:String = 'start', extraStates:Array = []) -> Dictionary:
return {
'function': dialogueCallable,
'resource': resource,
'title': title,
'extraStates': extraStates,
}
+1
View File
@@ -0,0 +1 @@
uid://cnljqhsjcowen
+20 -9
View File
@@ -1,18 +1,29 @@
class_name ItemAction
const ConversationAction = preload("res://cutscene/conversation/ConversationAction.gd")
const DialogueAction = preload("res://cutscene/dialogue/DialogueAction.gd")
# Passed as extra_game_states so {{item_name}} and {{quantity}} resolve in the .dialogue file.
class ItemDialogueState:
var item_name:String
var quantity:int
func _init(name:String, qty:int) -> void:
item_name = name
quantity = qty
static var PICKUP_DIALOGUE:DialogueResource = preload("res://dialogue/item/pickup.dialogue")
static func itemGetCallable(params:Dictionary) -> int:
assert(params.has('stack'))
PARTY.BACKPACK.addStack(params['stack'])
var text = "Obtained %s x%d." % [Item.getItemName(params['stack'].item), params['stack'].quantity]
params['cutscene'].addCallable(ConversationAction.getTextboxCallable(text).merged({
'position': Cutscene.CUTSCENE_ADD_NEXT,
}))
var stack:ItemStack = params['stack']
PARTY.BACKPACK.addStack(stack)
var state = ItemDialogueState.new(Item.getItemName(stack.item), stack.quantity)
var dialogueParams:Dictionary = DialogueAction.getDialogueCallable(PICKUP_DIALOGUE, 'start', [state])
dialogueParams['position'] = Cutscene.CUTSCENE_ADD_NEXT
params['cutscene'].addCallable(dialogueParams)
return Cutscene.CUTSCENE_CONTINUE
static func getItemCallable(itemStack:ItemStack) -> Dictionary:
return {
"function": itemGetCallable,
"stack": itemStack
'function': itemGetCallable,
'stack': itemStack,
}