diff --git a/Source/BeatBoxers/BeatBoxers.cpp b/Source/BeatBoxers/BeatBoxers.cpp index 173ffab1..3efcbb22 100644 --- a/Source/BeatBoxers/BeatBoxers.cpp +++ b/Source/BeatBoxers/BeatBoxers.cpp @@ -15,4 +15,5 @@ DEFINE_LOG_CATEGORY(LogABBGameMode); DEFINE_LOG_CATEGORY(LogBBAnimation); DEFINE_LOG_CATEGORY(LogBBUI); DEFINE_LOG_CATEGORY(LogFretboard); -DEFINE_LOG_CATEGORY(LogBeatTiming); \ No newline at end of file +DEFINE_LOG_CATEGORY(LogBeatTiming); +DEFINE_LOG_CATEGORY(LogClashing); \ No newline at end of file diff --git a/Source/BeatBoxers/BeatBoxers.h b/Source/BeatBoxers/BeatBoxers.h index b8531dce..8475ddbe 100644 --- a/Source/BeatBoxers/BeatBoxers.h +++ b/Source/BeatBoxers/BeatBoxers.h @@ -15,4 +15,5 @@ DECLARE_LOG_CATEGORY_EXTERN(LogABBGameMode, Log, All); DECLARE_LOG_CATEGORY_EXTERN(LogBBAnimation, Log, All); DECLARE_LOG_CATEGORY_EXTERN(LogBBUI, Log, All); DECLARE_LOG_CATEGORY_EXTERN(LogFretboard, Log, All); -DECLARE_LOG_CATEGORY_EXTERN(LogBeatTiming, Log, All); \ No newline at end of file +DECLARE_LOG_CATEGORY_EXTERN(LogBeatTiming, Log, All); +DECLARE_LOG_CATEGORY_EXTERN(LogClashing, Log, All); \ No newline at end of file diff --git a/Source/BeatBoxers/Implementation/BBGameMode.cpp b/Source/BeatBoxers/Implementation/BBGameMode.cpp index d43b91e0..9c81a38f 100644 --- a/Source/BeatBoxers/Implementation/BBGameMode.cpp +++ b/Source/BeatBoxers/Implementation/BBGameMode.cpp @@ -32,6 +32,14 @@ ABBGameMode::ABBGameMode(const class FObjectInitializer& ObjectInitializer) bReadyToEnd = false; RoundTime = 90; DelayBeforeEnd = 5.f; + DefaultClashImpact.bKnocksDown = false; + DefaultClashImpact.Damage = 0.f; + DefaultClashImpact.ImpartedMovement.Delta = FVector2D(-100.f, 0.f); + DefaultClashImpact.ImpartedMovement.Duration = 0.2f; + DefaultClashImpact.ImpartedMovement.UseDeltaAsSpeed = false; + DefaultClashImpact.ImpartedMovement.IsRelativeToAttackerFacing = true; + DefaultClashImpact.ImpartedMovement.UsePhysicsLaunch = false; + DefaultClashImpact.StunLength = 0.5f; } EFighterDamageType ABBGameMode::GetDamageType(EStance Stance, EFighterDamageType DesiredOverride) const @@ -134,6 +142,7 @@ EHitResponse ABBGameMode::HitActor(TWeakObjectPtr Actor, EFighterDamageT if (CheckClash(Actor, Source)) { + UE_LOG(LogClashing, Log, TEXT("Clash detected between %s and %s."), *Actor.Get()->GetName(), *Source.Get()->GetName()); OnClash(Actor, Source); return EHitResponse::HE_Clashed; } @@ -142,54 +151,20 @@ EHitResponse ABBGameMode::HitActor(TWeakObjectPtr Actor, EFighterDamageT FImpactData* ImpactData = (WasBlocked) ? &Block : &Hit; FImpactData ScaledImpact = GetScaledImpactData(*ImpactData, Accuracy); - if (ImpactData->StunLength > 0) - { - IFighter* Fighter = Cast(Actor.Get()); - Fighter->StartStun(ImpactData->StunLength, WasBlocked); - } - if (ApplyMovementToActor(Actor, Source, SourceController, ScaledImpact.ImpartedMovement) == 1 && !ScaledImpact.ImpartedMovement.UsePhysicsLaunch) + + if (ApplyImpact(Actor, ScaledImpact, WasBlocked, SourceController, Source) == 1 + && !ScaledImpact.ImpartedMovement.UsePhysicsLaunch) { UE_LOG(LogABBGameMode, Verbose, TEXT("%s::HitActor actor backed into wall, applying to source."), *GetNameSafe(this)); //The target is already pushed up against a wall, push back the source instead. - if (Source.IsValid() && SourceController.IsValid() && Source.Get() == SourceController.Get()->GetPawn()) - { - //Don't do this for projectiles. - ApplyMovementToActor(Source, Source, SourceController, -ScaledImpact.ImpartedMovement); - } - } - if (ImpactData->bKnocksDown && !WasBlocked) - { - IFighter* Fighter = Cast(Actor.Get()); - if (Fighter != nullptr) + //Don't do this for projectiles. + if (Source.IsValid() && SourceController.IsValid() + && Source.Get() == SourceController.Get()->GetPawn()) { - Fighter->Knockdown(); + ApplyMovementToActor(Source, Source, SourceController, -ImpactData->ImpartedMovement); } } - if (SourceController.IsValid() && SourceController.Get()->PlayerState != nullptr) - { - SourceController.Get()->PlayerState->Score += ScaledImpact.Damage; - AddSpecial(SourceController.Get()->PlayerState, ScaledImpact.SpecialGenerated); - APawn* mAPawn = Cast(Actor.Get()); - // Logic for applying damage to opponent - if (mAPawn != nullptr && mAPawn->Controller != nullptr) - { - APlayerController* mPlayerController = Cast(mAPawn->Controller); - if (mPlayerController != nullptr && mPlayerController->PlayerState != nullptr) - { - ABBPlayerState* mBBPlayerState = Cast(mPlayerController->PlayerState); - if (mBBPlayerState != nullptr) - { - mBBPlayerState->TakeDamage(ScaledImpact.Damage); - if (mBBPlayerState->GetHealth() == 0) - { - UE_LOG(LogBeatBoxers, Log, TEXT("A player has died.")); - EndRound(); - } - } - } - } - } return (WasBlocked) ? EHitResponse::HE_Blocked : EHitResponse::HE_Hit; } @@ -1102,47 +1077,53 @@ void ABBGameMode::PushMusicBalance() MusicBox->ChangeBalance(FinalParams); } -bool ABBGameMode::CheckClash(TWeakObjectPtr FighterA, TWeakObjectPtr FighterB) +bool ABBGameMode::CheckClash(TWeakObjectPtr ActorA, TWeakObjectPtr ActorB) { - IFighter* mFighterA = Cast(FighterA.Get()); - IFighter* mFighterB = Cast(FighterB.Get()); - if (FighterA != nullptr && FighterB != nullptr - && mFighterA != nullptr && mFighterB != nullptr - && mFighterA->CanClash() && mFighterB->CanClash()) - { - TArray> ActorsToIgnore; - FMoveHitbox Hitbox; - Hitbox.Radius = mFighterA->GetFighterHitbox().Radius; - Hitbox.Origin = mFighterA->GetFighterHitbox().Origin; - Hitbox.End = mFighterA->GetFighterHitbox().End; - - //Make hitboxes relative to facing - Hitbox.Origin.X *= mFighterA->GetFacing(); - Hitbox.End.X *= mFighterA->GetFacing(); - - FHitResult HitResult = TraceHitbox( - FighterA->GetActorLocation(), - Hitbox, - ActorsToIgnore - ); - if (HitResult.bBlockingHit && HitResult.Actor.IsValid()) + if (ActorA.IsValid() && ActorB.IsValid()) + { + IFighter* mFighterA = Cast(ActorA.Get()); + IFighter* mFighterB = Cast(ActorB.Get()); + if (mFighterA != nullptr && mFighterB != nullptr + && mFighterA->CanClash() && mFighterB->CanClash()) { - Hitbox.Radius = mFighterB->GetFighterHitbox().Radius; - Hitbox.Origin = mFighterB->GetFighterHitbox().Origin; - Hitbox.End = mFighterB->GetFighterHitbox().End; + TArray> ActorsToIgnore; + ActorsToIgnore.Add(ActorA); + FMoveHitbox Hitbox; + Hitbox.Radius = mFighterA->GetFighterHitbox().Radius; + Hitbox.Origin = mFighterA->GetFighterHitbox().Origin; + Hitbox.End = mFighterA->GetFighterHitbox().End; //Make hitboxes relative to facing - Hitbox.Origin.X *= mFighterB->GetFacing(); - Hitbox.End.X *= mFighterB->GetFacing(); + Hitbox.Origin.X *= mFighterA->GetFacing(); + Hitbox.End.X *= mFighterA->GetFacing(); - HitResult = TraceHitbox( - FighterB->GetActorLocation(), + FHitResult HitResult = TraceHitbox( + ActorA.Get()->GetActorLocation(), Hitbox, ActorsToIgnore ); if (HitResult.bBlockingHit && HitResult.Actor.IsValid()) { - return true; + ActorsToIgnore.Empty(); + ActorsToIgnore.Add(ActorB); + + Hitbox.Radius = mFighterB->GetFighterHitbox().Radius; + Hitbox.Origin = mFighterB->GetFighterHitbox().Origin; + Hitbox.End = mFighterB->GetFighterHitbox().End; + + //Make hitboxes relative to facing + Hitbox.Origin.X *= mFighterB->GetFacing(); + Hitbox.End.X *= mFighterB->GetFacing(); + + HitResult = TraceHitbox( + ActorB.Get()->GetActorLocation(), + Hitbox, + ActorsToIgnore + ); + if (HitResult.bBlockingHit && HitResult.Actor.IsValid()) + { + return true; + } } } } @@ -1153,17 +1134,70 @@ void ABBGameMode::OnClash(TWeakObjectPtr FighterA, TWeakObjectPtr(FighterA.Get()); IFighter* mFighterB = Cast(FighterB.Get()); - - if (mFighterA->GetFighterCurrentWindowAccuracy() >= mFighterA->GetFighterCurrentWindowAccuracy()) - { - - } if (mFighterA != nullptr && mFighterB != nullptr) { - mFighterA->StartStun(.5, false); - mFighterB->StartStun(.5, false); + IFighter* winner = DetermineClashWinner(mFighterA, mFighterB); + // Passes the fighters themselves as the source so the clash impact will be relative to their facing. + ApplyImpact(FighterA, GetClashImpact(mFighterA == winner), false, nullptr, FighterA); + ApplyImpact(FighterB, GetClashImpact(mFighterB == winner), false, nullptr, FighterB); } + else + { + UE_LOG(LogClashing, Warning, TEXT("ABBGameMode::OnClash given a nullptr for a Fighter.")); + } +} + +IFighter* ABBGameMode::DetermineClashWinner(IFighter* FighterA, IFighter* FighterB) +{ + // Nobody wins for now. + return nullptr; +} +int ABBGameMode::ApplyImpact(TWeakObjectPtr Actor, FImpactData ImpactData, bool WasBlocked, TWeakObjectPtr SourceController, TWeakObjectPtr Source) +{ + int toRet = ApplyMovementToActor(Actor, Source, SourceController, ImpactData.ImpartedMovement); + IFighter* Fighter = Cast(Actor.Get()); + if (Fighter != nullptr) + { + if (ImpactData.StunLength > 0) + { + Fighter->StartStun(ImpactData.StunLength, WasBlocked); + } + if (ImpactData.bKnocksDown && !WasBlocked) + { + IFighter* Fighter = Cast(Actor.Get()); + if (Fighter != nullptr) + { + Fighter->Knockdown(); + } + } + } + + if (SourceController.IsValid() && SourceController.Get()->PlayerState != nullptr) + { + AddSpecial(SourceController.Get()->PlayerState, ImpactData.SpecialGenerated); + } + + // Logic for applying damage to opponent + APawn* mAPawn = Cast(Actor.Get()); + if (mAPawn != nullptr && mAPawn->Controller != nullptr) + { + APlayerController* mPlayerController = Cast(mAPawn->Controller); + if (mPlayerController != nullptr && mPlayerController->PlayerState != nullptr) + { + ABBPlayerState* mBBPlayerState = Cast(mPlayerController->PlayerState); + if (mBBPlayerState != nullptr) + { + mBBPlayerState->TakeDamage(ImpactData.Damage); + if (mBBPlayerState->GetHealth() == 0) + { + UE_LOG(LogBeatBoxers, Log, TEXT("A player has died.")); + EndRound(); + } + } + } + } + return toRet; } \ No newline at end of file diff --git a/Source/BeatBoxers/Implementation/BBGameMode.h b/Source/BeatBoxers/Implementation/BBGameMode.h index 6311e007..e189b8a2 100644 --- a/Source/BeatBoxers/Implementation/BBGameMode.h +++ b/Source/BeatBoxers/Implementation/BBGameMode.h @@ -38,6 +38,7 @@ class BEATBOXERS_API ABBGameMode : public AGameMode, public IFighterWorld UPROPERTY(EditDefaultsOnly, BlueprintReadWrite) float DelayBeforeEnd; + /** Defines the Effects of a Clash. Needs to always be relative. */ UPROPERTY(EditDefaultsOnly, BlueprintReadWrite) FImpactData DefaultClashImpact; @@ -155,5 +156,12 @@ class BEATBOXERS_API ABBGameMode : public AGameMode, public IFighterWorld /** Callback for round timer. */ virtual void OnRoundTimeOut(); - virtual FImpactData GetClashImpact(bool WinnerData) { return DefaultClashImpact; } + /** If ForWinner is true, it will return the the ImpactData for the winner, otherwise it will return the Default/Looser data. */ + virtual FImpactData GetClashImpact(bool ForWinner) { return DefaultClashImpact; } + + /** Returns nullptr if no winner, otherwise Returns the pointer to the winner. */ + virtual IFighter* DetermineClashWinner(IFighter* FighterA, IFighter* FighterB); + + /** Returns -1 on error, 1 if theactor in question was backed against a wall, 0 otherwise. */ + virtual int ApplyImpact(TWeakObjectPtr Actor, FImpactData ImpactData, bool WasBlocked, TWeakObjectPtr SourceController, TWeakObjectPtr Source); };