haxis/Source/UnrealProject/GUI/HUD/IngameHUD.cpp

348 lines
9.8 KiB
C++

// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "DefaultPlayerController.h"
#include "IngameHUD.h"
#include "AbilityInfo.h"
#include "AbilityState.h"
#include "NetworkPlayer.h"
#include "HealthBar.h"
#include "CreatureSpawn.h"
#include "PlayerSlot.h"
#include "DefaultGameState.h"
#include "DefaultPlayerState.h"
#include "MiniMapWidget.h"
#include "ToolTipWidget.h"
#include "CombatText/CombatTextWidget.h"
#include "SpellInfoDisplay.h"
#include "ButtonBarSwitcher.h"
#include "BaseSkillObject.h"
#include "WidgetLayoutLibrary.h"
#include "NetworkGhost.h"
#include "TouhouBoss.h"
#include "MiniBossCreature.h"
#include "StatBar.h"
#include <algorithm>
static UClass* healthBarWidgetClass;
static UClass* playerSlotWidgetClass;
UIngameHUD::UIngameHUD(const FObjectInitializer& init)
:Super(init)
{
ConstructorHelpers::FClassFinder<UHealthBar> HealthBarWidgetCF(TEXT("/Game/Assets/GUI/WEEGEE_HealthBar"));
healthBarWidgetClass = HealthBarWidgetCF.Class;
miniMap = nullptr;
}
void UIngameHUD::NativeConstruct()
{
m_myTeam = 0;
m_character = nullptr;
Super::NativeConstruct();
m_spellInfoDisplay = Cast<USpellInfoDisplay>(WidgetTree->FindWidget("SpellInfoDisplay"));
miniMap = Cast<UMiniMapWidget>(WidgetTree->FindWidget("Minimap"));
toolTips = Cast<UToolTipWidget>(WidgetTree->FindWidget("ToolTipLayer"));
combatText = Cast<UCombatTextWidget>(WidgetTree->FindWidget("CombatTextLayer"));
buttonBarSwitcher = Cast<UButtonBarSwitcher>(WidgetTree->FindWidget("ButtonBarSwitcher"));
healthBarLayer = Cast<UCanvasPanel>(WidgetTree->FindWidget("HealthBarLayer"));
// Find stat display items
m_playerStatDisplay.hpBar = Cast<UStatBar>(WidgetTree->FindWidget("HP"));
m_playerStatDisplay.manaBar = Cast<UStatBar>(WidgetTree->FindWidget("Mana"));
m_playerStatDisplay.expBar = Cast<UExperienceBar>(WidgetTree->FindWidget("Exp"));
m_allyStatDisplay.hpBar = Cast<UStatBar>(WidgetTree->FindWidget("HP1"));
m_allyStatDisplay.manaBar = Cast<UStatBar>(WidgetTree->FindWidget("Mana1"));
m_allyStatDisplay.name = Cast<UTextBlock>(WidgetTree->FindWidget("Name1"));
m_InitStatDisplay(m_playerStatDisplay);
m_InitStatDisplay(m_allyStatDisplay);
check(healthBarLayer);
}
void UIngameHUD::NativeDestruct()
{
Super::NativeDestruct();
}
void UIngameHUD::NativeTick(const FGeometry& MyGeometry, float InDeltaTime)
{
Super::NativeTick(MyGeometry, InDeltaTime);
auto p = m_healthBars.CreateIterator();
while (p)
{
m_UpdateHealthBar(p.Key(), p.Value());
++p;
}
ADefaultPlayerState* ps = Cast<ADefaultPlayerState>(GetOwningPlayer()->PlayerState);
if (IsValid(ps))
{
m_UpdateStatDisplay(ps, m_playerStatDisplay);
m_UpdateStatDisplay(ps->teamMate, m_allyStatDisplay);
}
//UWorld* world = GetWorld();
//check(world);
//ADefaultGameState* state = Cast<ADefaultGameState>(world->GetGameState());
}
void UIngameHUD::NativeOnAssignCharacter(class ANetworkPossessable* pawn /*= nullptr*/, TArray<FIngameSkillTreeSkill> skillsetPrototype /*= TArray<FIngameSkillTreeSkill>()*/)
{
m_character = pawn;
// Cast to ghost or player
ANetworkPlayer* player = Cast<ANetworkPlayer>(pawn);
ANetworkGhost* ghost = Cast<ANetworkGhost>(pawn);
if(ghost)
{
// Grey out buttons in ghost mode
buttonBarSwitcher->SetGlobalEnable(false);
}
else if(player)
{
// Enable buttons back in player mode
buttonBarSwitcher->SetGlobalEnable(true);
// Set skill prototypes
if(buttonBarSwitcher)
{
for(int32 i = 0; i < skillsetPrototype.Num(); i++)
{
// Don't assign buttons for passive skills
if(skillsetPrototype[i].selectedEffect->passive)
continue;
switch(skillsetPrototype[i].abilityType)
{
case 0:
buttonBarSwitcher->AssignSkillButton(skillsetPrototype[i], false);
break;
case 1:
buttonBarSwitcher->AssignSkillButton(skillsetPrototype[i], true);
break;
case 2:
if(skillsetPrototype[i].selectedEffect && !skillsetPrototype[i].selectedEffect->passive)
{
GERROR("Non-passive skill added to skill with shape type == passive, " +
skillsetPrototype[i].skillObject->GetName() + " <= " +
skillsetPrototype[i].selectedEffect->GetName());
}
}
}
}
m_myTeam = player->GetTeam();
}
OnAssignCharacter(pawn);
}
void UIngameHUD::OnLevelUp(TArray<FIngameSkillTreeSkill> updatedSkills)
{
if (m_spellInfoDisplay && GetPlayer())
m_spellInfoDisplay->OnLevelUp(GetPlayer(), updatedSkills);
if (buttonBarSwitcher)
{
for (int32 i = 0; i < updatedSkills.Num(); i++)
{
buttonBarSwitcher->SetSkillButtonEnabled(updatedSkills[i], true);
}
}
}
void UIngameHUD::UpdateCooldowns(TArray<class AAbilityState*> abilityStates, ANetworkPlayer* player)
{
if (buttonBarSwitcher)
buttonBarSwitcher->UpdateCooldowns(abilityStates, player);
}
void UIngameHUD::OnCharacterCreated(ANetworkCharacter* character)
{
if (m_healthBars.Find(character))
{
// When OnCharacterCreated is called twice
GWWARNING(L"OnCharacterCreated called more thatn once");
return;
}
UHealthBar* widget = CreateWidget<UHealthBar>(GetOwningPlayer(), healthBarWidgetClass);
check(widget);
healthBarLayer->AddChild(widget);
m_healthBars.Add(character, widget);
m_UpdateHealthBar(character, widget);
}
void UIngameHUD::OnCharacterDestroyed(ANetworkCharacter* character)
{
auto it = m_healthBars.Find(character);
if (it)
{
(*it)->RemoveFromViewport();
m_healthBars.Remove(character);
}
else
{
// When OnCharacterDestroyed is called twice
GWWARNING(L"OnCharacterDestroyed called more than once");
}
}
ANetworkPlayer* UIngameHUD::GetTeamMate() const
{
if (Cast<ANetworkPlayer>(m_character))
{
ANetworkPlayer* teamMate = Cast<ANetworkPlayer>(m_character)->GetTeamMate();
return teamMate;
}
return nullptr;
}
ANetworkPlayer* UIngameHUD::GetPlayer() const
{
return Cast<ANetworkPlayer>(m_character);
}
ANetworkGhost* UIngameHUD::GetGhost() const
{
return Cast<ANetworkGhost>(m_character);
}
class ADefaultPlayerState* UIngameHUD::GetPlayerState() const
{
if (!m_character)
return nullptr;
return Cast<ADefaultPlayerState>(m_character->PlayerState);
}
void UIngameHUD::m_UpdateHealthBar(class ANetworkCharacter* character, class UHealthBar* bar)
{
APlayerController* pc = GetOwningPlayer();
if (!IsValid(pc)) return;
FVector screenPos;
const float height = character->GetCapsuleComponent()->GetScaledCapsuleHalfHeight();
const FVector position = character->GetActorLocation();
const FVector worldLocation = FVector(position.X, position.Y, position.Z + height);
// Check if is approximately in camera view
const FVector forward = pc->PlayerCameraManager->GetCameraRotation().RotateVector(FVector(1.0f, 0.0f, 0.0f));
const FVector dir = (worldLocation - pc->PlayerCameraManager->GetCameraLocation()).GetSafeNormal();
float dot = FVector::DotProduct(forward, dir);
if (dot < 0.01f)
{
bar->SetVisibility(ESlateVisibility::Hidden);
return;
}
bar->SetVisibility(ESlateVisibility::Visible);
pc->ProjectWorldLocationToScreenWithDistance(FVector(position.X, position.Y, position.Z + height), screenPos);
const float viewportScale = UWidgetLayoutLibrary::GetViewportScale(healthBarLayer);
uint32 otherTeam = character->GetTeam();
// Check witch bar style to use
bool useExtendedBarStyle = character->playerName.Len() > 0;
if(useExtendedBarStyle)
{
bar->SetStyle(0);
bar->UpdateMana(character->GetMana(), character->GetMaxMana(), character->GetBlockedMana());
bar->SetName(character->playerName);
}
else
{
bar->SetStyle(1);
bar->SetName("");
}
bar->UpdateAlignment(otherTeam == m_myTeam);
bar->UpdateHealth(character->GetHealth(), character->GetMaxHealth());
// Set the icon next to the bar
EMinimapIcon icon = EMinimapIcon::None;
if(character->IsA<ATouhouBoss>())
{
icon = EMinimapIcon::Crown;
}
else if(character->IsA<AMiniBossCreature>())
{
icon = EMinimapIcon::MiniBoss;
}
bar->SetIcon(icon);
// Set the on-screen position
UCanvasPanelSlot* asSlot = Cast<UCanvasPanelSlot>(bar->Slot);
if (IsValid(asSlot))
{
asSlot->SetAutoSize(true);
asSlot->SetAlignment(FVector2D(0.5f, 1));
const FVector2D setPos = FVector2D(screenPos.X, screenPos.Y) / viewportScale;
asSlot->SetPosition(FVector2D(FPlatformMath::RoundToFloat(setPos.X), FPlatformMath::RoundToFloat(setPos.Y)));
}
}
void UIngameHUD::m_UpdateStatDisplay(class ADefaultPlayerState* state, const FStatDisplay& sd)
{
ANetworkPlayer* player = state ? state->character : nullptr;
if(sd.hpBar)
{
if(!player)
sd.hpBar->SetStat(0.0f, true);
else
{
sd.hpBar->SetStat(player->GetHealth(), player->GetMaxHealth(), true);
}
}
if(sd.manaBar)
{
if(!player)
{
sd.manaBar->SetBlocked(0.0f);
sd.manaBar->SetStat(0, 1, true);
}
else
{
sd.manaBar->SetStat(player->GetMana(), player->GetMaxMana(), true);
sd.manaBar->SetBlocked((float)player->GetBlockedMana() / (float)player->GetMaxMana());
}
}
if(sd.expBar)
{
if(state)
{
if(state->GetLevel() == state->GetMaxLevel())
sd.expBar->Update(1.0f, state->GetMaxLevel(), true);
else
sd.expBar->Update((float)state->GetExperience() / (float)state->GetExperienceToLevel(), state->GetLevel(), false);
}
else
{
sd.expBar->Update(0.0f, 0, false);
}
}
if(sd.name)
{
if(state)
{
state->UpdatePersona();
sd.name->SetText(FText::FromString(state->nickname));
}
else
{
sd.name->SetText(FText());
}
}
if(sd.avatar && state)
{
sd.avatar->SetBrushFromTexture(state->avatar);
}
}
void UIngameHUD::m_InitStatDisplay(const FStatDisplay& sd)
{
if(sd.hpBar)
{
sd.hpBar->SetBarColor(EBarColor::GreenGradient);
}
if(sd.manaBar)
{
sd.manaBar->SetBarColor(EBarColor::BlueGradient);
}
}