float GetExperienceProgressToLevel(PlayerRecord@ record) { int64 xpStart = record.LevelExperience(record.level - 1); int64 xpEnd = record.LevelExperience(record.level) - xpStart; int64 xpNow = record.experience - xpStart; if (record.local && g_myTownRecord !is null && g_myTownRecord.m_accomplishmentRewards !is null) xpNow += g_myTownRecord.m_accomplishmentRewards.m_rExp; if (double(xpEnd) == 0) return 0.0f; return xpNow / double(xpEnd); } float GetExperience(PlayerRecord@ record) { int64 xpStart = record.LevelExperience(record.level - 1); int64 xpEnd = record.LevelExperience(record.level) - xpStart; int64 xpNow = record.experience - xpStart; if (record.local && g_myTownRecord !is null && g_myTownRecord.m_accomplishmentRewards !is null) xpNow += g_myTownRecord.m_accomplishmentRewards.m_rExp; return xpNow; } class HUDPlayer : HUDComponent { PortraitWidget@ m_wPortrait; RectWidget@ m_wBackgroundRect; Widget@ m_wBackground; Widget@ m_wLeftBackground2; Widget@ m_wLeftBackground3; Widget@ m_wLeftBackground4; TextWidget@ m_wMissionGold; TextWidget@ m_wMissionWood; TextWidget@ m_wMissionStone; TextWidget@ m_wMissionIron; TextWidget@ m_wMissionCrystal; TextWidget@ m_wMissionDust; TextWidget@ m_wMissionOre; TextWidget@ m_wPotCharges; SpriteWidget@ m_wPotIcon; SpriteWidget@ m_wPotEmptyIcon; vec4 m_potTextColFull; vec4 m_potTextColEmpty; vec4 m_potTextColDrinkable; PlayerHealthBarWidget@ m_wBarHealth; TextWidget@ m_wHealth; ScalingBarWidget@ m_wBarMana; TextWidget@ m_wMana; ScalingBarWidget@ m_wBarDash; Widget@ m_wBarDashBg; Widget@ m_wDashSegOne; Widget@ m_wDashSegFirst; Widget@ m_wDashSegMid; Widget@ m_wDashSegLast; Widget@ m_wDashSegMax; Widget@ m_wDashes; Widget@ m_wHandIcons; ScalingBarWidget@ m_wBarCombo; ScalingBarWidget@ m_wBarComboH; RadialSpriteWidget@ m_wRadialExp; SkillWidget@ m_wSkillTemplate; SkillWidget@ m_wSkillWeaponTemplate; array m_skillSlots; Widget@ m_wMainHandSkillSlot; Widget@ m_wOffHandSkillSlot; int m_maxDashCharges; HUDPlayer(GUIBuilder@ b) { super(b, "gui/hud_components/player_info.gui"); @m_wBackgroundRect = cast(m_widget.GetWidgetById("background-rect")); @m_wBackground = m_widget.GetWidgetById("background"); @m_wLeftBackground2 = m_widget.GetWidgetById("skill2"); @m_wLeftBackground3 = m_widget.GetWidgetById("skill3"); @m_wLeftBackground4 = m_widget.GetWidgetById("skill4"); @m_wPortrait = cast(m_widget.GetWidgetById("portrait")); @m_wMissionGold = cast(m_widget.GetWidgetById("mission-gold")); @m_wMissionWood = cast(m_widget.GetWidgetById("mission-wood")); @m_wMissionStone = cast(m_widget.GetWidgetById("mission-stone")); @m_wMissionIron = cast(m_widget.GetWidgetById("mission-iron")); @m_wMissionCrystal = cast(m_widget.GetWidgetById("mission-crys")); @m_wMissionDust = cast(m_widget.GetWidgetById("mission-dust")); @m_wMissionOre = cast(m_widget.GetWidgetById("mission-ore")); @m_wPotCharges = cast(m_widget.GetWidgetById("potion-charges")); @m_wPotIcon = cast(m_widget.GetWidgetById("potion-icon")); @m_wPotEmptyIcon = cast(m_widget.GetWidgetById("potion-empty-icon")); @m_wBarHealth = cast(m_widget.GetWidgetById("health-bar")); @m_wHealth = cast(m_widget.GetWidgetById("health")); @m_wBarMana = cast(m_widget.GetWidgetById("mana-bar")); @m_wMana = cast(m_widget.GetWidgetById("mana")); @m_wBarCombo = cast(m_widget.GetWidgetById("combo-bar")); @m_wBarComboH = cast(m_widget.GetWidgetById("combo-bar-highlight")); @m_wBarDash = cast(m_widget.GetWidgetById("dash-bar")); @m_wRadialExp = cast(m_widget.GetWidgetById("exp")); @m_wSkillTemplate = cast(m_widget.GetWidgetById("skill-template")); @m_wSkillWeaponTemplate = cast(m_widget.GetWidgetById("skill-weapon-template")); @m_wMainHandSkillSlot = m_widget.GetWidgetById("main-hand-slot"); @m_wOffHandSkillSlot = m_widget.GetWidgetById("off-hand-slot"); @m_wDashSegOne = m_widget.GetWidgetById("dash-one"); @m_wDashSegFirst = m_widget.GetWidgetById("dash-first"); @m_wDashSegMid = m_widget.GetWidgetById("dash-mid"); @m_wDashSegLast = m_widget.GetWidgetById("dash-last"); @m_wDashSegMax = m_widget.GetWidgetById("dash-max"); @m_wDashes = m_widget.GetWidgetById("dashes"); @m_wBarDashBg = m_widget.GetWidgetById("dash-bar-bg"); @m_wHandIcons = m_widget.GetWidgetById("hands"); m_potTextColFull = ParseColorRGBA("#00ff00ff"); m_potTextColEmpty = vec4(0.1f, 0.1f, 0.1f, 1.0f); m_potTextColDrinkable = ParseColorRGBA("#ffd700ff"); m_wBarCombo.m_scale = 0.0f; m_wBarComboH.m_scale = 0.0f; m_wBarDash.SetScale(0.0f); } void GetSkillSlots(Widget@ w) { m_skillSlots.resize(0); GetSkillSlots(w, HashString("skill-slot")); } void GetSkillSlots(Widget@ w, uint id) { for (uint i = 0; i < w.m_children.length(); i++) { if (w.m_children[i].m_idHash == id) m_skillSlots.insertLast(w.m_children[i]); GetSkillSlots(w.m_children[i], id); } } void Update(int dt, PlayerRecord@ record) override { HUDComponent::Update(dt, record); if (!m_visible || record is null) return; // Materials Tracking int goldCount = record.GetMaterial(MaterialType::Gold); int woodCount = record.GetMaterial(MaterialType::Wood); int stoneCount = record.GetMaterial(MaterialType::Stone); int ironCount = record.GetMaterial(MaterialType::Iron); int crysCount = record.GetMaterial(MaterialType::Crystals); int dustCount = record.GetMaterial(MaterialType::Dust); int oreCount = record.GetMaterial(MaterialType::Ore); m_wMissionGold.SetText(goldCount); m_wMissionWood.SetText(woodCount); m_wMissionStone.SetText(stoneCount); m_wMissionIron.SetText(ironCount); m_wMissionCrystal.SetText(crysCount); m_wMissionDust.SetText(dustCount); m_wMissionOre.SetText(oreCount); // Potion int charges = record.currStats.PotionCharges - record.potionChargesUsed; if (charges == 0) m_wPotCharges.SetColor(m_potTextColEmpty); else if (record.potionChargesUsed == 0) m_wPotCharges.SetColor(m_potTextColFull); else m_wPotCharges.SetColor(m_potTextColDrinkable); m_wPotCharges.SetText("" + charges); m_wPotIcon.m_visible = (charges > 0); m_wPotEmptyIcon.m_visible = (charges == 0 && record.currStats.PotionCharges > 0); // Health m_wBarHealth.CalculateScales(record); if (record.IsDead()) m_wHealth.SetText("" + 0 + "/" + record.MaxHealth()); else m_wHealth.SetText("" + int(ceil(record.hp * record.MaxHealth())) + "/" + record.MaxHealth()); // Mana m_wBarMana.SetScale(record.mana); m_wMana.SetText("" + int(floor(record.mana * record.MaxMana())) + "/" + record.MaxMana()); // Experience m_wRadialExp.m_scale = GetExperienceProgressToLevel(record); // Dash charges if (record.currStats.MaxDashes == 0 || record.dashCharges == 0) m_wBarDash.SetScale(0.0f); else if (record.dashCharges == record.currStats.MaxDashes) m_wBarDash.SetScale(1.0f); else { if (record.currStats.MaxDashes > 2) { float mid = float((record.dashCharges - 1) * m_wDashSegMid.m_width) / float(m_wBarDash.m_width); float first = float(m_wDashSegFirst.m_width) / float(m_wBarDash.m_width); m_wBarDash.SetScale(first + mid); } else m_wBarDash.SetScale(float(record.dashCharges) / float(record.currStats.MaxDashes)); } if (record.currStats.MaxDashes != m_maxDashCharges) UpdateDashMaxCharges(record); auto plr = cast(record.actor); if (record.currStats.ComboCountMax > 0 && plr !is null) { m_wBarCombo.m_scale = min(1.0f, float(plr.m_comboCount) / float(record.currStats.ComboCountMax)); int resetTime = plr.m_comboActive ? record.currStats.ComboSustainResetTime : record.currStats.ComboObtainResetTime; m_wBarComboH.m_scale = m_wBarCombo.m_scale * (1.0f - float(plr.m_comboC) / float(resetTime)); } else { m_wBarCombo.m_scale = 0.0f; m_wBarComboH.m_scale = 0.0f; } } void UpdateDashMaxCharges(PlayerRecord@ record) { if (record is null) return; m_wDashes.ClearChildren(); int width = -3; if (record.currStats.MaxDashes == 1) { auto seg = m_wDashSegOne.Clone(); seg.m_visible = true; width += seg.m_width; m_wDashes.AddChild(seg); } else if (record.currStats.MaxDashes == 2) { auto seg1 = m_wDashSegFirst.Clone(); auto seg2 = m_wDashSegLast.Clone(); seg1.m_visible = true; seg2.m_visible = true; width += seg1.m_width + seg2.m_width; m_wDashes.AddChild(seg1); m_wDashes.AddChild(seg2); } else { for (uint i = 0; i < record.currStats.MaxDashes; i++) { Widget@ seg; if (i == 0) @seg = m_wDashSegFirst.Clone(); else if (i == record.currStats.MaxDashes - 1) { if (i >= 8) @seg = m_wDashSegMax.Clone(); else { @seg = m_wDashSegLast.Clone(); } } else @seg = m_wDashSegMid.Clone(); seg.m_visible = true; width += seg.m_width; m_wDashes.AddChild(seg); } } m_wBarDash.m_width = width; m_wBarDashBg.m_width = width; m_maxDashCharges = record.currStats.MaxDashes; } void Refresh(PlayerRecord@ record) override { RefreshPotions(record); RefreshSkills(record); RefreshPortrait(record); } void RefreshPotions(PlayerRecord@ record) { if (record is null) return; Invalidate(); } void RefreshPortrait(PlayerRecord@ record) { m_wPortrait.SetPortrait(record.portrait); m_wPortrait.m_visible = record.level > 0; if (record.skinColor is null) return; array col; PlayerColors::GetPlayerColors(col, record); m_wPortrait.SetColors(col); } void RefreshSkills(PlayerRecord@ record) { array@ playerSkills; auto player = cast(record.actor); if (player !is null) @playerSkills = player.m_skills; else @playerSkills = PlayerHelper::GetDeadSkillList(record); auto mainHandWeapon = record.equipped.m_items[EquippedItemsSlots::MainHand]; auto offHandWeapon = record.equipped.m_items[EquippedItemsSlots::OffHand]; m_wHandIcons.m_visible = mainHandWeapon !is null && mainHandWeapon.GetSlot() == Equipment::Slot::TwoHanded; for (uint i = 0; i < m_skillSlots.length(); i++) m_skillSlots[i].ClearChildren(); m_wMainHandSkillSlot.ClearChildren(); m_wOffHandSkillSlot.ClearChildren(); Skills::Skill@ mainHandSkill; Skills::Skill@ offHandSkill; array skills = array(); for (uint i = 0; i < playerSkills.length(); i++) { if (playerSkills[i].GetTargetingMode() == Skills::TargetingMode::Passive) continue; if (playerSkills[i].m_type == PlayerSkillType::MainHand) @mainHandSkill = playerSkills[i]; else if (playerSkills[i].m_type == PlayerSkillType::OffHand) @offHandSkill = playerSkills[i]; else if (playerSkills[i].m_type != PlayerSkillType::Dash) skills.insertLast(playerSkills[i]); } if (skills.length() <= 2) { m_wLeftBackground2.m_visible = true; m_wLeftBackground3.m_visible = false; m_wLeftBackground4.m_visible = false; m_wBackgroundRect.m_width = m_wBackground.m_width + m_wLeftBackground2.m_width; GetSkillSlots(m_wLeftBackground2); } else if (skills.length() == 3) { m_wLeftBackground2.m_visible = false; m_wLeftBackground3.m_visible = true; m_wLeftBackground4.m_visible = false; m_wBackgroundRect.m_width = m_wBackground.m_width + m_wLeftBackground3.m_width; GetSkillSlots(m_wLeftBackground3); } else { m_wLeftBackground2.m_visible = false; m_wLeftBackground3.m_visible = false; m_wLeftBackground4.m_visible = true; m_wBackgroundRect.m_width = m_wBackground.m_width + m_wLeftBackground4.m_width; GetSkillSlots(m_wLeftBackground4); } if (m_wMainHandSkillSlot !is null && mainHandSkill !is null) { auto newSkill = cast(m_wSkillWeaponTemplate.Clone()); newSkill.SetID(""); newSkill.m_visible = true; newSkill.SetSkill(mainHandSkill, mainHandWeapon); auto bindingW = cast(newSkill.GetWidgetById("binding")); bindingW.SetText(""); m_wMainHandSkillSlot.AddChild(newSkill); } if (m_wOffHandSkillSlot !is null && offHandSkill !is null) { auto newSkill = cast(m_wSkillWeaponTemplate.Clone()); newSkill.SetID(""); newSkill.m_visible = true; newSkill.SetSkill(offHandSkill, m_wHandIcons.m_visible ? mainHandWeapon : offHandWeapon, m_wHandIcons.m_visible); auto bindingW = cast(newSkill.GetWidgetById("binding")); bindingW.SetText(""); m_wOffHandSkillSlot.AddChild(newSkill); } for (uint i = 0; i < m_skillSlots.length() && i < skills.length(); i++) { auto newSkill = cast(m_wSkillTemplate.Clone()); newSkill.SetID(""); newSkill.m_visible = true; newSkill.SetSkill(skills[i]); auto bindingW = cast(newSkill.GetWidgetById("binding")); bindingW.SetText(""); m_skillSlots[i].AddChild(newSkill); } Invalidate(); } }