348 lines
9.8 KiB
C++
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);
|
|
}
|
|
}
|