class_name Adventurer extends Node 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 appearance : Dictionary var stats : StatBlock var gold : int = 0 var quest : Quest var equipment : Array = [null, null, null] var inventory : Dictionary[Vector2, Item] = {} var inventory_size : Vector2i = Vector2i(3,2) var inventory_count : int = 0 var quest_sprite : QuestSprite signal changed() signal levelled() signal died() 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) generate_appearance() max_life = stats.STR * 10 + stats.CHA * 10 max_energy = stats.INT * 10 + stats.FAI * 10 life = max_life energy = max_energy changed.emit() func assign_quest(quest : Quest) -> void: self.quest = quest quest.initiate(self) changed.emit() 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]) changed.emit() levelled.emit() func gain_exp(amount : int) -> void: exp += amount while exp >= get_tnl(): exp -= get_tnl() gain_level() changed.emit() func gain_gold(amount :int) -> void: gold += amount changed.emit() func get_tnl() -> int: if job: return job.get_tnl(level) else: return level * 10 func find_open_inventory_slot(item : Item) -> Vector2: var first_open : Vector2 = Vector2(-1,-1) for j in range(inventory_size.y): for i in range(inventory_size.x): var curr_slot : Item = inventory.get(Vector2(i,j)) if curr_slot != null: #TODO: Figure out how to handle split stacking later? if curr_slot.name == item.name and curr_slot.max_quantity < curr_slot.quantity + item.quantity: return Vector2(i,j) elif first_open == Vector2(-1,-1): first_open = Vector2(i,j) return first_open func try_pickup_item(item : Item) -> bool: if inventory_count >= inventory_size.x * inventory_size.y: return false pickup_item(item) return true func pickup_item(item : Item) -> void: var open_slot = find_open_inventory_slot(item) if inventory.has(open_slot): inventory[open_slot].quantity += item.quantity else: if inventory_count >= inventory_size.x * inventory_size.y: printerr("Cannot fit additional item!") inventory[open_slot] = item inventory_count+=1 changed.emit() func equip_item(from : Vector2, slot : Item.Slots) -> void: if !inventory.has(from): printerr("Cannot equip item from %s, it is empty!" % [from]) var itm = inventory[from] if !itm.can_equip_slot(slot): printerr("Cannot equip item from %s to %s, it is the wrong type!" % [from, Item.slot_name(slot)]) if !job.can_equip(itm): printerr("Cannot equip item from %s to %s, %s cannot equip it!" % [from, Item.slot_name(slot), job.name]) if equipment[slot] != null: inventory[from] = equipment[slot] remove_stats_from_item(itm) else: inventory.erase(from) equipment[slot] = itm apply_stats_from_item(itm) #Apply Stats from func remove_stats_from_item(itm : Item) -> void: stats.STR -= stats.STR stats.DEX-= stats.DEX stats.INT-= stats.INT stats.CHA-= stats.CHA stats.FAI-= stats.FAI stats.LUK-= stats.LUK stats.PATK-= stats.PATK stats.MATK-= stats.MATK stats.PDEF-= stats.PDEF stats.MDEF-= stats.MDEF func apply_stats_from_item(itm : Item) -> void: stats.STR += stats.STR stats.DEX+= stats.DEX stats.INT+= stats.INT stats.CHA+= stats.CHA stats.FAI+= stats.FAI stats.LUK+= stats.LUK stats.PATK+= stats.PATK stats.MATK+= stats.MATK stats.PDEF+= stats.PDEF stats.MDEF+= stats.MDEF func move_item(from : Vector2, to: Vector2) -> void: if !inventory.has(from): printerr("Cannot move item from %s to %s, %s is empty!" % [from, to, from]) var itm = inventory[from] if inventory.has(to): var itm2 = inventory[to] inventory[from] = itm2 else: inventory.erase(from) inventory[to] = itm changed.emit() func generate_appearance(features=null) -> void: if features == null: appearance = { "hair":{ "color":"", "type":"" }, "skin":{ "color":"", "type":"" }, "eyes":{ "color":"", "type":"" } } #TODO: Handle different types of hair and eyes appearance.hair.color = AdventurerPortrait.random_color(ColorVariant.Types.HAIR) #appearance.hair_type = randi_range(0,len(job.portrait.hair_types) - 1) appearance.eyes.color = AdventurerPortrait.random_color(ColorVariant.Types.EYES) #appearance.eye_type = randi_range(0,len(job.portrait.eye_types) - 1) appearance.skin.color = AdventurerPortrait.random_color(ColorVariant.Types.SKIN) changed.emit() func save_inventory() -> Dictionary: return {} func save_equipment() -> Dictionary: return {} func save() -> Dictionary: var dict = {} dict.name = [given_name, surname] dict.gender = gender dict.gold = gold if quest: dict.quest = quest.id dict.exp = exp dict.level = level dict.appearance = appearance.duplicate() dict.stats = stats.duplicate() dict.life = [life, max_life] dict.energy = [energy, max_energy] #TODO: Prepare for more on these later dict.job = {} dict.abilities = {} dict.inventory = save_inventory() dict.equipment = save_equipment() return dict func load(dict : Dictionary) -> void: return