Extensive work on VFX for the guild, assets for the world, and portrait variance. Work on quests. Extra work on User Flow completion and file saving.
This commit is contained in:
270
data/quests/quest.gd
Normal file
270
data/quests/quest.gd
Normal file
@@ -0,0 +1,270 @@
|
||||
class_name Quest extends Resource
|
||||
|
||||
|
||||
|
||||
|
||||
enum Status{
|
||||
OPEN,
|
||||
TAKEN,
|
||||
IN_PROGRESS,
|
||||
COMPLETED,
|
||||
FAILED,
|
||||
CLOSED
|
||||
}
|
||||
|
||||
enum Locations{
|
||||
NESTORS_WOODS
|
||||
}
|
||||
|
||||
class Event:
|
||||
var enemy_types: Dictionary[String, PackedScene] = {
|
||||
"goo": preload("res://templates/enemies/goo.tscn")
|
||||
}
|
||||
enum Type{
|
||||
WAIT,
|
||||
COMBAT,
|
||||
CHOICE
|
||||
}
|
||||
|
||||
enum CombatState{
|
||||
FIGHTING,
|
||||
VICTORY,
|
||||
DEFEAT
|
||||
}
|
||||
var type : Type = Type.WAIT
|
||||
var enemies : Array[String] = []
|
||||
var time : float = 1
|
||||
var time_elapsed
|
||||
signal completed()
|
||||
signal failed()
|
||||
|
||||
var participants : Array = []
|
||||
var turn_queue : Array = []
|
||||
var busy_list : Array = []
|
||||
var combat_state
|
||||
var dex_speed : int
|
||||
func start(quest : Quest) -> void:
|
||||
match(type):
|
||||
Type.WAIT:
|
||||
return
|
||||
Type.COMBAT:
|
||||
combat_state = CombatState.FIGHTING
|
||||
var enemy_list = []
|
||||
for enemy_name in enemies:
|
||||
enemy_list.append(enemy_types[enemy_name].instantiate())
|
||||
quest.questview.set_questor_animation("idle")
|
||||
for enemy in enemy_list:
|
||||
quest.questview.pause_setting()
|
||||
quest.questview.place_enemy(enemy)
|
||||
quest.questview.set_enemy_animation(enemy, "idle")
|
||||
start_combat([quest.questor.quest_sprite], enemy_list)
|
||||
|
||||
func start_combat(adventurers : Array, enemies : Array) -> void:
|
||||
participants = []
|
||||
participants.append_array(adventurers)
|
||||
participants.append_array(enemies)
|
||||
|
||||
var c_order : Array = []
|
||||
var dex_speed = 0
|
||||
for p in participants:
|
||||
c_order.append([p, p.stats.DEX])
|
||||
if p.stats.DEX > dex_speed:
|
||||
dex_speed = p.stats.DEX
|
||||
|
||||
c_order.sort_custom(func(a,b): return a[1] > b[1])
|
||||
var delay = 5
|
||||
var last_time = 0
|
||||
for c in c_order:
|
||||
c[0].busy.connect(_on_busy.bind(c[0]))
|
||||
c[0].action_complete.connect(_on_combat_action_complete.bind(c[0]))
|
||||
c[0].died.connect(_on_death.bind(c[0]))
|
||||
var time = delay * dex_speed
|
||||
if c[1] != 0:
|
||||
time = delay * dex_speed / c[1]
|
||||
turn_queue.append({"combatant":c[0], "time": time - last_time})
|
||||
last_time = time
|
||||
|
||||
func execute_attack(combatant : QuestSprite, target : QuestSprite) -> void:
|
||||
var tween = combatant.create_tween()
|
||||
tween.tween_interval(.25)
|
||||
tween.tween_callback(combatant.attack.bind(target))
|
||||
|
||||
func add_to_turn_queue(combatant) -> void:
|
||||
#Calculate time
|
||||
var time = dex_speed / combatant.stats.DEX
|
||||
#Walk through list to find insertion point
|
||||
var idx = -1
|
||||
for i in range(len(turn_queue)):
|
||||
if turn_queue[i].time > time:
|
||||
idx = i
|
||||
break
|
||||
else:
|
||||
time -= turn_queue[i].time
|
||||
var entry = {"combatant":combatant, "time":time}
|
||||
if idx == -1:
|
||||
turn_queue.append(entry)
|
||||
else:
|
||||
turn_queue[idx].time -= time
|
||||
turn_queue.insert(idx,entry)
|
||||
|
||||
func _on_busy(combatant : QuestSprite) -> void:
|
||||
busy_list.append(combatant)
|
||||
|
||||
func _on_death(killer : QuestSprite, combatant : QuestSprite) -> void:
|
||||
busy_list.erase(combatant)
|
||||
remove_from_queue(combatant)
|
||||
participants.erase(combatant)
|
||||
if killer != combatant:
|
||||
var xp = Game.calculate_kill_exp(killer, combatant)
|
||||
print("%s has earned %d exp" % [killer.name, xp])
|
||||
killer.exp += xp
|
||||
var enemy_list : Array = get_enemy_list(killer)
|
||||
if len(enemy_list) == 0:
|
||||
if killer is QuestorSprite:
|
||||
victory()
|
||||
else:
|
||||
defeat()
|
||||
|
||||
func victory():
|
||||
print("Questor won!")
|
||||
combat_state = CombatState.VICTORY
|
||||
for p : QuestorSprite in participants:
|
||||
p.check_levelup()
|
||||
#TODO: Notify player if level up occurs
|
||||
time = 5
|
||||
|
||||
func defeat():
|
||||
print("Questor lost!")
|
||||
combat_state = CombatState.DEFEAT
|
||||
failed.emit()
|
||||
|
||||
func remove_from_queue(combatant : QuestSprite) -> void:
|
||||
var idx = -1
|
||||
for i in range(len(turn_queue)):
|
||||
if turn_queue[i].combatant == combatant:
|
||||
idx = i
|
||||
break
|
||||
if idx != -1:
|
||||
turn_queue.remove_at(idx)
|
||||
else:
|
||||
printerr("Tried to remove someone not in the turn queue")
|
||||
|
||||
func _on_combat_action_complete(requeue : bool, combatant : QuestSprite) -> void:
|
||||
busy_list.erase(combatant)
|
||||
if requeue:
|
||||
add_to_turn_queue(combatant)
|
||||
|
||||
func execute_action(combatant) -> void:
|
||||
busy_list = [combatant]
|
||||
#TODO: Come up with other options than just swinging at each other
|
||||
var enemies : Array = get_enemy_list(combatant)
|
||||
var target = enemies.pick_random()
|
||||
execute_attack(combatant, target)
|
||||
|
||||
func get_enemy_list(combatant) -> Array:
|
||||
var lst = []
|
||||
for p in participants:
|
||||
if p != combatant:
|
||||
lst.append(p)
|
||||
return lst
|
||||
|
||||
func resolve_combat() -> void:
|
||||
pass
|
||||
|
||||
func process(delta : float) -> void:
|
||||
#TODO: Make quest combat work
|
||||
match(type):
|
||||
Type.COMBAT:
|
||||
match(combat_state):
|
||||
CombatState.FIGHTING:
|
||||
if len(busy_list) < 1:
|
||||
if len(turn_queue) > 0:
|
||||
turn_queue[0].time -= delta
|
||||
if turn_queue[0].time <= 0:
|
||||
var c = turn_queue.pop_front()
|
||||
print("%s taking a turn!" % [c.combatant.name])
|
||||
if len(turn_queue) > 0:
|
||||
turn_queue[0].time += c.time
|
||||
execute_action(c.combatant)
|
||||
else:
|
||||
resolve_combat()
|
||||
CombatState.VICTORY:
|
||||
time_elapsed += delta
|
||||
if time_elapsed >= time:
|
||||
completed.emit()
|
||||
Type.WAIT:
|
||||
time_elapsed += delta
|
||||
if time_elapsed >= time:
|
||||
completed.emit()
|
||||
|
||||
var name : String = "A Basic Quest"
|
||||
var desc : String = "The default quest, with no special anything."
|
||||
var difficulty : int = 1
|
||||
var location : Locations
|
||||
var steps : int = 1
|
||||
var rewards : Dictionary
|
||||
var guild_rewards : Dictionary
|
||||
var covenant_cost : int = 1
|
||||
var length : float = 10
|
||||
var events : Array[Event] = []
|
||||
|
||||
|
||||
var progress : float = 0
|
||||
var current_step : int = 0
|
||||
var taken : bool = false
|
||||
var status : Status = Status.OPEN
|
||||
var questview : QuestView = null
|
||||
|
||||
var questor : Adventurer = null
|
||||
signal status_changed(status : Status)
|
||||
|
||||
func _init() -> void:
|
||||
pass
|
||||
|
||||
func initiate(member : Adventurer) -> void:
|
||||
questor = member
|
||||
status = Status.TAKEN
|
||||
status_changed.emit(Status.TAKEN)
|
||||
|
||||
func fail() -> void:
|
||||
status = Status.FAILED
|
||||
status_changed.emit(Status.FAILED)
|
||||
|
||||
func complete() -> void:
|
||||
status = Status.COMPLETED
|
||||
status_changed.emit(Status.COMPLETED)
|
||||
for reward in rewards.keys():
|
||||
if reward == "gold":
|
||||
questor.gain_gold(rewards[reward])
|
||||
elif reward == "exp":
|
||||
questor.gain_exp(rewards[reward])
|
||||
#TODO: Implement other reward types
|
||||
#elif rewards[reward] is Item:
|
||||
# questor.gain_item()
|
||||
#else it's a guild item they'll bring back for us
|
||||
Game.notice("%s completed the quest '%s'!" % [questor.full_name(), name])
|
||||
|
||||
func num_events() -> int:
|
||||
return len(events)
|
||||
|
||||
#TODO: Put in quest requirements
|
||||
func is_eligible(member : Adventurer) -> bool:
|
||||
return !taken
|
||||
|
||||
func is_taken() -> bool:
|
||||
return status == Status.TAKEN
|
||||
|
||||
func location_name() -> String:
|
||||
match(location):
|
||||
Locations.NESTORS_WOODS: return "Nestor's Woods"
|
||||
return "ERROR"
|
||||
|
||||
func difficulty_name() -> String:
|
||||
match(difficulty):
|
||||
0: return "None"
|
||||
1: return "Trivial"
|
||||
2: return "Moderate"
|
||||
3: return "Severe"
|
||||
4: return "Extreme"
|
||||
5: return "Legendary"
|
||||
_: return "Unknown"
|
||||
Reference in New Issue
Block a user