Some changes
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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,
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://cnljqhsjcowen
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user