Files
MxHoH2/scripts/GUI/HUD/Components/HUDPlayer.as
2026-05-30 19:23:56 -04:00

434 lines
13 KiB
ActionScript

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<Widget@> 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<RectWidget>(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<PortraitWidget>(m_widget.GetWidgetById("portrait"));
@m_wMissionGold = cast<TextWidget>(m_widget.GetWidgetById("mission-gold"));
@m_wMissionWood = cast<TextWidget>(m_widget.GetWidgetById("mission-wood"));
@m_wMissionStone = cast<TextWidget>(m_widget.GetWidgetById("mission-stone"));
@m_wMissionIron = cast<TextWidget>(m_widget.GetWidgetById("mission-iron"));
@m_wMissionCrystal = cast<TextWidget>(m_widget.GetWidgetById("mission-crys"));
@m_wMissionDust = cast<TextWidget>(m_widget.GetWidgetById("mission-dust"));
@m_wMissionOre = cast<TextWidget>(m_widget.GetWidgetById("mission-ore"));
@m_wPotCharges = cast<TextWidget>(m_widget.GetWidgetById("potion-charges"));
@m_wPotIcon = cast<SpriteWidget>(m_widget.GetWidgetById("potion-icon"));
@m_wPotEmptyIcon = cast<SpriteWidget>(m_widget.GetWidgetById("potion-empty-icon"));
@m_wBarHealth = cast<PlayerHealthBarWidget>(m_widget.GetWidgetById("health-bar"));
@m_wHealth = cast<TextWidget>(m_widget.GetWidgetById("health"));
@m_wBarMana = cast<ScalingBarWidget>(m_widget.GetWidgetById("mana-bar"));
@m_wMana = cast<TextWidget>(m_widget.GetWidgetById("mana"));
@m_wBarCombo = cast<ScalingBarWidget>(m_widget.GetWidgetById("combo-bar"));
@m_wBarComboH = cast<ScalingBarWidget>(m_widget.GetWidgetById("combo-bar-highlight"));
@m_wBarDash = cast<ScalingBarWidget>(m_widget.GetWidgetById("dash-bar"));
@m_wRadialExp = cast<RadialSpriteWidget>(m_widget.GetWidgetById("exp"));
@m_wSkillTemplate = cast<SkillWidget>(m_widget.GetWidgetById("skill-template"));
@m_wSkillWeaponTemplate = cast<SkillWidget>(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<Player>(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<PlayerColors@> col;
PlayerColors::GetPlayerColors(col, record);
m_wPortrait.SetColors(col);
}
void RefreshSkills(PlayerRecord@ record)
{
array<Skills::Skill@>@ playerSkills;
auto player = cast<PlayerBase>(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::Skill@> skills = array<Skills::Skill@>();
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<SkillWidget>(m_wSkillWeaponTemplate.Clone());
newSkill.SetID("");
newSkill.m_visible = true;
newSkill.SetSkill(mainHandSkill, mainHandWeapon);
auto bindingW = cast<TextWidget>(newSkill.GetWidgetById("binding"));
bindingW.SetText("");
m_wMainHandSkillSlot.AddChild(newSkill);
}
if (m_wOffHandSkillSlot !is null && offHandSkill !is null)
{
auto newSkill = cast<SkillWidget>(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<TextWidget>(newSkill.GetWidgetById("binding"));
bindingW.SetText("");
m_wOffHandSkillSlot.AddChild(newSkill);
}
for (uint i = 0; i < m_skillSlots.length() && i < skills.length(); i++)
{
auto newSkill = cast<SkillWidget>(m_wSkillTemplate.Clone());
newSkill.SetID("");
newSkill.m_visible = true;
newSkill.SetSkill(skills[i]);
auto bindingW = cast<TextWidget>(newSkill.GetWidgetById("binding"));
bindingW.SetText("");
m_skillSlots[i].AddChild(newSkill);
}
Invalidate();
}
}