Extensive work on the sideview and initial work on player profiles, inventory display, and renaming adventurerdata vs adventurer to adventurer vs adventurersprite
This commit is contained in:
@@ -1,74 +1,74 @@
|
||||
class_name Adventurer extends Npc
|
||||
class_name Adventurer extends Node
|
||||
|
||||
func _ready() -> void:
|
||||
nav_agent.navigation_finished.connect(_on_nav_agent_finished)
|
||||
pass
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
if nav_agent.is_navigation_finished():
|
||||
if interaction_target:
|
||||
try_interact(interaction_target)
|
||||
#If they have an interaction target within range
|
||||
#clear the target
|
||||
#try_interact
|
||||
enum Gender{
|
||||
MASC,
|
||||
FEMME,
|
||||
NONBINARY
|
||||
}
|
||||
|
||||
var given_name : String = "Test"
|
||||
var surname : String = "Testing"
|
||||
var gender : Gender = Gender.MASC
|
||||
var life : int = 1
|
||||
var max_life : int = 1
|
||||
var energy : int = 1
|
||||
var max_energy : int = 1
|
||||
var level : int = 1
|
||||
var exp : int = 0
|
||||
var job : JobData
|
||||
var stats : StatBlock
|
||||
var gold : int = 0
|
||||
var quest : Quest
|
||||
var weapon : Weapon
|
||||
var armor : Armor
|
||||
var accessory : Accessory
|
||||
var inventory : Dictionary[Vector2, Item] = {}
|
||||
var inventory_size : Vector2i = Vector2i(6,1)
|
||||
|
||||
var quest_sprite : QuestSprite
|
||||
|
||||
func _init() -> void:
|
||||
stats = StatBlock.new()
|
||||
|
||||
func generate() -> void:
|
||||
if job == null:
|
||||
return
|
||||
var curr_pos: Vector2 = global_position
|
||||
var next_path_pos: Vector2 = nav_agent.get_next_path_position()
|
||||
stats.STR = randi_range(job.min_STR, job.max_STR)
|
||||
stats.DEX = randi_range(job.min_DEX, job.max_DEX)
|
||||
stats.INT = randi_range(job.min_INT, job.max_INT)
|
||||
stats.CHA = randi_range(job.min_CHA, job.max_CHA)
|
||||
stats.FAI = randi_range(job.min_FAI, job.max_FAI)
|
||||
stats.LUK = randi_range(job.min_LUK, job.max_LUK)
|
||||
|
||||
velocity = curr_pos.direction_to(next_path_pos) * movement_speed
|
||||
move_and_slide()
|
||||
#If they virtually didn't move
|
||||
if !stuck:
|
||||
if (global_position - last_position).length_squared() < 5:
|
||||
stuck = true
|
||||
stuck_time_remaining = 1
|
||||
max_life = stats.STR * 10 + stats.CHA * 10
|
||||
max_energy = stats.INT * 10 + stats.FAI * 10
|
||||
life = max_life
|
||||
energy = max_energy
|
||||
|
||||
func assign_quest(quest : Quest) -> void:
|
||||
self.quest = quest
|
||||
quest.initiate(self)
|
||||
|
||||
func full_name() -> String:
|
||||
return given_name + " " + surname
|
||||
|
||||
func gain_level() -> void:
|
||||
level += 1
|
||||
#TODO: Make stats improve based on job
|
||||
Game.notice("%s has reached level %d!" % [full_name(), level])
|
||||
|
||||
func gain_exp(amount : int) -> void:
|
||||
exp += amount
|
||||
while exp >= get_tnl():
|
||||
exp -= get_tnl()
|
||||
gain_level()
|
||||
|
||||
func gain_gold(amount :int) -> void:
|
||||
gold += amount
|
||||
|
||||
func get_tnl() -> int:
|
||||
if job:
|
||||
return job.get_tnl(level)
|
||||
else:
|
||||
if stuck_time_remaining > 0:
|
||||
stuck_time_remaining -= delta
|
||||
if stuck_time_remaining <= 0:
|
||||
nav_agent.target_position = global_position
|
||||
navigation_failed.emit()
|
||||
last_position = global_position
|
||||
|
||||
func approach(pos : Vector2) -> void:
|
||||
stuck = false
|
||||
var rid = get_world_2d().get_navigation_map()
|
||||
var point : Vector2 = NavigationServer2D.map_get_closest_point(rid, pos)
|
||||
set_movement_target(point)
|
||||
|
||||
func approach_and_interact(obj : Interactable) -> void:
|
||||
set_movement_target(obj.global_position)
|
||||
nav_agent.target_desired_distance = interaction_range - 5
|
||||
interaction_target = obj
|
||||
|
||||
func try_interact(obj : Interactable) -> void:
|
||||
var df = obj.global_position - global_position
|
||||
if df.length() > interaction_range:
|
||||
approach_and_interact(obj)
|
||||
else:
|
||||
interact(obj)
|
||||
interaction_target = null
|
||||
|
||||
func interact(obj : Interactable) -> void:
|
||||
obj.interact(self)
|
||||
|
||||
func set_movement_target(target : Vector2) -> void:
|
||||
nav_agent.target_position = target
|
||||
|
||||
func show_speech_bubble(bubble_type : String) -> void:
|
||||
bubble.try_show_speech(bubble_type)
|
||||
|
||||
|
||||
|
||||
func _on_nav_agent_finished() -> void:
|
||||
navigation_finished.emit()
|
||||
|
||||
|
||||
func _on_mouse_entered() -> void:
|
||||
profile_popup = popup_template.instantiate()
|
||||
add_child(profile_popup)
|
||||
profile_popup.setup(data.name, data.level, data.job.name, activity)
|
||||
|
||||
|
||||
func _on_mouse_exited() -> void:
|
||||
profile_popup.queue_free()
|
||||
return level * 10
|
||||
|
||||
@@ -1 +1 @@
|
||||
uid://cjqumk0kw2vte
|
||||
uid://0jl2qbvtmsik
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
class_name AdventurerData extends Node
|
||||
|
||||
class StatBlock:
|
||||
var STR : int = 1
|
||||
var DEX : int = 1
|
||||
var INT : int = 1
|
||||
var CHA : int = 1
|
||||
var FAI : int = 1
|
||||
var LUK : int = 1
|
||||
|
||||
enum Gender{
|
||||
MASC,
|
||||
FEMME,
|
||||
NONBINARY
|
||||
}
|
||||
|
||||
var given_name : String = "Test"
|
||||
var surname : String = "Testing"
|
||||
var gender : Gender = Gender.MASC
|
||||
var life : int = 1
|
||||
var max_life : int = 1
|
||||
var energy : int = 1
|
||||
var max_energy : int = 1
|
||||
var level : int = 1
|
||||
var exp : int = 0
|
||||
var job : JobData
|
||||
var stats : StatBlock
|
||||
var gold : int = 0
|
||||
var quest : Quest
|
||||
var weapon : Weapon
|
||||
var armor : Armor
|
||||
var accessory : Accessory
|
||||
var inventory : Dictionary[Vector2, Item] = {}
|
||||
var inventory_size : Vector2i = Vector2i(6,1)
|
||||
func _init() -> void:
|
||||
stats = StatBlock.new()
|
||||
|
||||
func generate() -> void:
|
||||
if job == null:
|
||||
return
|
||||
stats.STR = randi_range(job.min_STR, job.max_STR)
|
||||
stats.DEX = randi_range(job.min_DEX, job.max_DEX)
|
||||
stats.INT = randi_range(job.min_INT, job.max_INT)
|
||||
stats.CHA = randi_range(job.min_CHA, job.max_CHA)
|
||||
stats.FAI = randi_range(job.min_FAI, job.max_FAI)
|
||||
stats.LUK = randi_range(job.min_LUK, job.max_LUK)
|
||||
|
||||
max_life = stats.STR * 10 + stats.CHA * 10
|
||||
max_energy = stats.INT * 10 + stats.FAI * 10
|
||||
life = max_life
|
||||
energy = max_energy
|
||||
|
||||
func assign_quest(quest : Quest) -> void:
|
||||
self.quest = quest
|
||||
quest.initiate(self)
|
||||
|
||||
func full_name() -> String:
|
||||
return given_name + " " + surname
|
||||
|
||||
func gain_level() -> void:
|
||||
level += 1
|
||||
#TODO: Make stats improve based on job
|
||||
Game.notice("%s has reached level %d!" % [full_name(), level])
|
||||
|
||||
func gain_exp(amount : int) -> void:
|
||||
exp += amount
|
||||
while exp >= get_tnl():
|
||||
exp -= get_tnl()
|
||||
gain_level()
|
||||
|
||||
func gain_gold(amount :int) -> void:
|
||||
gold += amount
|
||||
|
||||
func get_tnl() -> int:
|
||||
if job:
|
||||
return job.get_tnl(level)
|
||||
else:
|
||||
return level * 10
|
||||
@@ -1 +0,0 @@
|
||||
uid://0jl2qbvtmsik
|
||||
40
scripts/adventurer_profile_window.gd
Normal file
40
scripts/adventurer_profile_window.gd
Normal file
@@ -0,0 +1,40 @@
|
||||
class_name AdventurerProfileWindow extends ProfileWindow
|
||||
|
||||
var data : Adventurer
|
||||
@onready var nameLabel = %NameLabel
|
||||
@onready var jobLabel = %JobLabel
|
||||
@onready var expLabel : Label = %ExpLabel
|
||||
@onready var levelLabel :Label = %LevelLabel
|
||||
@onready var lifeLabel :Label = %LifeLabel
|
||||
@onready var energyLabel :Label = %EnergyLabel
|
||||
|
||||
@onready var strLabel :Label = %STRLabel
|
||||
@onready var dexLabel :Label = %DEXLabel
|
||||
@onready var intLabel :Label = %INTLabel
|
||||
@onready var chaLabel :Label = %CHALabel
|
||||
@onready var faiLabel :Label = %FAILabel
|
||||
@onready var lukLabel :Label = %LUKLabel
|
||||
|
||||
|
||||
func setup(adv : Adventurer) -> void:
|
||||
data = adv
|
||||
nameLabel.text = data.full_name()
|
||||
if data.job:
|
||||
jobLabel.text = data.job.name
|
||||
else:
|
||||
jobLabel.text = "ERROR"
|
||||
levelLabel.text = str(data.level)
|
||||
expLabel.text = "Exp: %d/%d" % [data.exp, data.get_tnl()]
|
||||
lifeLabel.text = "Life: " + str(data.life) + "/" + str(data.max_life)
|
||||
energyLabel.text = "Energy: " + str(data.energy) + "/" + str(data.max_energy)
|
||||
strLabel.text = str(data.stats.STR)
|
||||
dexLabel.text = str(data.stats.DEX)
|
||||
intLabel.text = str(data.stats.INT)
|
||||
chaLabel.text = str(data.stats.CHA)
|
||||
faiLabel.text = str(data.stats.FAI)
|
||||
lukLabel.text = str(data.stats.LUK)
|
||||
#TODO: Show equipment
|
||||
populate_items()
|
||||
|
||||
func populate_items() -> void:
|
||||
pass
|
||||
1
scripts/adventurer_profile_window.gd.uid
Normal file
1
scripts/adventurer_profile_window.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://c0adqs12cwkkc
|
||||
74
scripts/adventurer_sprite.gd
Normal file
74
scripts/adventurer_sprite.gd
Normal file
@@ -0,0 +1,74 @@
|
||||
class_name AdventurerSprite extends Npc
|
||||
|
||||
func _ready() -> void:
|
||||
nav_agent.navigation_finished.connect(_on_nav_agent_finished)
|
||||
pass
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
if nav_agent.is_navigation_finished():
|
||||
if interaction_target:
|
||||
try_interact(interaction_target)
|
||||
#If they have an interaction target within range
|
||||
#clear the target
|
||||
#try_interact
|
||||
return
|
||||
var curr_pos: Vector2 = global_position
|
||||
var next_path_pos: Vector2 = nav_agent.get_next_path_position()
|
||||
|
||||
velocity = curr_pos.direction_to(next_path_pos) * movement_speed
|
||||
move_and_slide()
|
||||
#If they virtually didn't move
|
||||
if !stuck:
|
||||
if (global_position - last_position).length_squared() < 5:
|
||||
stuck = true
|
||||
stuck_time_remaining = 1
|
||||
else:
|
||||
if stuck_time_remaining > 0:
|
||||
stuck_time_remaining -= delta
|
||||
if stuck_time_remaining <= 0:
|
||||
nav_agent.target_position = global_position
|
||||
navigation_failed.emit()
|
||||
last_position = global_position
|
||||
|
||||
func approach(pos : Vector2) -> void:
|
||||
stuck = false
|
||||
var rid = get_world_2d().get_navigation_map()
|
||||
var point : Vector2 = NavigationServer2D.map_get_closest_point(rid, pos)
|
||||
set_movement_target(point)
|
||||
|
||||
func approach_and_interact(obj : Interactable) -> void:
|
||||
set_movement_target(obj.global_position)
|
||||
nav_agent.target_desired_distance = interaction_range - 5
|
||||
interaction_target = obj
|
||||
|
||||
func try_interact(obj : Interactable) -> void:
|
||||
var df = obj.global_position - global_position
|
||||
if df.length() > interaction_range:
|
||||
approach_and_interact(obj)
|
||||
else:
|
||||
interact(obj)
|
||||
interaction_target = null
|
||||
|
||||
func interact(obj : Interactable) -> void:
|
||||
obj.interact(self)
|
||||
|
||||
func set_movement_target(target : Vector2) -> void:
|
||||
nav_agent.target_position = target
|
||||
|
||||
func show_speech_bubble(bubble_type : String) -> void:
|
||||
bubble.try_show_speech(bubble_type)
|
||||
|
||||
|
||||
|
||||
func _on_nav_agent_finished() -> void:
|
||||
navigation_finished.emit()
|
||||
|
||||
|
||||
func _on_mouse_entered() -> void:
|
||||
profile_popup = popup_template.instantiate()
|
||||
add_child(profile_popup)
|
||||
profile_popup.setup(data.name, data.level, data.job.name, activity)
|
||||
|
||||
|
||||
func _on_mouse_exited() -> void:
|
||||
profile_popup.queue_free()
|
||||
1
scripts/adventurer_sprite.gd.uid
Normal file
1
scripts/adventurer_sprite.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cjqumk0kw2vte
|
||||
7
scripts/enemy.gd
Normal file
7
scripts/enemy.gd
Normal file
@@ -0,0 +1,7 @@
|
||||
class_name Enemy extends QuestSprite
|
||||
|
||||
|
||||
|
||||
|
||||
func set_animation(anim_name : String) -> void:
|
||||
anim_player.play(anim_name)
|
||||
1
scripts/enemy.gd.uid
Normal file
1
scripts/enemy.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://fxixa11vqdrn
|
||||
@@ -2,19 +2,26 @@ extends Node
|
||||
|
||||
var player : Player = null
|
||||
var panel : GamePanel = null
|
||||
var player_profile : Window = null
|
||||
var quest_log : QuestLog = null
|
||||
var top_menu : TopMenu = null
|
||||
var active : bool = true
|
||||
var open : bool = true
|
||||
var end_shift_confirmation : ConfirmationDialog
|
||||
var end_shift_confirm_template = preload("res://templates/end_shift_confirmation.tscn")
|
||||
var player_profile_template = preload("res://templates/player_profile_window.tscn")
|
||||
|
||||
func _ready() -> void:
|
||||
DisplayServer.register_additional_output(self)
|
||||
end_shift_confirmation = end_shift_confirm_template.instantiate()
|
||||
add_child(end_shift_confirmation)
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if active and Input.is_action_just_pressed("switch modes"):
|
||||
confirm_end_shift()
|
||||
if open:
|
||||
if Input.is_action_just_pressed("profile"):
|
||||
toggle_player_profile()
|
||||
if Input.is_action_just_pressed("switch modes"):
|
||||
confirm_end_shift()
|
||||
|
||||
|
||||
func add_quest_progress_bar(quest : Quest) -> void:
|
||||
panel.add_quest_progress_bar(quest)
|
||||
@@ -25,10 +32,22 @@ func confirm_end_shift() -> void:
|
||||
func setup_visitor_ui(spawner: VisitorSpawner)-> void:
|
||||
if panel:
|
||||
panel.connect_visitor_spawner(spawner)
|
||||
|
||||
func toggle_player_profile():
|
||||
if player_profile != null:
|
||||
player_profile.queue_free()
|
||||
player_profile = null
|
||||
else:
|
||||
player_profile = player_profile_template.instantiate()
|
||||
add_child(player_profile)
|
||||
player_profile.setup(player.data)
|
||||
|
||||
|
||||
func end_shift() -> void:
|
||||
active = false
|
||||
panel.switch_panel(active)
|
||||
open = false
|
||||
if player_profile != null:
|
||||
toggle_player_profile()
|
||||
panel.switch_panel(open)
|
||||
var window = get_window()
|
||||
window.mode = Window.MODE_WINDOWED
|
||||
var size = DisplayServer.screen_get_size()
|
||||
@@ -45,7 +64,11 @@ func end_shift() -> void:
|
||||
top_menu.hide()
|
||||
panel.get_parent().global_position = Vector2i(5,5)
|
||||
window.size = Vector2i(415,700)
|
||||
panel.populate_quest_views()
|
||||
panel.populate_quest_bars()
|
||||
|
||||
func notice(msg : String, time : float = 1) -> void:
|
||||
panel.notice(msg, time)
|
||||
|
||||
func calculate_kill_exp(killer : QuestSprite, killed : QuestSprite) -> int:
|
||||
return clamp(1, (killed.level - killer.level) * 5, 100)
|
||||
|
||||
@@ -20,7 +20,7 @@ const job_list = [
|
||||
|
||||
var jobs : Dictionary[String, JobData] = {}
|
||||
|
||||
var members : Array[AdventurerData] = []
|
||||
var members : Array[Adventurer] = []
|
||||
var quests : Dictionary[Quest,bool] = {}
|
||||
var hall : Guildhall = null
|
||||
var visitor_spawner : VisitorSpawner = null
|
||||
@@ -55,14 +55,14 @@ func _ready() -> void:
|
||||
for job : JobData in job_list:
|
||||
jobs[job.name] = job
|
||||
|
||||
func register_guild_member(member : AdventurerData, first : bool = false) -> void:
|
||||
func register_guild_member(member : Adventurer, first : bool = false) -> void:
|
||||
members.append(member)
|
||||
Game.top_menu.add_member(member)
|
||||
changed.emit()
|
||||
if first:
|
||||
Game.notice("%s has joined the guild!" % member.name, 5)
|
||||
|
||||
func has_guild_member(member : AdventurerData) -> bool:
|
||||
func has_guild_member(member : Adventurer) -> bool:
|
||||
if member == null:
|
||||
return false
|
||||
return members.has(member)
|
||||
@@ -72,13 +72,13 @@ func add_quest(quest : Quest) -> void:
|
||||
Game.top_menu.add_quest(quest)
|
||||
#Game.quest_log.add_entry(quest)
|
||||
|
||||
func assign_quest(member : AdventurerData, quest : Quest) -> void:
|
||||
func assign_quest(member : Adventurer, quest : Quest) -> void:
|
||||
member.assign_quest(quest)
|
||||
quests[quest] = true #Mark it as active
|
||||
|
||||
func spawn_visitor(pos : Vector2) -> void:
|
||||
var data : AdventurerData = visitors["test"].data.instantiate()
|
||||
var sprite : Adventurer = visitors["test"].sprite.instantiate()
|
||||
var data : Adventurer = visitors["test"].data.instantiate()
|
||||
var sprite : AdventurerSprite = visitors["test"].sprite.instantiate()
|
||||
var r = randf()
|
||||
if r > 0.8:
|
||||
data.gender = 2 #Nonbinary
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
class_name GuildEmployee extends Adventurer
|
||||
class_name GuildEmployee extends AdventurerSprite
|
||||
|
||||
@export var speech :String
|
||||
@onready var queue : GuildQueue = $Queue
|
||||
|
||||
@@ -4,27 +4,27 @@ var length : int :
|
||||
get:
|
||||
return len(members)
|
||||
@export var direction : Vector2 = Vector2.ZERO
|
||||
var members : Array[Adventurer] = []
|
||||
var members : Array[AdventurerSprite] = []
|
||||
|
||||
var front : Adventurer :
|
||||
var front : AdventurerSprite :
|
||||
get: return null if len(members) == 0 else members[0]
|
||||
|
||||
signal advanced()
|
||||
|
||||
func add_member(member : Adventurer) -> void:
|
||||
func add_member(member : AdventurerSprite) -> void:
|
||||
members.append(member)
|
||||
|
||||
func remove_member(member : Adventurer) -> void:
|
||||
func remove_member(member : AdventurerSprite) -> void:
|
||||
members.erase(member)
|
||||
|
||||
|
||||
func try_advance() -> Adventurer:
|
||||
func try_advance() -> AdventurerSprite:
|
||||
if length > 0:
|
||||
return advance()
|
||||
else:
|
||||
return null
|
||||
|
||||
func advance() -> Adventurer:
|
||||
func advance() -> AdventurerSprite:
|
||||
advanced.emit()
|
||||
return front
|
||||
|
||||
|
||||
@@ -19,5 +19,5 @@ func register_employee(employee: GuildEmployee) -> void:
|
||||
func register_interactables(equipment: Interactable) -> void:
|
||||
interactables[equipment.name] = equipment
|
||||
|
||||
func add_sprite(sprite : Adventurer) -> void:
|
||||
func add_sprite(sprite : AdventurerSprite) -> void:
|
||||
sprite_node.add_child(sprite)
|
||||
|
||||
@@ -1,10 +1,20 @@
|
||||
extends Control
|
||||
class_name ItemSlot extends Control
|
||||
|
||||
#var item_display_window_template = preload("res://templates/item_display_window.tscn")
|
||||
var dragging : bool = false
|
||||
var last_click : int = 0
|
||||
var item : Item
|
||||
@onready var item_sprite : TextureRect = $Item
|
||||
|
||||
func assign(itm : Item) -> void:
|
||||
item = item
|
||||
item_sprite.texture = item.image
|
||||
|
||||
func swap(item_slot : ItemSlot) -> void:
|
||||
var itm = item
|
||||
assign(itm)
|
||||
item_slot.assign(itm)
|
||||
|
||||
func _on_gui_input(event: InputEvent) -> void:
|
||||
var mmevt = event as InputEventMouseMotion
|
||||
var mbevt = event as InputEventMouseButton
|
||||
|
||||
@@ -2,6 +2,7 @@ class_name GamePanel extends MarginContainer
|
||||
|
||||
const notice_template = preload("res://templates/notice_panel.tscn")
|
||||
const quest_progress_bar_template = preload("res://templates/quest_progress_bar.tscn")
|
||||
const quest_view_template = preload("res://templates/quest_view.tscn")
|
||||
|
||||
signal time_changed(time : float)
|
||||
|
||||
@@ -18,12 +19,20 @@ func add_quest_progress_bar(quest : Quest) -> void:
|
||||
var qpb : QuestProgressBar = quest_progress_bar_template.instantiate()
|
||||
%QuestList.add_child(qpb)
|
||||
qpb.setup(quest)
|
||||
|
||||
#TODO: Change the hero portrait to match
|
||||
if quest.steps > 1:
|
||||
for i in range(quest.steps-1):
|
||||
qpb.add_waypoint(float(i) / quest.steps, quest.step_messages[i])
|
||||
|
||||
|
||||
func add_quest_view(quest : Quest, visible : bool) -> void:
|
||||
var qv : QuestView = quest_view_template.instantiate()
|
||||
qv.visible = visible
|
||||
%QuestView.add_child(qv)
|
||||
qv.setup(quest)
|
||||
|
||||
|
||||
func switch_panel(active : bool) -> void:
|
||||
%OpenShift.visible = active
|
||||
%WorkingShift.visible = !active
|
||||
@@ -47,6 +56,14 @@ func connect_visitor_spawner(spawner : VisitorSpawner) -> void:
|
||||
func update_visitor_count(current : int, total : int) -> void:
|
||||
%OpenList/VisitorsLabel.text = "Visitors: %d/%d" % [current, total]
|
||||
|
||||
func populate_quest_views() -> void:
|
||||
var count : int = 0
|
||||
for quest in Guild.quests:
|
||||
if quest.is_taken():
|
||||
count+=1
|
||||
add_quest_view(quest, count == 1)
|
||||
%QuestViewerButton.disabled = (count == 0)
|
||||
|
||||
func populate_quest_bars() -> void:
|
||||
|
||||
var count : int = 0
|
||||
@@ -64,6 +81,7 @@ func notice(msg : String, time : float) -> void:
|
||||
|
||||
var dragging : bool = false
|
||||
var drag_pos : Vector2
|
||||
|
||||
func _on_drag_region_gui_input(event: InputEvent) -> void:
|
||||
if event is InputEventMouseButton:
|
||||
if event.button_index == MOUSE_BUTTON_LEFT:
|
||||
|
||||
@@ -8,7 +8,7 @@ var enabled: bool:
|
||||
set(value):
|
||||
enable(value)
|
||||
|
||||
var data : AdventurerData
|
||||
var data : Adventurer
|
||||
|
||||
|
||||
func enable(en: bool) -> void:
|
||||
@@ -18,7 +18,7 @@ func enable(en: bool) -> void:
|
||||
else:
|
||||
mouse_filter=Control.MOUSE_FILTER_IGNORE
|
||||
|
||||
func setup(member : AdventurerData) -> void:
|
||||
func setup(member : Adventurer) -> void:
|
||||
data = member
|
||||
%NameLabel.text = data.given_name + " " + data.surname
|
||||
%LevelLabel.text = str(data.level)
|
||||
|
||||
@@ -9,7 +9,7 @@ var profile_popup
|
||||
@onready var movement_target_position : Vector2 = global_position
|
||||
@onready var nav_agent : NavigationAgent2D = $NavigationAgent2D
|
||||
|
||||
var data : AdventurerData = null
|
||||
var data : Adventurer = null
|
||||
var interaction_target = null
|
||||
var last_position : Vector2 = Vector2.ZERO
|
||||
var stuck : bool = false
|
||||
|
||||
@@ -1,49 +1 @@
|
||||
extends Window
|
||||
|
||||
var dragging : bool = false
|
||||
var data : AdventurerData
|
||||
@onready var nameLabel = %NameLabel
|
||||
@onready var jobLabel = %JobLabel
|
||||
@onready var expLabel : Label = %ExpLabel
|
||||
@onready var levelLabel :Label = %LevelLabel
|
||||
@onready var lifeLabel :Label = %LifeLabel
|
||||
@onready var energyLabel :Label = %EnergyLabel
|
||||
|
||||
@onready var strLabel :Label = %STRLabel
|
||||
@onready var dexLabel :Label = %DEXLabel
|
||||
@onready var intLabel :Label = %INTLabel
|
||||
@onready var chaLabel :Label = %CHALabel
|
||||
@onready var faiLabel :Label = %FAILabel
|
||||
@onready var lukLabel :Label = %LUKLabel
|
||||
|
||||
|
||||
func setup(adv : AdventurerData) -> void:
|
||||
data = adv
|
||||
nameLabel.text = data.full_name()
|
||||
if data.job:
|
||||
jobLabel.text = data.job.name
|
||||
else:
|
||||
jobLabel.text = "ERROR"
|
||||
levelLabel.text = str(data.level)
|
||||
expLabel.text = "Exp: %d/%d" % [data.exp, data.get_tnl()]
|
||||
lifeLabel.text = "Life: " + str(data.life) + "/" + str(data.max_life)
|
||||
energyLabel.text = "Energy: " + str(data.energy) + "/" + str(data.max_energy)
|
||||
strLabel.text = str(data.stats.STR)
|
||||
dexLabel.text = str(data.stats.DEX)
|
||||
intLabel.text = str(data.stats.INT)
|
||||
chaLabel.text = str(data.stats.CHA)
|
||||
faiLabel.text = str(data.stats.FAI)
|
||||
lukLabel.text = str(data.stats.LUK)
|
||||
#TODO: Show equipment
|
||||
|
||||
func _on_close_requested() -> void:
|
||||
queue_free()
|
||||
|
||||
|
||||
func _on_drag_region_gui_input(event: InputEvent) -> void:
|
||||
if event is InputEventMouseButton:
|
||||
if event.button_index == MOUSE_BUTTON_LEFT:
|
||||
dragging = event.pressed
|
||||
elif dragging and event is InputEventMouseMotion:
|
||||
position += Vector2i(event.screen_relative)
|
||||
|
||||
class_name NpcProfileWindow extends AdventurerProfileWindow
|
||||
|
||||
@@ -7,11 +7,11 @@ class_name Player extends Person
|
||||
var interaction_target = null
|
||||
@export var interaction_range : float = 75
|
||||
@export var stop_range : float = 25
|
||||
var data : AdventurerData
|
||||
var data : Adventurer
|
||||
|
||||
func _ready() -> void:
|
||||
Game.player = self
|
||||
data = AdventurerData.new()
|
||||
data = Adventurer.new()
|
||||
data.name = "Player"
|
||||
setup.call_deferred()
|
||||
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
extends Window
|
||||
class_name ProfileWindow extends Window
|
||||
|
||||
var dragging : bool = false
|
||||
|
||||
|
||||
func _on_close_button_pressed() -> void:
|
||||
func _on_close_requested() -> void:
|
||||
queue_free()
|
||||
|
||||
func _on_drag_region_gui_input(event: InputEvent) -> void:
|
||||
if event is InputEventMouseButton:
|
||||
if event.button_index == MOUSE_BUTTON_LEFT:
|
||||
dragging = event.pressed
|
||||
elif dragging and event is InputEventMouseMotion:
|
||||
position += Vector2i(event.screen_relative)
|
||||
|
||||
|
||||
157
scripts/quest.gd
157
scripts/quest.gd
@@ -1,6 +1,7 @@
|
||||
class_name Quest extends Object
|
||||
|
||||
|
||||
|
||||
enum Status{
|
||||
OPEN,
|
||||
TAKEN,
|
||||
@@ -11,49 +12,140 @@ enum Status{
|
||||
}
|
||||
|
||||
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
|
||||
var start(quest : Quest) -> void:
|
||||
func start(quest : Quest) -> void:
|
||||
match(type):
|
||||
Type.WAIT:
|
||||
pass
|
||||
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.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 / c[1]
|
||||
turn_queue.append({"combatant":c[0], "time": time - last_time})
|
||||
last_time = time
|
||||
|
||||
func execute_attack(combatant, target) -> void:
|
||||
busy_list.append(target)
|
||||
#TODO: Make the combatant execute an attack
|
||||
#TODO: Make the target take damage
|
||||
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 = 10
|
||||
|
||||
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]
|
||||
@@ -74,21 +166,29 @@ class Event:
|
||||
|
||||
func process(delta : float) -> void:
|
||||
#TODO: Make quest combat work
|
||||
if type == Type.COMBAT:
|
||||
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()
|
||||
if len(turn_queue) > 0:
|
||||
turn_queue[0].time += c.time
|
||||
execute_action(c.combatant)
|
||||
else:
|
||||
resolve_combat()
|
||||
|
||||
time_elapsed += delta
|
||||
if time_elapsed >= time:
|
||||
completed.emit()
|
||||
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."
|
||||
@@ -104,14 +204,15 @@ var progress : float = 0
|
||||
var current_step : int = 0
|
||||
var taken : bool = false
|
||||
var status : Status = Status.OPEN
|
||||
var questview : QuestView = null
|
||||
|
||||
var questor : AdventurerData = null
|
||||
var questor : Adventurer = null
|
||||
signal status_changed(status : Status)
|
||||
|
||||
func _init() -> void:
|
||||
pass
|
||||
|
||||
func initiate(member : AdventurerData) -> void:
|
||||
func initiate(member : Adventurer) -> void:
|
||||
questor = member
|
||||
status = Status.TAKEN
|
||||
status_changed.emit(Status.TAKEN)
|
||||
@@ -138,7 +239,7 @@ func num_events() -> int:
|
||||
return len(events)
|
||||
|
||||
#TODO: Put in quest requirements
|
||||
func is_eligible(member : AdventurerData) -> bool:
|
||||
func is_eligible(member : Adventurer) -> bool:
|
||||
return !taken
|
||||
|
||||
func is_taken() -> bool:
|
||||
|
||||
@@ -15,6 +15,7 @@ var quest : Quest = null
|
||||
var current_event : Quest.Event = null
|
||||
var time_elapsed : float = 0
|
||||
var next_waypoint = 0
|
||||
var failed : bool = false
|
||||
#signal value_changed(value : float)
|
||||
#var min_value
|
||||
#var max_value
|
||||
@@ -29,10 +30,11 @@ func _ready() -> void:
|
||||
hero.position = hero_offset + Vector2(length * bar.value / bar.max_value, 0)
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if failed:
|
||||
return
|
||||
if time_elapsed < quest.length:
|
||||
if current_event != null:
|
||||
if current_event.type != Quest.Event.Type.COMBAT:
|
||||
current_event.process(delta)
|
||||
current_event.process(delta)
|
||||
else:
|
||||
time_elapsed += delta
|
||||
progress_quest()
|
||||
@@ -69,7 +71,8 @@ func update_waypoints(value : float) -> void:
|
||||
func start_event(event : Quest.Event, offset : float) -> void:
|
||||
current_event = event
|
||||
current_event.completed.connect(_on_event_complete)
|
||||
current_event.start()
|
||||
current_event.failed.connect(_on_event_failed)
|
||||
current_event.start(quest)
|
||||
event.time_elapsed = offset
|
||||
|
||||
func setup(quest : Quest) -> void:
|
||||
@@ -93,10 +96,26 @@ func progress_quest() -> void:
|
||||
quest.complete()
|
||||
update_waypoints(bar.value)
|
||||
|
||||
func set_fill_color(color : Color) -> void:
|
||||
%Start/Fill.self_modulate = color
|
||||
%End/Fill.self_modulate = color
|
||||
$ProgressBar.tint_progress = color
|
||||
for wp : Waypoint in waypoints:
|
||||
wp.fill_color = color
|
||||
|
||||
func _on_event_complete() -> void:
|
||||
#TODO: Show event message!
|
||||
speech_bubble.show_message("Event complete!")
|
||||
if current_event.type == Quest.Event.Type.COMBAT:
|
||||
quest.questview.unpause_setting()
|
||||
for p : QuestorSprite in current_event.participants:
|
||||
p.set_animation("running")
|
||||
waypoints[next_waypoint].blink(false)
|
||||
next_waypoint += 1
|
||||
current_event = null
|
||||
|
||||
func _on_event_failed() -> void:
|
||||
failed = true
|
||||
set_fill_color(Color.RED)
|
||||
quest.fail()
|
||||
|
||||
|
||||
38
scripts/quest_sprite.gd
Normal file
38
scripts/quest_sprite.gd
Normal file
@@ -0,0 +1,38 @@
|
||||
class_name QuestSprite extends Control
|
||||
|
||||
var life : int = 1
|
||||
var max_life : int = 1
|
||||
var energy : int = 1
|
||||
var max_energy : int = 1
|
||||
var level : int = 1
|
||||
var exp : int = 0
|
||||
|
||||
@export var stats : StatBlock
|
||||
var gold : int = 0
|
||||
|
||||
|
||||
@onready var anim_player : AnimationPlayer = $AnimationPlayer
|
||||
signal died(killer :QuestSprite)
|
||||
signal action_complete(requeue : bool)
|
||||
signal busy()
|
||||
|
||||
|
||||
func attack(target : QuestSprite) -> void:
|
||||
print("Attack by %s to %s" % [name, target.name])
|
||||
target.take_damage(self, 10)
|
||||
action_complete.emit(true)
|
||||
|
||||
func take_damage(source : QuestSprite, amount : int) -> void:
|
||||
busy.emit()
|
||||
life = clampi(life - amount, 0, max_life)
|
||||
if life == 0:
|
||||
print("%s killed %s!" % [source.name, name])
|
||||
die(source)
|
||||
else:
|
||||
print("%s hit %s for %d damage!" % [source.name, name, amount])
|
||||
action_complete.emit(false)
|
||||
|
||||
|
||||
func die(killer : QuestSprite) -> void:
|
||||
died.emit(killer)
|
||||
queue_free()
|
||||
1
scripts/quest_sprite.gd.uid
Normal file
1
scripts/quest_sprite.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://c7tmerbioa0vn
|
||||
33
scripts/quest_view.gd
Normal file
33
scripts/quest_view.gd
Normal file
@@ -0,0 +1,33 @@
|
||||
class_name QuestView extends Panel
|
||||
|
||||
const questor_template = preload("res://templates/questor_sprite.tscn")
|
||||
|
||||
@onready var questorSprite : QuestorSprite
|
||||
@onready var setting = $Setting
|
||||
var quest : Quest
|
||||
|
||||
|
||||
func setup(qst : Quest) -> void:
|
||||
quest = qst
|
||||
quest.questview = self
|
||||
questorSprite = questor_template.instantiate()
|
||||
questorSprite.setup(quest.questor)
|
||||
add_child(questorSprite)
|
||||
questorSprite.global_position = $QuestorPosition.global_position
|
||||
|
||||
|
||||
func set_questor_animation(anim_name : String) -> void:
|
||||
questorSprite.set_animation(anim_name)
|
||||
|
||||
func set_enemy_animation(enemy : Enemy, anim_name : String) -> void:
|
||||
enemy.set_animation(anim_name)
|
||||
|
||||
func place_enemy(enemy : Enemy) -> void:
|
||||
add_child(enemy)
|
||||
enemy.global_position = $EnemyPosition.global_position
|
||||
|
||||
func pause_setting() -> void:
|
||||
setting.process_mode = Node.PROCESS_MODE_DISABLED
|
||||
|
||||
func unpause_setting() -> void:
|
||||
setting.process_mode = Node.PROCESS_MODE_INHERIT
|
||||
1
scripts/quest_view.gd.uid
Normal file
1
scripts/quest_view.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bm4826vxrmuqh
|
||||
33
scripts/questor_sprite.gd
Normal file
33
scripts/questor_sprite.gd
Normal file
@@ -0,0 +1,33 @@
|
||||
class_name QuestorSprite extends QuestSprite
|
||||
|
||||
|
||||
var data : Adventurer = null
|
||||
|
||||
func _ready() -> void:
|
||||
if data:
|
||||
life = data.life
|
||||
max_life = data.max_life
|
||||
energy = data.energy
|
||||
max_energy = data.max_energy
|
||||
level = data.level
|
||||
exp = data.exp
|
||||
stats = StatBlock.copy(data.stats)
|
||||
gold = data.gold
|
||||
|
||||
func set_animation(anim_name : String) -> void:
|
||||
anim_player.play(anim_name)
|
||||
|
||||
func setup(adv : Adventurer) -> void:
|
||||
data = adv
|
||||
life = data.life
|
||||
max_life = data.max_life
|
||||
energy = data.energy
|
||||
max_energy = data.max_energy
|
||||
level = data.level
|
||||
exp = data.exp
|
||||
stats = StatBlock.copy(data.stats)
|
||||
gold = data.gold
|
||||
adv.quest_sprite = self
|
||||
|
||||
func check_levelup() -> void:
|
||||
data.gain_exp(exp)
|
||||
1
scripts/questor_sprite.gd.uid
Normal file
1
scripts/questor_sprite.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://ce0vugvrwvppb
|
||||
@@ -1,14 +1,19 @@
|
||||
extends Node2D
|
||||
var test_adv = preload("res://templates/test_adventurer.tscn")
|
||||
|
||||
@onready var door_player : AudioStreamPlayer = $AudioStreamPlayer
|
||||
func _ready() -> void:
|
||||
#var adv : AdventurerData = test_adv.instantiate() as AdventurerData
|
||||
#var adv : Adventurer = test_adv.instantiate() as Adventurer
|
||||
#Guild.register_guild_member(adv)
|
||||
var quest : Quest = Quest.new()
|
||||
var evt : Quest.Event = Quest.Event.new()
|
||||
evt.type = Quest.Event.Type.COMBAT
|
||||
evt.enemies = ["goo"]
|
||||
evt.time = 10
|
||||
quest.events.append(evt)
|
||||
Guild.add_quest(quest)
|
||||
Guild.assign_quest(Game.player.data, quest)
|
||||
#Game.end_shift()
|
||||
#var tween = create_tween()
|
||||
#tween.tween_interval(3)
|
||||
#tween.tween_callback(Callable($DoorLight/AnimationPlayer.play).bind("open"))
|
||||
|
||||
@@ -29,7 +29,7 @@ func _on_quests_button_pressed() -> void:
|
||||
for child in quest_list.get_children():
|
||||
child.enabled = quests.visible
|
||||
|
||||
func add_member(member : AdventurerData) -> void:
|
||||
func add_member(member : Adventurer) -> void:
|
||||
var entry = member_panel_entry_template.instantiate()
|
||||
entry.setup(member)
|
||||
members_list.add_child(entry)
|
||||
|
||||
@@ -12,6 +12,11 @@ var fill: bool :
|
||||
if value != filled:
|
||||
set_fill(value)
|
||||
|
||||
var fill_color: Color :
|
||||
get: return $Fill.self_modulate
|
||||
set(value):
|
||||
$Fill.self_modulate = value
|
||||
|
||||
func blink(blnk : bool) -> void:
|
||||
if blinking == blnk:
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user