// Fill out your copyright notice in the Description page of Project Settings. #include "Player/MatchPlayerState.h" #include "ShooterTypes/ShooterTypes.h" #include "UI/Elims/SpecialElimWidget.h" AMatchPlayerState::AMatchPlayerState() { SetNetUpdateFrequency(100.f); // let's not be sluggish, alright? ScoredElims = 0; Defeats = 0; Hits = 0; Misses = 0; bOnStreak = false; HeadShotElims = 0; SequentialElims = TMap(); HighestStreak = 0; RevengeElims = 0; DethroneElims = 0; ShowStopperElims = 0; bFirstBlood = false; bWinner = false; } void AMatchPlayerState::AddScoredElim() { ++ScoredElims; } void AMatchPlayerState::AddDefeat() { ++Defeats; } void AMatchPlayerState::AddHit() { ++Hits; } void AMatchPlayerState::AddMiss() { ++Misses; } void AMatchPlayerState::AddHeadShotElim() { ++HeadShotElims; } void AMatchPlayerState::AddSequentialElim(int32 SequenceCount) { if (SequentialElims.Contains(SequenceCount)) { SequentialElims[SequenceCount]++; } else { SequentialElims.Add(SequenceCount, 1); } // Reduce the count for all lower sequence counts // This is because a triple elim means a double was scored first, // But we want to count this as just a triple, i.e: // elim 1, elim 2, elim 3 = just a triple, not a double and a triple. for (auto& Elem : SequentialElims) { if (Elem.Key < SequenceCount && Elem.Value > 0) { Elem.Value--; } } } void AMatchPlayerState::UpdateHighestStreak(int32 StreakCount) { if (StreakCount > HighestStreak) { HighestStreak = StreakCount; } } void AMatchPlayerState::AddRevengeElim() { ++RevengeElims; } void AMatchPlayerState::AddDethroneElim() { ++DethroneElims; } void AMatchPlayerState::AddShowStopperElim() { ++ShowStopperElims; } void AMatchPlayerState::GotFirstBlood() { bFirstBlood = true; } void AMatchPlayerState::IsTheWinner() { bWinner = true; } TArray AMatchPlayerState::DecodeElimBitmask(ESpecialElimType ElimTypeBitmask) { TArray ValidElims; uint8 BitmaskValue = static_cast(ElimTypeBitmask); for(uint8 i = 0; i < 16; i++) // Assuming 8 bits since ESpecialElimType is a uint16 { if (BitmaskValue & (1 << i)) { ESpecialElimType EnumValue = static_cast(1 << i); ValidElims.Add(EnumValue); } } return ValidElims; } void AMatchPlayerState::ProcessNextSpecialElim() { FSpecialElimInfo ElimInfo; if (SpecialElimQueue.Dequeue(ElimInfo)) { bIsProcessingQueue = true; ShowSpecialElim(ElimInfo); // Schedule the next elimination processing after a delay GetWorldTimerManager().SetTimerForNextTick([this]() { constexpr float ElimDisplayTime = 0.5f; // Adjust the time in seconds as needed FTimerHandle TimerHandle; GetWorldTimerManager().SetTimer(TimerHandle, this, &AMatchPlayerState::ProcessNextSpecialElim, ElimDisplayTime, false); }); } else { bIsProcessingQueue = false; } } void AMatchPlayerState::ShowSpecialElim(const FSpecialElimInfo& ElimMessageInfo) { FString ElimMessageString = ElimMessageInfo.ElimMessage; if (ElimMessageInfo.ElimType == ESpecialElimType::Sequential) { FString Msg = ElimMessageInfo.ElimMessage; int32 Seq = ElimMessageInfo.SequentialElimCount; int32 Streak = ElimMessageInfo.StreakCount; if (ElimMessageInfo.SequentialElimCount == 2) ElimMessageString = FString("Double Elim!"); else if (ElimMessageInfo.SequentialElimCount == 3) ElimMessageString = FString("Triple Elim!"); else if (ElimMessageInfo.SequentialElimCount == 4) ElimMessageString = FString("Quad Elim!"); else if (ElimMessageInfo.SequentialElimCount > 4) ElimMessageString = FString::Printf(TEXT("Rampage x%d!"), ElimMessageInfo.SequentialElimCount); } if (ElimMessageInfo.ElimType == ESpecialElimType::Streak) ElimMessageString = FString::Printf(TEXT("Streak x%d!"), ElimMessageInfo.StreakCount); if (SpecialElimWidgetClass) { USpecialElimWidget* ElimWidget = CreateWidget(GetWorld(), SpecialElimWidgetClass); if (IsValid(ElimWidget)) { ElimWidget->InitializeWidget(ElimMessageString, ElimMessageInfo.ElimIcon); ElimWidget->AddToViewport(); } } } void AMatchPlayerState::Client_ScoredElim_Implementation(int32 ElimScore) { OnScoreChanged.Broadcast(ElimScore); } void AMatchPlayerState::Client_SpecialElim_Implementation(const ESpecialElimType& SpecialElim, int32 SequentialElimCount, int32 StreakCount, int32 ElimScore) { OnScoreChanged.Broadcast(ElimScore); if (!IsValid(SpecialElimData)) return; TArray ElimTypes = DecodeElimBitmask(SpecialElim); for (ESpecialElimType ElimType : ElimTypes) { FSpecialElimInfo& ElimInfo = SpecialElimData->SpecialElimInfo.FindChecked(ElimType); if (ElimType == ESpecialElimType::Sequential) { ElimInfo.SequentialElimCount = SequentialElimCount; } if (ElimType == ESpecialElimType::Streak) { ElimInfo.StreakCount = StreakCount; } ElimInfo.ElimType = ElimType; SpecialElimQueue.Enqueue(ElimInfo); } if (!bIsProcessingQueue) { ProcessNextSpecialElim(); } } void AMatchPlayerState::Client_LostTheLead_Implementation() { UE_LOG(LogTemp, Warning, TEXT("%s Lost the Lead"), *GetName()); if (!IsValid(SpecialElimData)) return; auto& ElimMessageInfo = SpecialElimData->SpecialElimInfo.FindChecked(ESpecialElimType::LostTheLead); if (SpecialElimWidgetClass) { USpecialElimWidget* ElimWidget = CreateWidget(GetWorld(), SpecialElimWidgetClass); if (IsValid(ElimWidget)) { ElimWidget->InitializeWidget(ElimMessageInfo.ElimMessage, ElimMessageInfo.ElimIcon); ElimWidget->AddToViewport(); } } }