Advertisement
Guest User

Untitled

a guest
Jun 19th, 2016
253
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 46.20 KB | None | 0 0
  1. #include "FPSTemplate.h"
  2. #include "Soldier.h"
  3. #include "UnrealNetwork.h"
  4. #include "Soldier/SoldierAnimInstance.h"
  5. #include "Game/BaseGameMode.h"
  6. #include "Soldier/SoldierMovementComponent.h"
  7. #include "StaticFunctionLibrary.h"
  8. #include "Player/BasePlayerController.h"
  9. #include "Attachments/Sight.h"
  10. #include "Damage/DamageType_Knife.h"
  11. #include "Damage/DamageType_Environment.h"
  12. #include "Damage/DamageType_Headshot.h"
  13. #include "Items/Firearm.h"
  14. #include "Items/ThrowableItem.h"
  15. #include "Items/Knife.h"
  16. #include "BaseGameInstance.h"
  17.  
  18. #define DefaultHealth 100.f
  19. #define DefaultFOV 90.f
  20. #define LeanTraceDist 100.f
  21. #define LeanSideTraceDist 35.f
  22. #define LeanTraceChannel ECC_Camera
  23. #define MaxHitPenaltyRotation 10.f
  24. #define MaxArmsLagRotation 20.f
  25. #define strafing false
  26. bool Bstrafe;
  27.  
  28. #define MaxInteractionDistanceSquared 22500.f
  29. #define MaxInteractionAngle 45.f
  30.  
  31. #define ItemAnimationSlot FName(TEXT("UpperBody"))
  32.  
  33. ASoldier::ASoldier(const FObjectInitializer & ObjectInitializer)
  34. : Super(ObjectInitializer.SetDefaultSubobjectClass<USoldierMovementComponent>(ASoldier::CharacterMovementComponentName))
  35. {
  36. Camera = ObjectInitializer.CreateDefaultSubobject<UCameraComponent>(this, TEXT("Camera"));
  37. Camera->SetupAttachment(GetMesh(), FName(TEXT("camera_socket")));
  38. Camera->bUsePawnControlRotation = false;
  39. FPostProcessSettings & PPS = Camera->PostProcessSettings;
  40. PPS.bOverride_FilmSaturation = true;
  41. PPS.bOverride_SceneFringeIntensity = true;
  42. PPS.bOverride_VignetteIntensity = true;
  43.  
  44. CameraBoom = ObjectInitializer.CreateDefaultSubobject<USpringArmComponent>(this, TEXT("CameraBoom"));
  45. CameraBoom->SetupAttachment(GetCapsuleComponent());
  46. CameraBoom->TargetArmLength = 100.f;
  47. CameraBoom->RelativeLocation.Z = 80.f;
  48. CameraBoom->SocketOffset.Y = 30;
  49.  
  50. CameraTP = ObjectInitializer.CreateDefaultSubobject<UCameraComponent>(this, TEXT("CameraTP"));
  51. CameraTP->SetupAttachment(CameraBoom);
  52. CameraTP->bUsePawnControlRotation = false;
  53.  
  54. FootstepsAudioComponent = ObjectInitializer.CreateDefaultSubobject<UAudioComponent>(this, TEXT("FootstepsAudioComponent"));
  55. FootstepsAudioComponent->SetupAttachment(RootComponent);
  56. FootstepsAudioComponent->RelativeLocation.Z = -90.f;
  57. FootstepsAudioComponent->bAlwaysPlay = true;
  58.  
  59. static ConstructorHelpers::FObjectFinder<USoundAttenuation> FootstepsAttenuation(TEXT("SoundAttenuation'/Game/FPSTemplate/Soldier/Sounds/FootstepsAttenuation.FootstepsAttenuation'"));
  60. FootstepsAudioComponent->AttenuationSettings = FootstepsAttenuation.Object;
  61.  
  62. static ConstructorHelpers::FObjectFinder<USkeletalMesh> NewMesh(TEXT("SkeletalMesh'/Game/FPSTemplate/Soldier/Meshes/SK_Mannequin.SK_Mannequin'"));
  63. GetMesh()->SetSkeletalMesh(NewMesh.Object);
  64. static ConstructorHelpers::FObjectFinder<UAnimBlueprintGeneratedClass> AnimBlueprint(TEXT("AnimBlueprint'/Game/FPSTemplate/Soldier/ABP_Soldier.ABP_Soldier_C'"));
  65. GetMesh()->AnimClass = AnimBlueprint.Object;
  66. GetMesh()->MeshComponentUpdateFlag = EMeshComponentUpdateFlag::AlwaysTickPoseAndRefreshBones;
  67. GetMesh()->RelativeRotation.Yaw = -90.f;
  68. GetMesh()->RelativeLocation.Z = -90.f;
  69. GetMesh()->SetCollisionProfileName(FName(TEXT("Ragdoll")));
  70. GetMesh()->SetCollisionResponseToAllChannels(ECR_Ignore);
  71. GetMesh()->SetCollisionResponseToChannel(ECC_WorldStatic, ECR_Block);
  72. GetMesh()->SetCollisionResponseToChannel(ECC_GameTraceChannel1, ECR_Block);
  73.  
  74. GetCapsuleComponent()->SetCollisionResponseToChannel(ECC_GameTraceChannel1, ECR_Ignore);
  75. GetCapsuleComponent()->SetCollisionResponseToChannel(ECC_Camera, ECR_Ignore);
  76. GetCapsuleComponent()->SetCapsuleHalfHeight(90.f);
  77. GetCapsuleComponent()->SetCapsuleRadius(30.f);
  78.  
  79. SceneCapture = ObjectInitializer.CreateDefaultSubobject<USceneCaptureComponent2D>(this, TEXT("SceneCapture"));
  80. SceneCapture->SetupAttachment(Camera);
  81. SceneCapture->bCaptureEveryFrame = true;
  82. SceneCapture->bHiddenInGame = true;
  83. static ConstructorHelpers::FObjectFinder<UTextureRenderTarget2D> NewRenderTarget(TEXT("TextureRenderTarget2D'/Game/FPSTemplate/Soldier/SightRenderTarget.SightRenderTarget'"));
  84. SceneCapture->TextureTarget = NewRenderTarget.Object;
  85. SceneCapture->TextureTarget->ClearColor = FLinearColor::Black;
  86.  
  87. Health = DefaultHealth;
  88. Bstrafe = false;
  89. }
  90.  
  91. void ASoldier::GetLifetimeReplicatedProps(TArray<FLifetimeProperty> & OutLifetimeProps) const
  92. {
  93. Super::GetLifetimeReplicatedProps(OutLifetimeProps);
  94.  
  95. DOREPLIFETIME(ASoldier, Health);
  96. DOREPLIFETIME(ASoldier, Items);
  97. DOREPLIFETIME(ASoldier, CurrentItem);
  98. DOREPLIFETIME(ASoldier, InteractionActor);
  99. DOREPLIFETIME(ASoldier, SoldierTask);
  100. DOREPLIFETIME_CONDITION(ASoldier, Perk, COND_InitialOnly);
  101. DOREPLIFETIME_CONDITION(ASoldier, CharacterMesh, COND_InitialOnly);
  102. DOREPLIFETIME_CONDITION(ASoldier, bAiming, COND_SkipOwner);
  103. DOREPLIFETIME_CONDITION(ASoldier, LeanRatio, COND_SkipOwner)
  104. }
  105.  
  106. void ASoldier::SetupPlayerInputComponent(class UInputComponent * InputComponent)
  107. {
  108. Super::SetupPlayerInputComponent(InputComponent);
  109.  
  110. // Bind input axes
  111. InputComponent->BindAxis("MoveForward", this, &ASoldier::MoveForward);
  112. InputComponent->BindAxis("MoveRight", this, &ASoldier::MoveRight);
  113. //InputComponent->BindAxis("MoveRight", this, &ASoldier::StopSprinting);
  114. InputComponent->BindAxis("LookUp", this, &ASoldier::AddControllerPitchInput);
  115. InputComponent->BindAxis("LookRight", this, &ASoldier::AddControllerYawInput);
  116.  
  117. //Bind input actions
  118. InputComponent->BindAction("Interact", IE_Pressed, this, &ASoldier::StartInteract);
  119. InputComponent->BindAction("Interact", IE_Released, this, &ASoldier::StopInteract);
  120. InputComponent->BindAction("Wasd", IE_Pressed, this, &ASoldier::StartSprinting);
  121. InputComponent->BindAction("Wasd", IE_Released, this, &ASoldier::StopSprinting);
  122. InputComponent->BindAction("Asd", IE_Pressed, this, &ASoldier::StopSprinting);
  123. InputComponent->BindAction("Asd", IE_Released, this, &ASoldier::StartSprinting);
  124. InputComponent->BindAction("Sprint", IE_Released, this, &ASoldier::StartSprinting);
  125. InputComponent->BindAction("Sprint", IE_Pressed, this, &ASoldier::StopSprinting);
  126. InputComponent->BindAction("Crouch", IE_Pressed, this, &ASoldier::StartCrouching);
  127. InputComponent->BindAction("Crouch", IE_Released, this, &ASoldier::StopCrouching);
  128. InputComponent->BindAction("Jump", IE_Pressed, this, &ASoldier::Jump);
  129.  
  130. InputComponent->BindAction("Fire", IE_Pressed, this, &ASoldier::StartFiring);
  131. InputComponent->BindAction("Fire", IE_Released, this, &ASoldier::StopFiring);
  132. InputComponent->BindAction("ToggleFireMode", IE_Pressed, this, &ASoldier::ToggleFireMode);
  133. InputComponent->BindAction("Aim", IE_Pressed, this, &ASoldier::StartAiming);
  134. InputComponent->BindAction("Aim", IE_Released, this, &ASoldier::StopAiming);
  135. InputComponent->BindAction("Reload", IE_Pressed, this, &ASoldier::Reload);
  136. InputComponent->BindAction("DropItem", IE_Pressed, this, &ASoldier::DropItem);
  137. InputComponent->BindAction("ToggleCamera", IE_Pressed, this, &ASoldier::ToggleCameraMode);
  138.  
  139. InputComponent->BindAction("Slot0", IE_Pressed, this, &ASoldier::EquipSlot0);
  140. InputComponent->BindAction("Slot1", IE_Pressed, this, &ASoldier::EquipSlot1);
  141. InputComponent->BindAction("Slot2", IE_Pressed, this, &ASoldier::EquipSlot2);
  142. InputComponent->BindAction("Slot3", IE_Pressed, this, &ASoldier::EquipSlot3);
  143. InputComponent->BindAction("Slot4", IE_Pressed, this, &ASoldier::EquipSlot4);
  144. InputComponent->BindAction("Slot5", IE_Pressed, this, &ASoldier::EquipSlot5);
  145. InputComponent->BindAction("Slot6", IE_Pressed, this, &ASoldier::EquipSlot6);
  146.  
  147. InputComponent->BindAction("NextItem", IE_Pressed, this, &ASoldier::EquipNextItem);
  148. InputComponent->BindAction("PreviousItem", IE_Pressed, this, &ASoldier::EquipPreviousItem);
  149.  
  150. InputComponent->BindAction("ThrowGrenade", IE_Pressed, this, &ASoldier::ThrowGrenade);
  151. InputComponent->BindAction("Knife", IE_Pressed, this, &ASoldier::Knife);
  152. //InputComponent->BindAction("Knife", IE_Released, this, &ASoldier::StopFiring);
  153. }
  154.  
  155. void ASoldier::Reset()
  156. {
  157. if (!Controller)
  158. {
  159. // Destroy this and all items when not possessed by a controller
  160. for (AItem * Item : Items)
  161. {
  162. if (Item)
  163. {
  164. Item->Destroy();
  165. }
  166. }
  167.  
  168. Destroy();
  169. }
  170. else
  171. {
  172. // Reset all important values
  173. Health = DefaultHealth;
  174. DamageInfoArray.Empty();
  175. InteractionActor = NULL;
  176. BulletCount = 0.f;
  177. TargetItemRecoil = FVector::ZeroVector;
  178. TargetPitchRecoil = 0.f;
  179. TargetYawRecoil = 0.f;
  180. //bSprinting = true;
  181.  
  182. if (CurrentItem)
  183. {
  184. CurrentItem->Draw();
  185. }
  186.  
  187. if (GetNetMode() != NM_DedicatedServer)
  188. OnRep_Health();
  189. }
  190. }
  191.  
  192. void ASoldier::UnPossessed()
  193. {
  194. Super::UnPossessed();
  195.  
  196. // Stop firing and aiming when being unpossessed
  197. bFiring = false;
  198. bAiming = false;
  199. }
  200.  
  201. void ASoldier::TurnOff()
  202. {
  203. Super::TurnOff();
  204.  
  205. SetActorTickEnabled(false);
  206. }
  207.  
  208. void ASoldier::Tick(float DeltaTime)
  209. {
  210. Super::Tick(DeltaTime);
  211.  
  212. if (GetNetMode() != NM_Client)
  213. {
  214. // Check if soldier is interaction and still can interact
  215. if (InteractionActor)
  216. {
  217. if (ItemTask != EItemTaskEnum::None || !CanInteractWith(InteractionActor))
  218. {
  219. InteractionActor = NULL;
  220. StopSoldierTask();
  221. }
  222. }
  223. }
  224.  
  225. /*if (Controller && Controller->IsLocalController())
  226. {
  227. // Check if player should lean
  228. LeanRatio = 0.f;
  229.  
  230. if (GetCharacterMovement()->MovementMode == EMovementMode::MOVE_Walking)
  231. {
  232. FVector CameraLocation;
  233. FRotator CameraRotation;
  234. GetActorEyesViewPoint(CameraLocation, CameraRotation);
  235. CameraLocation.X = GetActorLocation().X;
  236. CameraLocation.Y = GetActorLocation().Y;
  237. const FVector TraceOffset = CameraRotation.Vector() * LeanTraceDist;
  238.  
  239. FHitResult FrontHit;
  240. FCollisionQueryParams CollisionParams;
  241. CollisionParams.AddIgnoredActor(this);
  242. if (GetWorld()->LineTraceSingleByChannel(FrontHit, CameraLocation, CameraLocation + TraceOffset, LeanTraceChannel, CollisionParams))
  243. {
  244. //DrawDebugLine(GetWorld(), CameraLocation, Hit.Location, FColor::Red);
  245.  
  246. const FVector RightOffset = GetActorRightVector() * LeanSideTraceDist;
  247. FHitResult SideHit;
  248. if (!GetWorld()->LineTraceSingleByChannel(SideHit, CameraLocation + RightOffset, CameraLocation + RightOffset + TraceOffset, LeanTraceChannel, CollisionParams))
  249. {
  250. LeanRatio = 1.f;
  251. //DrawDebugLine(GetWorld(), CameraLocation + RightOffset, CameraLocation + RightOffset + TraceOffset, FColor::Green);
  252. }
  253. else if (!GetWorld()->LineTraceSingleByChannel(SideHit, CameraLocation - RightOffset, CameraLocation - RightOffset + TraceOffset, LeanTraceChannel, CollisionParams))
  254. {
  255. //DrawDebugLine(GetWorld(), CameraLocation + RightOffset, Hit.Location, FColor::Red);
  256. LeanRatio = -1.f;
  257. }
  258.  
  259. if (LeanRatio != 0.f)
  260. {
  261. LeanRatio *= -FMath::Pow(-(1.f - (FrontHit.Location - CameraLocation).Size() / LeanTraceDist) + 1.f, 2.f) + 1.f;
  262. }
  263. }
  264. }
  265.  
  266. {
  267. DrawDebugLine(GetWorld(), CameraLocation, CameraLocation + TraceOffset, FColor::Green);
  268. }
  269.  
  270. if (GetNetMode() == NM_Client)
  271. {
  272. // Send input to server
  273. ServerUpdateInput(FSoldierInputStruct(bFiring, bAiming, bSprinting, bInteracting, LeanRatio));
  274. }
  275.  
  276. if (bInteracting && !InteractionActor)
  277. {
  278. StartInteract();
  279. }
  280. }*/
  281.  
  282. // Cosmetics only from here on
  283. if (GetNetMode() == NM_DedicatedServer) return;
  284.  
  285. float Weight = 0.f;
  286. float SourceWeight;
  287. float TotalWeight;
  288. if (GetMesh()->GetAnimInstance())
  289. {
  290. GetMesh()->GetAnimInstance()->GetSlotWeight(ItemAnimationSlot, Weight, SourceWeight, TotalWeight);
  291. }
  292.  
  293. // Soldier should only aim when aiming is pressed, item supports aiming and no montage is playing in item animation slot node
  294. const bool bShouldAim = bAiming && Weight == 0.f && CurrentItem ? CurrentItem->CanAim() : false;
  295. float TargetAimRation = bShouldAim ? 1.f : 0.f;
  296. if (TargetAimRation != AimRatio)
  297. {
  298. if (AimRatio < TargetAimRation)
  299. {
  300. AimRatio += DeltaTime * 5.f;
  301. TargetItemRecoil.X += DeltaTime * 10.f;
  302.  
  303. if (AimRatio > 1.f)
  304. {
  305. AimRatio = 1.f;
  306. OnStartedAiming();
  307. }
  308. }
  309. else if (AimRatio > TargetAimRation)
  310. {
  311. if (AimRatio == 1.f)
  312. {
  313. OnStoppedAiming();
  314. }
  315.  
  316. AimRatio -= DeltaTime * 5.f;
  317.  
  318. if (AimRatio < 0.f)
  319. {
  320. AimRatio = 0.f;
  321. }
  322. }
  323.  
  324. // Camera FOV and location
  325. const float ZoomedFOV = 60.f;
  326.  
  327. Camera->FieldOfView = FMath::Lerp(DefaultFOV, ZoomedFOV, AimRatio);
  328. }
  329.  
  330. // Calculate arms lag
  331. const float ViewPitch = GetViewPitch();
  332. const float ViewYaw = GetActorRotation().Yaw;
  333. const float NewPitchLag = FMath::ClampAngle((ViewPitch - OldViewPitchRotation) * 2.f, -MaxArmsLagRotation, MaxArmsLagRotation);
  334. const float NewYawLag = FMath::ClampAngle((OldViewYawRotation - ViewYaw) * 2.f, -MaxArmsLagRotation, MaxArmsLagRotation);
  335. ArmsLagRotation = FMath::RInterpTo(ArmsLagRotation, FRotator(NewPitchLag, NewYawLag, NewYawLag), DeltaTime, 8.f);
  336.  
  337. OldViewPitchRotation = ViewPitch;
  338. OldViewYawRotation = ViewYaw;
  339.  
  340. // Reduce bullet count
  341. if (ItemTask != EItemTaskEnum::Fire)
  342. {
  343. BulletCount = FMath::FInterpTo(BulletCount, 0.f, DeltaTime, 4.f);
  344. }
  345.  
  346. // Interpolate target recoils to 0, only when not shooting
  347. TargetPitchRecoil = FMath::FInterpConstantTo(TargetPitchRecoil, 0.f, DeltaTime, 16.f);
  348. TargetYawRecoil = FMath::FInterpConstantTo(TargetYawRecoil, 0.f, DeltaTime, 16.f);
  349.  
  350. // Interpolaterecoil to target recoil
  351. PitchRecoil = FMath::FInterpTo(PitchRecoil, TargetPitchRecoil * 0.5f, DeltaTime, 8.f);
  352. YawRecoil = FMath::FInterpTo(YawRecoil, TargetYawRecoil * 0.5f, DeltaTime, 8.f);
  353.  
  354. // Apply recoil to view rotation
  355. AddControllerPitchInput(-TargetPitchRecoil * 0.5f * DeltaTime);
  356. AddControllerYawInput(TargetYawRecoil * 0.5f * DeltaTime);
  357.  
  358. // Interpolate item recoil to target item recoil
  359. TargetItemRecoil = FMath::VInterpTo(TargetItemRecoil, FVector::ZeroVector, DeltaTime, 32.f);
  360. ItemRecoil = FMath::VInterpTo(ItemRecoil, TargetItemRecoil, DeltaTime, 16.f);
  361.  
  362. // Footstep sounds
  363. USoundWave * NewSound;
  364. float FootstepsRatio;
  365. FHitResult GroundHit;
  366. FCollisionQueryParams CollisionParams;
  367. CollisionParams.AddIgnoredActor(this);
  368. CollisionParams.bReturnPhysicalMaterial = true;
  369. const FVector TraceStart = GetMesh()->GetComponentLocation() + FVector::UpVector * 10.f;
  370. if (!IsDead() && GetWorld()->LineTraceSingleByChannel(GroundHit, TraceStart, TraceStart - FVector::UpVector * 30.f, ECC_Pawn, CollisionParams))
  371. {
  372. NewSound = ConcreteFootsteps;
  373.  
  374. const EPhysicalSurface SurfaceType = UGameplayStatics::GetSurfaceType(GroundHit);
  375. switch (SurfaceType)
  376. {
  377. case (SurfaceType1) :
  378. NewSound = MetalFootsteps;
  379. break;
  380. case (SurfaceType3) :
  381. NewSound = WoodFootsteps;
  382. break;
  383. case (SurfaceType6) :
  384. NewSound = WaterFootsteps;
  385. break;
  386. case (SurfaceType9) :
  387. NewSound = ForestFootsteps;
  388. break;
  389. case (SurfaceType10) :
  390. NewSound = SnowFootsteps;
  391. break;
  392. case (SurfaceType11) :
  393. NewSound = GrassFootsteps;
  394. break;
  395. }
  396.  
  397. FootstepsRatio = FMath::GetMappedRangeValueClamped(FVector2D(0.f, Cast<USoldierMovementComponent>(GetCharacterMovement())->MaxSprintSpeed), FVector2D(0.f, 1.f), GetVelocity().Size());
  398. }
  399. else
  400. {
  401. NewSound = NULL;
  402. FootstepsRatio = 0.f;
  403. }
  404.  
  405. if (NewSound != FootstepsAudioComponent->Sound)
  406. {
  407. FootstepsAudioComponent->SetSound(NewSound);
  408. FootstepsAudioComponent->Play();
  409. }
  410.  
  411. FootstepsAudioComponent->SetVolumeMultiplier(FootstepsRatio);
  412. FootstepsAudioComponent->SetPitchMultiplier(FootstepsRatio * 0.5f + 0.5f);
  413. }
  414.  
  415. void ASoldier::Destroyed()
  416. {
  417. for (AItem * Item : Items)
  418. {
  419. if (Item)
  420. {
  421. Item->Destroy();
  422. }
  423. }
  424.  
  425. Super::Destroyed();
  426. }
  427.  
  428. void ASoldier::OnStartCrouch(float HeightAdjust, float ScaledHeightAdjust)
  429. {
  430. Super::OnStartCrouch(HeightAdjust, ScaledHeightAdjust);
  431.  
  432. //CameraBoom->RelativeLocation.Z = HeightAdjust;
  433. }
  434.  
  435. void ASoldier::OnEndCrouch(float HeightAdjust, float ScaledHeightAdjust)
  436. {
  437. Super::OnEndCrouch(HeightAdjust, ScaledHeightAdjust);
  438.  
  439. //CameraBoom->RelativeLocation.Z = 0.f;
  440. }
  441.  
  442. float ASoldier::TakeDamage(float DamageAmount, const FDamageEvent & DamageEvent, AController * EventInstigator, AActor * DamageCauser)
  443. {
  444. if (GetNetMode() == NM_Client || Health <= 0.f || DamageAmount == 0.f) return 0.f;
  445.  
  446. //if (DamageEvent.IsOfType(FPointDamageEvent::ClassID))
  447. //{
  448. // const FPointDamageEvent * PointDamageEvent = (FPointDamageEvent *) & DamageEvent;
  449. // if (PointDamageEvent->HitInfo.BoneName == FName(TEXT("head")))
  450. // {
  451. // // Double damage if soldiers head was hit
  452. // DamageAmount *= 2.f;
  453. // }
  454. //}
  455.  
  456. if (DamageEvent.DamageTypeClass == UDamageType_Headshot::StaticClass())
  457. {
  458. DamageAmount *= 2.f;
  459. }
  460.  
  461. if (DamageEvent.IsOfType(FRadialDamageEvent::ClassID))
  462. {
  463. const FRadialDamageEvent * RadialDamageEvent = (FRadialDamageEvent *)& DamageEvent;
  464. const float DistanceFactor = FMath::Pow((1.f - (RadialDamageEvent->Origin - GetActorLocation()).Size() / RadialDamageEvent->Params.OuterRadius), RadialDamageEvent->Params.DamageFalloff);
  465. DamageAmount *= FMath::Clamp(DistanceFactor, 0.f, 1.f);
  466. }
  467.  
  468. ABaseGameMode * GameMode = Cast<ABaseGameMode>(GetWorld()->GetAuthGameMode());
  469. if (!GameMode) return DamageAmount;
  470.  
  471. ABasePlayerController * PC = Cast<ABasePlayerController>(Controller);
  472. if (!PC) return DamageAmount;
  473.  
  474. ABasePlayerController * InstigatorPC = Cast<ABasePlayerController>(EventInstigator);
  475.  
  476. // Let the game mode adjust the DamageAmount (e.g. disable friendly fire)
  477. GameMode->CalcDamage(DamageAmount, PC, InstigatorPC);
  478.  
  479. // Notify instigator that he hit another soldier, draws hit marker if this is an enemy
  480. if (InstigatorPC)
  481. {
  482. InstigatorPC->ClientOnDamagedSoldier(this, DamageAmount);
  483. }
  484.  
  485. // Notify all clients that this soldier was hit
  486. MulticastTookDamage(DamageAmount, DamageCauser);
  487.  
  488. Health -= DamageAmount;
  489. if (Health <= 0.f)
  490. {
  491. if (CurrentItem)
  492. {
  493. CurrentItem->Drop();
  494. }
  495.  
  496. for (uint8 i = 0; i < NumItemSlots; i++)
  497. {
  498. if (Items[i] == CurrentItem)
  499. {
  500. // Remove CurrentItem from Items
  501. Items[i] = NULL;
  502. break;
  503. }
  504. }
  505.  
  506. CurrentItem = NULL;
  507. StopItemTask();
  508. StopSoldierTask();
  509. GameMode->OnSoldierDied(this, DamageEvent, InstigatorPC, DamageCauser);
  510. }
  511. else if (InstigatorPC)
  512. {
  513. // Check if instigator already has an entry in DamageInfoArray, else create one
  514. bool bFoundInfo = false;
  515. for (FDamageInfo & DamageInfo : DamageInfoArray)
  516. {
  517. if (DamageInfo.Instigator == InstigatorPC)
  518. {
  519. DamageInfo.DamageAmount += DamageAmount;
  520. bFoundInfo = true;
  521. break;
  522. }
  523. }
  524.  
  525. if (!bFoundInfo)
  526. {
  527. DamageInfoArray.Add(FDamageInfo(InstigatorPC, DamageAmount));
  528. }
  529. }
  530.  
  531. if (GetNetMode() != NM_DedicatedServer)
  532. {
  533. OnRep_Health();
  534. }
  535.  
  536. return DamageAmount;
  537. }
  538.  
  539. void ASoldier::MulticastTookDamage_Implementation(float DamageAmount, AActor * Causer)
  540. {
  541. TargetPitchRecoil = FMath::Clamp(TargetPitchRecoil - DamageAmount * 0.1f, -MaxHitPenaltyRotation, MaxHitPenaltyRotation);
  542. TargetYawRecoil = FMath::Clamp(TargetYawRecoil - DamageAmount * 0.1f, -MaxHitPenaltyRotation, MaxHitPenaltyRotation);
  543.  
  544. if (Controller && Controller->IsLocalController())
  545. {
  546. ABasePlayerController * PC = Cast<ABasePlayerController>(Controller);
  547. if (PC)
  548. {
  549. // Notify player controller that we got hit
  550. PC->OnTookDamage(DamageAmount, Causer);
  551. }
  552. }
  553. }
  554.  
  555. void ASoldier::Heal(float Amount)
  556. {
  557. Health += Amount;
  558. if (Health > DefaultHealth)
  559. {
  560. Amount -= (Health - DefaultHealth);
  561. Health = DefaultHealth;
  562. }
  563.  
  564. if (DamageInfoArray.Num() > 0)
  565. {
  566. float Fraction = Amount / DamageInfoArray.Num();
  567. for (int i = 0; i < DamageInfoArray.Num(); ++i)
  568. {
  569. FDamageInfo & DamageInfo = DamageInfoArray[i];
  570. DamageInfo.DamageAmount -= DamageInfo.DamageAmount * Fraction;
  571. if (DamageInfo.DamageAmount <= 0.f)
  572. {
  573. DamageInfoArray.RemoveAt(i);
  574. --i;
  575. }
  576. }
  577. }
  578.  
  579. if (GetNetMode() != NM_DedicatedServer)
  580. {
  581. OnRep_Health();
  582. }
  583. }
  584.  
  585. bool ASoldier::IsDead() const
  586. {
  587. return Health <= 0.f;
  588. }
  589.  
  590. bool ASoldier::HasFullHealth() const
  591. {
  592. return Health == DefaultHealth;
  593. }
  594.  
  595. const TArray<FDamageInfo> & ASoldier::GetDamageInfoArray() const
  596. {
  597. return DamageInfoArray;
  598. }
  599.  
  600. bool ASoldier::AllItemsFullAmmo() const
  601. {
  602. for (AItem * Item : Items)
  603. {
  604. if (Item && !Item->HasFullAmmo())
  605. {
  606. return false;
  607. }
  608. }
  609.  
  610. return true;
  611. }
  612.  
  613. void ASoldier::RefillAmmo(bool bAllItems)
  614. {
  615. for (AItem * Item : Items)
  616. {
  617. if (Item && !Item->HasFullAmmo())
  618. {
  619. Item->RefillAmmo();
  620.  
  621. if (!bAllItems) break;
  622. }
  623. }
  624. }
  625.  
  626.  
  627. void ASoldier::Landed(const FHitResult & Hit)
  628. {
  629. if (GetNetMode() != NM_Client)
  630. {
  631. // Apply falling damage
  632. const float Speed = GetCharacterMovement()->Velocity.Z;
  633. if (Speed < -1000.f)
  634. {
  635. FDamageEvent DamageEvent;
  636. DamageEvent.DamageTypeClass = UDamageType_Environment::StaticClass();
  637. TakeDamage((-Speed - 1000.f) * 0.5f, DamageEvent, Controller, NULL);
  638. }
  639. }
  640. }
  641.  
  642. void ASoldier::FaceRotation(FRotator NewControlRotation, float DeltaTime)
  643. {
  644. SetActorRotation(FRotator(0.f, NewControlRotation.Yaw + YawRecoil, 0.f));
  645. }
  646.  
  647. void ASoldier::PostRenderFor(APlayerController * PC, UCanvas * Canvas, FVector CameraPosition, FVector CameraDir)
  648. {
  649. if (CurrentItem)//&& !bInThirdPersonMode)
  650. {
  651. CurrentItem->DrawItemHUD(PC, Canvas, CameraPosition, CameraDir, AimRatio, BulletCount, GetCharacterMovement()->Velocity);
  652. }
  653. }
  654.  
  655. void ASoldier::BecomeViewTarget(APlayerController * PC)
  656. {
  657. if (AimRatio == 1.f)
  658. {
  659. OnStartedAiming();
  660. }
  661.  
  662. if (CurrentItem)
  663. {
  664. CurrentItem->BecomeViewTarget(PC);
  665. }
  666. }
  667.  
  668. void ASoldier::EndViewTarget(APlayerController * PC)
  669. {
  670. OnStoppedAiming();
  671.  
  672. if (CurrentItem)
  673. {
  674. CurrentItem->EndViewTarget(PC);
  675. }
  676. }
  677.  
  678. void ASoldier::CalcCamera(float DeltaTime, FMinimalViewInfo & OutResult)
  679. {
  680. Camera->GetCameraView(DeltaTime, OutResult);
  681.  
  682. if (bInThirdPersonMode)
  683. {
  684. CameraBoom->RelativeRotation.Pitch = GetViewPitch();
  685. const float DefaultCamHeight = GetDefault<ASoldier>(GetClass())->CameraBoom->RelativeLocation.Z;
  686. CameraBoom->SetRelativeLocation(FVector(0.f, 0.f, DefaultCamHeight + GetMesh()->GetSocketTransform(FName(TEXT("pelvis")), RTS_Actor).GetLocation().Z));
  687.  
  688. const float OffsetY = GetDefault<ASoldier>(GetClass())->CameraBoom->SocketOffset.Y;
  689. CameraBoom->SocketOffset.Y = FMath::FInterpTo(CameraBoom->SocketOffset.Y, LeanRatio < 0.f ? -OffsetY : OffsetY, DeltaTime, 8.f);
  690.  
  691. FMinimalViewInfo TPView;
  692. CameraTP->GetCameraView(DeltaTime, TPView);
  693. OutResult.BlendViewInfo(TPView, 1.f - AimRatio);
  694. }
  695. }
  696.  
  697. bool ASoldier::IsViewTarget() const
  698. {
  699. // TODO
  700. return Controller && Controller->IsLocalPlayerController() && (bAiming || !bInThirdPersonMode);
  701.  
  702. /*if (Controller && Controller->IsLocalPlayerController())
  703. {
  704. return true;
  705. }
  706. else
  707. {
  708. for (FConstPlayerControllerIterator Iterator = GetWorld()->GetPlayerControllerIterator(); Iterator; ++Iterator)
  709. {
  710. APlayerController * PlayerController = *Iterator;
  711. if (PlayerController && PlayerController->PlayerCameraManager->GetViewTargetPawn() == this)
  712. {
  713. return true;
  714. }
  715. }
  716. }*/
  717.  
  718. return false;
  719. }
  720.  
  721. void ASoldier::OnStartedAiming()
  722. {
  723. if (SceneCapture->FOVAngle > 0.f)
  724. {
  725. SceneCapture->bHiddenInGame = false;
  726. }
  727. }
  728.  
  729. void ASoldier::OnStoppedAiming()
  730. {
  731. SceneCapture->bHiddenInGame = true;
  732. }
  733.  
  734. float ASoldier::GetViewPitch() const
  735. {
  736. if (Controller)
  737. {
  738. return Controller->GetControlRotation().Pitch + PitchRecoil;
  739. }
  740.  
  741. return RemoteViewPitch / 255.f * 360.f + PitchRecoil;
  742. }
  743.  
  744. void ASoldier::GetActorEyesViewPoint(FVector & OutLocation, FRotator & OutRotation) const
  745. {
  746. if (!bInThirdPersonMode || bAiming)
  747. {
  748. OutLocation = Camera->GetComponentLocation();
  749. OutRotation = Camera->GetComponentRotation();
  750. }
  751. else
  752. {
  753. OutRotation = CameraTP->GetComponentRotation();
  754.  
  755. OutLocation = CameraTP->GetComponentLocation();
  756. OutLocation = FVector::PointPlaneProject(OutLocation, FPlane(Camera->GetComponentLocation(), OutRotation.Vector()));
  757. }
  758. }
  759.  
  760. void ASoldier::GetArmsOffset(FVector & OutOffset, FRotator & OutRotation) const
  761. {
  762. OutOffset = ItemRecoil;
  763. if (CurrentItem && IsViewTarget())
  764. {
  765. // Add items eye height to arm offset, so the sights can line up with the camera
  766. OutOffset.Z -= CurrentItem->GetEyeHeight() * AimRatio;
  767. }
  768.  
  769. OutOffset = Camera->GetComponentRotation().RotateVector(OutOffset);
  770.  
  771. OutRotation = ArmsLagRotation;
  772. }
  773.  
  774. float ASoldier::GetInteractionPercentage() const
  775. {
  776. IInteractionInterface * Interface = Cast<IInteractionInterface>(InteractionActor);
  777. if (Interface)
  778. {
  779. const float InteractionLength = Interface->GetInteractionLength();
  780. if (InteractionLength > 0.f)
  781. {
  782. return GetWorld()->GetTimerManager().GetTimerElapsed(TimerHandle_SoldierTask) / InteractionLength;
  783. }
  784. }
  785.  
  786. return -1.f;
  787. }
  788.  
  789. AItem * ASoldier::GetCurrentItem() const
  790. {
  791. return CurrentItem;
  792. }
  793.  
  794. bool ASoldier::HasPerk(EPerkEnum InPerk) const
  795. {
  796. return InPerk == Perk;
  797. }
  798.  
  799. void ASoldier::SetLoadout(const FLoadoutStruct & Loadout, USkeletalMesh * CustomMesh)
  800. {
  801. UBaseGameInstance * GameInstance = UStaticFunctionLibrary::GetBaseGameInstance(this);
  802. if (!GameInstance) return;
  803.  
  804. CharacterMesh = CustomMesh;
  805. Perk = Loadout.Perk;
  806.  
  807. if (GetNetMode() != NM_DedicatedServer)
  808. {
  809. OnRep_CharacterMesh();
  810. }
  811.  
  812. for (const FLoadoutSlotStruct Slot : Loadout.ItemSlots)
  813. {
  814. AItem * Item = SpawnItem(GameInstance->GetItem(Slot.ItemClassName));
  815. if (Item)
  816. {
  817. // Apply item specific loadout
  818. Item->SetLoadout(Slot);
  819. }
  820. }
  821. }
  822.  
  823. AItem * ASoldier::SpawnItem(TSubclassOf<AItem> ItemClass)
  824. {
  825. FActorSpawnParameters SpawnParams;
  826. SpawnParams.Owner = this;
  827. SpawnParams.Instigator = this;
  828. SpawnParams.bNoFail = true;
  829. // Spawn actual item
  830. AItem * NewItem = GetWorld()->SpawnActor<AItem>(ItemClass, SpawnParams);
  831. // Add new item to loadout
  832. AddItem(NewItem);
  833.  
  834. return NewItem;
  835. }
  836.  
  837. void ASoldier::AddItem(AItem * Item)
  838. {
  839. if (Item)
  840. {
  841. // Get correct slot for the new item
  842. uint8 Slot = Item->ItemSlot - 1;
  843. if (Slot == EItemSlotEnum::Grenade - 1)
  844. {
  845. for (uint8 i = EItemSlotEnum::Grenade - 1; i < EItemSlotEnum::Grenade + 3; i++)
  846. {
  847. if (!Items[i])
  848. {
  849. Slot = i;
  850. break;
  851. }
  852. }
  853. }
  854.  
  855. const bool bCurrentItem = Items[Slot] == CurrentItem;
  856. if (Items[Slot])
  857. {
  858. // Drop the old item
  859. Items[Slot]->Drop();
  860. }
  861.  
  862. Items[Slot] = Item;
  863. Item->PickUp(this);
  864.  
  865. if (bCurrentItem)
  866. {
  867. CurrentItem = Item;
  868. InitCurrentItem();
  869. CurrentItem->Draw();
  870. }
  871. else
  872. {
  873. StoreItem(Item);
  874. }
  875. }
  876. }
  877.  
  878. void ASoldier::InitCurrentItem()
  879. {
  880. if (CurrentItem)
  881. {
  882. CurrentItem->AttachToComponent(GetMesh(), FAttachmentTransformRules::SnapToTargetIncludingScale, FName(TEXT("hand_r")));
  883.  
  884. // From here on only on listen server and clients
  885. if (GetNetMode() == NM_DedicatedServer) return;
  886.  
  887. CurrentItem->BecomeActiveItem();
  888. CurrentItem->SetActorHiddenInGame(false);
  889.  
  890. if (IsViewTarget())
  891. {
  892. CurrentItem->BecomeViewTarget(NULL);
  893. }
  894.  
  895. USoldierAnimInstance * AnimInstance = Cast<USoldierAnimInstance>(GetMesh()->GetAnimInstance());
  896. {
  897. if (AnimInstance)
  898. {
  899. // Update item specific properties on AnimInstance for CurrentItem
  900. AnimInstance->InitItem(CurrentItem);
  901. }
  902. }
  903.  
  904. // Update scene capture FOV
  905. USight * Sight = CurrentItem->SightComponent ? CurrentItem->SightComponent->SightClass.GetDefaultObject() : NULL;
  906. if (Sight)
  907. {
  908. SceneCapture->FOVAngle = Sight->FieldOfView;
  909. }
  910. else
  911. {
  912. SceneCapture->FOVAngle = 0.f;
  913. }
  914. }
  915. }
  916.  
  917. void ASoldier::StoreItem(AItem * Item)
  918. {
  919. if (Item)
  920. {
  921. Item->EndActiveItem();
  922.  
  923. /*uint8 Slot = 0;
  924. for (uint8 i = 0; i < 7; i++)
  925. {
  926. if (Items[i] == Item)
  927. {
  928. Slot = i;
  929. break;
  930. }
  931. }
  932.  
  933. FName SocketName = NAME_None;
  934. switch (Slot)
  935. {
  936. case (0) :
  937. SocketName = FName(TEXT("primary_socket"));
  938. break;
  939. case (1) :
  940. SocketName = FName(TEXT("secondary_socket"));
  941. break;
  942. case (2) :
  943. SocketName = FName(TEXT("throwable1_socket"));
  944. break;
  945. case (3) :
  946. SocketName = FName(TEXT("throwable2_socket"));
  947. break;
  948. case (4) :
  949. SocketName = FName(TEXT("throwable3_socket"));
  950. break;
  951. case (5) :
  952. SocketName = FName(TEXT("throwable4_socket"));
  953. break;
  954. case (6) :
  955. SocketName = FName(TEXT("knife_socket"));
  956. break;
  957. }*/
  958.  
  959. if (Item == Items[0])
  960. {
  961. Item->AttachToComponent(GetMesh(), FAttachmentTransformRules::SnapToTargetIncludingScale, FName(TEXT("primary_socket")));
  962. }
  963. else
  964. {
  965. Item->SetActorHiddenInGame(true);
  966. }
  967. }
  968. }
  969.  
  970. bool ASoldier::PerformItemTask(EItemTaskEnum::Type Task, float Length)
  971. {
  972. if (SoldierTask < ESoldierTaskEnum::FullBody && ItemTask == EItemTaskEnum::None || (Task <= EItemTaskEnum::Undraw) && ItemTask != Task)
  973. {
  974. float Rate = 1.f;
  975. if ((Task >= EItemTaskEnum::Reload && Task <= EItemTaskEnum::ReloadChamber && HasPerk(EPerkEnum::FastReload)) || (Task <= EItemTaskEnum::Undraw && HasPerk(EPerkEnum::FastDraw)))
  976. {
  977. Rate = FastAnimationRate;
  978. }
  979.  
  980. const EItemTaskEnum::Type OldTask = ItemTask;
  981. ItemTask = Task;
  982.  
  983. // If length of task is <= 0 we want a really small number so that event gets executed on next tick
  984. GetWorld()->GetTimerManager().SetTimer(TimerHandle_ItemTask, this, &ASoldier::OnPerformedItemTask, Length > 0.f ? Length / Rate : 0.001f);
  985.  
  986. // Multicast new task to all clients
  987. MulticastSetItemTask(ItemTask);
  988.  
  989. return true;
  990. }
  991.  
  992. return false;
  993. }
  994.  
  995. void ASoldier::StopItemTask()
  996. {
  997. ItemTask = EItemTaskEnum::None;
  998. MulticastSetItemTask(ItemTask = EItemTaskEnum::None);
  999. GetWorldTimerManager().ClearTimer(TimerHandle_ItemTask);
  1000.  
  1001. if (GetMesh()->GetAnimInstance())
  1002. {
  1003. GetMesh()->GetAnimInstance()->StopSlotAnimation(0.25f, ItemAnimationSlot);
  1004. }
  1005. }
  1006.  
  1007. void ASoldier::MulticastSetItemTask_Implementation(EItemTaskEnum::Type NewTask)
  1008. {
  1009. if (GetNetMode() == NM_Client)
  1010. {
  1011. EItemTaskEnum::Type OldTask = ItemTask;
  1012. ItemTask = NewTask;
  1013. OnRep_ItemTask(OldTask);
  1014. }
  1015. }
  1016.  
  1017. void ASoldier::OnPerformedItemTask()
  1018. {
  1019. EItemTaskEnum::Type OldTask = ItemTask;
  1020. ItemTask = EItemTaskEnum::None;
  1021.  
  1022. if (OldTask != EItemTaskEnum::Undraw)
  1023. {
  1024. MulticastSetItemTask(ItemTask);
  1025. }
  1026.  
  1027. if (CurrentItem)
  1028. {
  1029. CurrentItem->OnPerformedTask(OldTask);
  1030. }
  1031. }
  1032.  
  1033. bool ASoldier::PerformSoldierTask(ESoldierTaskEnum Task, UAnimMontage * Montage, float Length)
  1034. {
  1035. if (SoldierTask == ESoldierTaskEnum::None)
  1036. {
  1037. /*if (Task > ESoldierTaskEnum::FullBody && ItemTask != EItemTaskEnum::None)
  1038. {
  1039. StopItemTask();
  1040. }*/
  1041. SoldierTask = Task;
  1042.  
  1043. const float MontageLength = PlayAnimMontage(Montage);
  1044. GetWorldTimerManager().SetTimer(TimerHandle_SoldierTask, this, &ASoldier::OnPerformedSoldierTask, Length != -1.f ? (Length > 0.f ? Length : 0.001f) : MontageLength);
  1045.  
  1046. OnSoldierTaskChanged();
  1047.  
  1048. return true;
  1049. }
  1050.  
  1051. return false;
  1052. }
  1053.  
  1054. void ASoldier::StopSoldierTask()
  1055. {
  1056. SoldierTask = ESoldierTaskEnum::None;
  1057. GetWorldTimerManager().ClearTimer(TimerHandle_SoldierTask);
  1058. OnSoldierTaskChanged();
  1059. }
  1060.  
  1061. void ASoldier::OnPerformedSoldierTask()
  1062. {
  1063. ESoldierTaskEnum OldTask = SoldierTask;
  1064. SoldierTask = ESoldierTaskEnum::None;
  1065. OnSoldierTaskChanged();
  1066.  
  1067. switch (OldTask)
  1068. {
  1069. case (ESoldierTaskEnum::None) :
  1070. break;
  1071. case (ESoldierTaskEnum::Interact) :
  1072. OnFinishedInteraction();
  1073. break;
  1074. }
  1075. }
  1076.  
  1077. void ASoldier::OnUndrewItem()
  1078. {
  1079. // CurrentItem was undrawn, setup new item
  1080. if (CurrentItem)
  1081. {
  1082. StoreItem(CurrentItem);
  1083.  
  1084. CurrentItem = Items[NextSlot];
  1085. if (CurrentItem)
  1086. {
  1087. InitCurrentItem();
  1088.  
  1089. if (bInstantFireItem && !CurrentItem->IsA<AFirearm>())
  1090. {
  1091. CurrentItem->StartFiring();
  1092. }
  1093. else
  1094. {
  1095. CurrentItem->Draw();
  1096. }
  1097. }
  1098. }
  1099. }
  1100.  
  1101. void ASoldier::PlayItemAnimation(UAnimSequenceBase * Sequence, float BlendInTime, float BlendOutTime, float PlaybackSpeed)
  1102. {
  1103. if (!Sequence) return;
  1104.  
  1105. if (Sequence->IsA<UAnimMontage>())
  1106. {
  1107. // TODO
  1108. UAnimMontage * Montage = Cast<UAnimMontage>(Sequence);
  1109. //Montage->BlendInTime = BlendInTime;
  1110. //Montage->BlendOutTime = BlendOutTime;
  1111. PlayAnimMontage(Montage, PlaybackSpeed);
  1112. }
  1113. else
  1114. {
  1115. if (GetMesh()->GetAnimInstance())
  1116. {
  1117. GetMesh()->GetAnimInstance()->PlaySlotAnimationAsDynamicMontage(Sequence, ItemAnimationSlot, BlendInTime, BlendOutTime, PlaybackSpeed);
  1118. }
  1119. }
  1120. }
  1121.  
  1122. void ASoldier::FireProjectile(TSubclassOf<ABaseProjectile> ProjectileClass, UCurveVector * RecoilCurve, const FVector & VisualRecoil)
  1123. {
  1124. FActorSpawnParameters SpawnParams;
  1125. SpawnParams.Instigator = this;
  1126. SpawnParams.Owner = CurrentItem;
  1127.  
  1128. FVector Location;
  1129. FRotator Rotation;
  1130. GetActorEyesViewPoint(Location, Rotation);
  1131.  
  1132. if (RecoilCurve)
  1133. {
  1134. // Evalute curve and update recoil
  1135. const FVector Recoil = RecoilCurve->GetVectorValue(BulletCount);
  1136. const float Imprecision = CurrentItem->GetImprecision(AimRatio, BulletCount, GetCharacterMovement()->Velocity);
  1137. Rotation += FRotator(FMath::FRandRange(-Imprecision, Imprecision), FMath::FRandRange(-Imprecision, Imprecision), FMath::FRandRange(-Imprecision, Imprecision));
  1138. TargetPitchRecoil += Recoil.X;
  1139. TargetYawRecoil += Recoil.Y;
  1140. }
  1141.  
  1142. // Multiplyer for item recoil
  1143. const float AimMultiplyer = FMath::Lerp(1.f, 0.8f, AimRatio);
  1144. // Apply item recoil to target item recoil
  1145. TargetItemRecoil += FVector(-VisualRecoil.X, FMath::FRandRange(-VisualRecoil.Y, VisualRecoil.Y), FMath::FRandRange(-VisualRecoil.Z, VisualRecoil.Z)) * AimMultiplyer;
  1146.  
  1147. // Raise bullet count
  1148. BulletCount += 1.f;
  1149.  
  1150. // Spawn actual projectile
  1151. GetWorld()->SpawnActor<AActor>(ProjectileClass, Location, Rotation, SpawnParams);
  1152. }
  1153.  
  1154. void ASoldier::ThrowProjectile(TSubclassOf<AThrowableProjectile> ProjectileClass)
  1155. {
  1156. FActorSpawnParameters SpawnParams;
  1157. SpawnParams.Instigator = this;
  1158. SpawnParams.Owner = CurrentItem;
  1159.  
  1160. FVector Location;
  1161. FRotator Rotation;
  1162. GetActorEyesViewPoint(Location, Rotation);
  1163.  
  1164. // Spawn projectile
  1165. GetWorld()->SpawnActor<AThrowableProjectile>(ProjectileClass, Location, Rotation, SpawnParams);
  1166. }
  1167.  
  1168. void ASoldier::OnClientStartAutoFire(float FireLength)
  1169. {
  1170. GetWorld()->GetTimerManager().SetTimer(TimerHandle_ItemTask, this, &ASoldier::OnClientAutoFire, FireLength);
  1171. }
  1172.  
  1173. void ASoldier::OnClientAutoFire()
  1174. {
  1175. // Only fire next round if server is still firing
  1176. if (CurrentItem && ItemTask == EItemTaskEnum::Fire)
  1177. {
  1178. CurrentItem->OnFire();
  1179. }
  1180. }
  1181.  
  1182. bool ASoldier::Stab(FHitResult & OutHit, float Damage, float MaxDistance)
  1183. {
  1184. FVector Location;
  1185. FRotator Rotation;
  1186. GetActorEyesViewPoint(Location, Rotation);
  1187.  
  1188. FCollisionQueryParams CollisionParams;
  1189. CollisionParams.AddIgnoredActor(this);
  1190. CollisionParams.bReturnPhysicalMaterial = true;
  1191.  
  1192. // Trace prjectile channel
  1193. if (GetWorld()->LineTraceSingleByChannel(OutHit, Location, Location + Rotation.Vector() * MaxDistance, ECC_GameTraceChannel1, CollisionParams))
  1194. {
  1195. if (OutHit.GetActor())
  1196. {
  1197. FPointDamageEvent DamageEvent;
  1198. DamageEvent.DamageTypeClass = UDamageType_Knife::StaticClass();
  1199. DamageEvent.Damage = Damage;
  1200. DamageEvent.HitInfo = OutHit;
  1201. DamageEvent.ShotDirection = Rotation.Vector();
  1202. OutHit.Actor->TakeDamage(Damage, DamageEvent, Controller, CurrentItem);
  1203. }
  1204.  
  1205. return true;
  1206. }
  1207.  
  1208. return false;
  1209. }
  1210.  
  1211. ETeamEnum ASoldier::GetTeam() const
  1212. {
  1213. ABasePlayerState * PS = Cast<ABasePlayerState>(PlayerState);
  1214. if (PS)
  1215. {
  1216. return PS->GetTeam();
  1217. }
  1218.  
  1219. return ETeamEnum::None;
  1220. }
  1221.  
  1222. bool ASoldier::IsEnemyFor(ASoldier * OtherSoldier) const
  1223. {
  1224. if (OtherSoldier)
  1225. {
  1226. return IsEnemyFor(Cast<ABasePlayerState>(OtherSoldier->PlayerState));
  1227. }
  1228.  
  1229. return false;
  1230. }
  1231.  
  1232. bool ASoldier::IsEnemyFor(ABasePlayerState * OtherPlayerState) const
  1233. {
  1234. ABasePlayerState * BasePlayerState = Cast<ABasePlayerState>(PlayerState);
  1235. if (BasePlayerState)
  1236. {
  1237. return BasePlayerState->IsEnemyFor(OtherPlayerState);
  1238. }
  1239.  
  1240. return false;
  1241. }
  1242.  
  1243. bool ASoldier::IsEnemyFor(ABasePlayerController * OtherPlayerController) const
  1244. {
  1245. if (OtherPlayerController)
  1246. {
  1247. return IsEnemyFor(Cast<ABasePlayerState>(OtherPlayerController->PlayerState));
  1248. }
  1249.  
  1250. return false;
  1251. }
  1252.  
  1253. void ASoldier::ServerUpdateInput_Implementation(const FSoldierInputStruct & PlayerInput)
  1254. {
  1255. bAiming = PlayerInput.bPressedAim;
  1256.  
  1257. // Fire
  1258. if (PlayerInput.bPressedFire)
  1259. {
  1260. if (!bFiring)
  1261. {
  1262. StartFiring();
  1263. }
  1264. }
  1265. else
  1266. {
  1267. if (bFiring)
  1268. {
  1269. StopFiring();
  1270. }
  1271. }
  1272.  
  1273. // Sprint
  1274. if (PlayerInput.bPressedSprint)
  1275. {
  1276. //if (!bSprinting)
  1277. //{
  1278. StartSprinting();
  1279. //}
  1280. }
  1281. else
  1282. {
  1283. if (bSprinting)
  1284. {
  1285. StopSprinting();
  1286. }
  1287. }
  1288.  
  1289. if (InteractionActor && !PlayerInput.bPressedInteract)
  1290. {
  1291. StopInteract();
  1292. }
  1293.  
  1294. LeanRatio = PlayerInput.LeanRatio;
  1295. }
  1296.  
  1297. bool ASoldier::ServerUpdateInput_Validate(const FSoldierInputStruct & PlayerInput)
  1298. {
  1299. return true;
  1300. }
  1301.  
  1302. void ASoldier::StartInteract()
  1303. {
  1304. bInteracting = true;
  1305.  
  1306. // Iterate all actors and try to interact with them
  1307. InteractWith(GetBestInteractionTarget());
  1308. }
  1309.  
  1310. bool ASoldier::InteractWith(AActor * TargetActor)
  1311. {
  1312. if (CanInteractWith(TargetActor))
  1313. {
  1314. if (GetNetMode() != NM_Client)
  1315. {
  1316. IInteractionInterface * InterfaceActor = Cast<IInteractionInterface>(TargetActor);
  1317. if (InterfaceActor)
  1318. {
  1319. if (PerformSoldierTask(ESoldierTaskEnum::Interact, InterfaceActor->GetInteractionMontage(this), InterfaceActor->GetInteractionLength()))
  1320. {
  1321. InteractionActor = TargetActor;
  1322. return true;
  1323. }
  1324. }
  1325. }
  1326. else
  1327. {
  1328. ServerInteractWith(TargetActor);
  1329. }
  1330. }
  1331.  
  1332. return false;
  1333. }
  1334.  
  1335. void ASoldier::ServerInteractWith_Implementation(AActor * TargetActor)
  1336. {
  1337. InteractWith(TargetActor);
  1338. }
  1339.  
  1340. bool ASoldier::ServerInteractWith_Validate(AActor * TargetActor)
  1341. {
  1342. return true;
  1343. }
  1344.  
  1345. bool ASoldier::CanInteractWith(AActor * InterfaceActor)
  1346. {
  1347. IInteractionInterface * Interface = Cast<IInteractionInterface>(InterfaceActor);
  1348. if (Interface)
  1349. {
  1350. FVector CameraLocation = Camera->GetComponentLocation();
  1351. const FVector InteractionLocation = Interface->GetInteractionLocation();
  1352. FVector ToVector = InteractionLocation - CameraLocation;
  1353. const float DistanceSquared = ToVector.SizeSquared();
  1354. ToVector.Normalize();
  1355. const float Angle = FMath::Acos(ToVector | GetControlRotation().Vector());
  1356. return DistanceSquared <= MaxInteractionDistanceSquared && Angle < MaxInteractionAngle && Interface->CanSoldierInteract(this);
  1357. }
  1358.  
  1359. return false;
  1360. }
  1361.  
  1362. AActor * ASoldier::GetBestInteractionTarget()
  1363. {
  1364. if (InteractionActor || SoldierTask == ESoldierTaskEnum::Interact) return InteractionActor;
  1365.  
  1366. // Iterate all actors and try to interact with them
  1367. for (FActorIterator ActorItr(GetWorld()); ActorItr; ++ActorItr)
  1368. {
  1369. if (CanInteractWith(*ActorItr))
  1370. {
  1371. return *ActorItr;
  1372. }
  1373. }
  1374.  
  1375. return NULL;
  1376. }
  1377.  
  1378. FVector ASoldier::GetInteractionLocation(AActor * Actor)
  1379. {
  1380. IInteractionInterface * Interface = Cast<IInteractionInterface>(Actor);
  1381. if (Interface)
  1382. {
  1383. return Interface->GetInteractionLocation();
  1384. }
  1385.  
  1386. return FVector::ZeroVector;
  1387. }
  1388.  
  1389. void ASoldier::StopInteract()
  1390. {
  1391. bInteracting = false;
  1392.  
  1393. if (GetNetMode() == NM_Client) return;
  1394.  
  1395. if (InteractionActor)
  1396. {
  1397. InteractionActor = NULL;
  1398. StopSoldierTask();
  1399. }
  1400. }
  1401.  
  1402. void ASoldier::OnFinishedInteraction()
  1403. {
  1404. IInteractionInterface * Interface = Cast<IInteractionInterface>(InteractionActor);
  1405. if (Interface && Interface->CanSoldierInteract(this))
  1406. {
  1407. // Execute actual interaction logic
  1408. Interface->OnInteract(this);
  1409. InteractionActor = NULL;
  1410. StopInteract();
  1411. }
  1412. }
  1413.  
  1414. void ASoldier::PickUpItem(AItem * Item)
  1415. {
  1416. if (!Item || !Item->CanBePickedUp()) return;
  1417.  
  1418. AddItem(Item);
  1419.  
  1420. if (Item != CurrentItem)
  1421. {
  1422. StoreItem(CurrentItem);
  1423. CurrentItem = Item;
  1424. InitCurrentItem();
  1425.  
  1426. CurrentItem->Draw();
  1427. }
  1428.  
  1429. // Set slot to the picked up item
  1430. /*for (uint8 i = 0; i < NumItemSlots; i++)
  1431. {
  1432. if (Items[i] == Item)
  1433. {
  1434. SetSlot(i);
  1435. break;
  1436. }
  1437. }*/
  1438. }
  1439.  
  1440. void ASoldier::MoveForward(float Val)
  1441. {
  1442. MoveRight(0);
  1443. AddMovementInput(GetActorForwardVector(), Val);
  1444. }
  1445.  
  1446. void ASoldier::MoveRight(float Val)
  1447. {
  1448. if (Val > 0 or Val <0) {
  1449. Bstrafe = true;
  1450. }else{
  1451. Bstrafe = false;
  1452. }
  1453. AddMovementInput(GetActorRightVector(), Val);
  1454. }
  1455.  
  1456. void ASoldier::AddControllerPitchInput(float Val)
  1457. {
  1458. Super::AddControllerPitchInput(Val * Camera->FieldOfView / DefaultFOV);
  1459. }
  1460.  
  1461. void ASoldier::AddControllerYawInput(float Val)
  1462. {
  1463. Super::AddControllerYawInput(Val * Camera->FieldOfView / DefaultFOV);
  1464. }
  1465.  
  1466. void ASoldier::StartSprinting()
  1467. {
  1468. MoveForward(0);
  1469. if (Bstrafe) {
  1470. MoveForward(0);
  1471. } else {
  1472. bSprinting = true;
  1473. }
  1474.  
  1475. }
  1476.  
  1477. void ASoldier::StopSprinting()
  1478. {
  1479. bSprinting = false;
  1480. }
  1481.  
  1482. void ASoldier::StartCrouching()
  1483. {
  1484. Crouch();
  1485. }
  1486.  
  1487. void ASoldier::StopCrouching()
  1488. {
  1489. UnCrouch();
  1490. }
  1491.  
  1492. void ASoldier::StartFiring()
  1493. {
  1494. bFiring = true;
  1495.  
  1496. if (GetNetMode() == NM_Client) return;
  1497.  
  1498. if (CurrentItem)
  1499. {
  1500. CurrentItem->StartFiring();
  1501. }
  1502. }
  1503.  
  1504. void ASoldier::StopFiring()
  1505. {
  1506. bFiring = false;
  1507.  
  1508. if (GetNetMode() == NM_Client) return;
  1509.  
  1510. if (CurrentItem)
  1511. {
  1512. CurrentItem->StopFiring();
  1513. }
  1514. }
  1515.  
  1516. void ASoldier::StartAiming()
  1517. {
  1518. bAiming = true;
  1519. }
  1520.  
  1521. void ASoldier::StopAiming()
  1522. {
  1523. bAiming = false;
  1524. }
  1525.  
  1526. void ASoldier::ToggleFireMode()
  1527. {
  1528. if (GetNetMode() == NM_Client)
  1529. {
  1530. ServerToggleFireMode();
  1531. return;
  1532. }
  1533.  
  1534. if (CurrentItem)
  1535. {
  1536. CurrentItem->ToggleFireMode();
  1537. }
  1538. }
  1539.  
  1540. void ASoldier::ToggleCameraMode()
  1541. {
  1542. bInThirdPersonMode = !bInThirdPersonMode;
  1543. }
  1544.  
  1545. void ASoldier::ServerToggleFireMode_Implementation()
  1546. {
  1547. ToggleFireMode();
  1548. }
  1549.  
  1550. bool ASoldier::ServerToggleFireMode_Validate()
  1551. {
  1552. return true;
  1553. }
  1554.  
  1555. void ASoldier::Reload()
  1556. {
  1557. if (GetNetMode() == NM_Client)
  1558. {
  1559. ServerReload();
  1560. return;
  1561. }
  1562.  
  1563. if (CurrentItem)
  1564. {
  1565. CurrentItem->Reload();
  1566. }
  1567. }
  1568.  
  1569. void ASoldier::ServerReload_Implementation()
  1570. {
  1571. Reload();
  1572. }
  1573.  
  1574. void ASoldier::DropItem()
  1575. {
  1576. if (!CurrentItem || !CurrentItem->CanBeDropped()) return;
  1577.  
  1578. if (GetNetMode() == NM_Client)
  1579. {
  1580. ServerDropItem();
  1581. return;
  1582. }
  1583.  
  1584. CurrentItem->Drop();
  1585.  
  1586. for (uint8 i = 0; i < NumItemSlots; i++)
  1587. {
  1588. if (Items[i] == CurrentItem)
  1589. {
  1590. // Remove CurrentItem from Items
  1591. Items[i] = NULL;
  1592. break;
  1593. }
  1594. }
  1595.  
  1596. ItemTask = EItemTaskEnum::None;
  1597.  
  1598. // Switch to first valid item
  1599. for (AItem * Item : Items)
  1600. {
  1601. if (Item)
  1602. {
  1603. CurrentItem = Item;
  1604. InitCurrentItem();
  1605. CurrentItem->Draw();
  1606. break;
  1607. }
  1608. }
  1609. }
  1610.  
  1611. void ASoldier::ServerDropItem_Implementation()
  1612. {
  1613. DropItem();
  1614. }
  1615.  
  1616. bool ASoldier::ServerDropItem_Validate()
  1617. {
  1618. return true;
  1619. }
  1620.  
  1621. bool ASoldier::ServerReload_Validate()
  1622. {
  1623. return true;
  1624. }
  1625.  
  1626. void ASoldier::EquipSlot0()
  1627. {
  1628. SetSlot(0);
  1629. }
  1630.  
  1631. void ASoldier::EquipSlot1()
  1632. {
  1633. SetSlot(1);
  1634. }
  1635.  
  1636. void ASoldier::EquipSlot2()
  1637. {
  1638. SetSlot(2);
  1639. }
  1640.  
  1641. void ASoldier::EquipSlot3()
  1642. {
  1643. SetSlot(3);
  1644. }
  1645.  
  1646. void ASoldier::EquipSlot4()
  1647. {
  1648. SetSlot(4);
  1649. }
  1650.  
  1651. void ASoldier::EquipSlot5()
  1652. {
  1653. SetSlot(5);
  1654. }
  1655.  
  1656. void ASoldier::EquipSlot6()
  1657. {
  1658. SetSlot(6);
  1659. }
  1660.  
  1661. void ASoldier::EquipNextItem()
  1662. {
  1663. // Search for first item after CurrentItem
  1664. bool bFoundCurrentItem = false;
  1665. for (uint8 i = 0; i < NumItemSlots; i++)
  1666. {
  1667. if (bFoundCurrentItem)
  1668. {
  1669. if (Items[i])
  1670. {
  1671. SetSlot(i);
  1672. break;
  1673. }
  1674. }
  1675. else
  1676. {
  1677. bFoundCurrentItem = Items[i] == CurrentItem;
  1678. }
  1679. }
  1680. }
  1681.  
  1682. void ASoldier::EquipPreviousItem()
  1683. {
  1684. // Search for first item before CurrentItem
  1685. bool bFoundCurrentItem = false;
  1686. for (uint8 i = NumItemSlots - 1; i >= 0; i--)
  1687. {
  1688. if (bFoundCurrentItem)
  1689. {
  1690. if (Items[i])
  1691. {
  1692. SetSlot(i);
  1693. break;
  1694. }
  1695. }
  1696. else
  1697. {
  1698. bFoundCurrentItem = Items[i] == CurrentItem;
  1699. }
  1700. }
  1701. }
  1702.  
  1703. void ASoldier::SetSlot(uint8 NewSlot, bool bInstantFire)
  1704. {
  1705. if (GetNetMode() == NM_Client)
  1706. {
  1707. ServerSetSlot(NewSlot, bInstantFire);
  1708. return;
  1709. }
  1710.  
  1711. if (NewSlot >= 0 && NewSlot < NumItemSlots && Items[NewSlot] && Items[NewSlot] != CurrentItem)
  1712. {
  1713. NextSlot = NewSlot;
  1714. bInstantFireItem = bInstantFire;
  1715.  
  1716. if (CurrentItem)
  1717. {
  1718. // Switch to new item after CurrentItem undrew
  1719. CurrentItem->Undraw();
  1720. }
  1721. else
  1722. {
  1723. // CurrentItem does not exist, we can switch to new item right away
  1724. CurrentItem = Items[NewSlot];
  1725.  
  1726. InitCurrentItem();
  1727. CurrentItem->Draw();
  1728. }
  1729. }
  1730. }
  1731.  
  1732. void ASoldier::ServerSetSlot_Implementation(uint8 NewSlot, bool bInstantFire)
  1733. {
  1734. SetSlot(NewSlot, bInstantFire);
  1735. }
  1736.  
  1737. bool ASoldier::ServerSetSlot_Validate(uint8 NewSlot, bool bInstantFire)
  1738. {
  1739. return true;
  1740. }
  1741.  
  1742. void ASoldier::ThrowGrenade()
  1743. {
  1744. EquipFirstItemOfClass<AThrowableItem>(true);
  1745. }
  1746.  
  1747. void ASoldier::Knife()
  1748. {
  1749. EquipFirstItemOfClass<AKnife>(true);
  1750. }
  1751.  
  1752. void ASoldier::OnRep_Health()
  1753. {
  1754. if (Health <= 0.f)
  1755. {
  1756. // Activate ragdoll if health <= 0
  1757. GetMesh()->SetAllBodiesSimulatePhysics(true);
  1758. bInThirdPersonMode = true;
  1759. }
  1760.  
  1761. // Set saturation
  1762. FPostProcessSettings & PPS = Camera->PostProcessSettings;
  1763. PPS.FilmSaturation = Health / DefaultHealth;
  1764. PPS.SceneFringeIntensity = FMath::GetMappedRangeValueClamped(FVector2D(0.f, 20.f), FVector2D(5.f, 0.f), Health);
  1765. PPS.VignetteIntensity = FMath::GetMappedRangeValueClamped(FVector2D(0.f, 50.f), FVector2D(1.f, 0.f), Health);
  1766. }
  1767.  
  1768. void ASoldier::OnRep_CharacterMesh()
  1769. {
  1770. if (CharacterMesh)
  1771. {
  1772. GetMesh()->SetSkeletalMesh(CharacterMesh);
  1773. }
  1774. }
  1775.  
  1776. void ASoldier::OnRep_CurrentItem(AItem * OldItem)
  1777. {
  1778. if (OldItem)
  1779. {
  1780. for (AItem * Item : Items)
  1781. {
  1782. if (Item == OldItem)
  1783. {
  1784. // Store previous CurrentItem
  1785. StoreItem(Item);
  1786. break;
  1787. }
  1788. }
  1789. }
  1790.  
  1791. if (CurrentItem)
  1792. {
  1793. if (CurrentItem->Instigator != this)
  1794. {
  1795. // Update Instigator on item if it is not up to date
  1796. CurrentItem->Instigator = this;
  1797. CurrentItem->OnRep_Instigator();
  1798. }
  1799.  
  1800. InitCurrentItem();
  1801.  
  1802. if (ItemTask == EItemTaskEnum::Undraw)
  1803. {
  1804. ItemTask = EItemTaskEnum::Draw;
  1805. }
  1806. else
  1807. {
  1808. OnRep_ItemTask(EItemTaskEnum::None);
  1809. }
  1810. }
  1811. }
  1812.  
  1813. void ASoldier::OnRep_ItemTask(EItemTaskEnum::Type OldTask)
  1814. {
  1815. if (CurrentItem && OldTask != EItemTaskEnum::Undraw)
  1816. {
  1817. CurrentItem->OnRep_Task(ItemTask);
  1818. }
  1819. }
  1820.  
  1821. void ASoldier::OnSoldierTaskChanged()
  1822. {
  1823. if (ItemTask != EItemTaskEnum::None && SoldierTask > ESoldierTaskEnum::FullBody)
  1824. {
  1825. StopItemTask();
  1826. }
  1827.  
  1828. switch (SoldierTask)
  1829. {
  1830. case (ESoldierTaskEnum::None) :
  1831. StopAnimMontage(SoldierTaskMontage);
  1832. break;
  1833. case (ESoldierTaskEnum::Interact) :
  1834. IInteractionInterface * Interface = Cast<IInteractionInterface>(InteractionActor);
  1835. if (Interface)
  1836. {
  1837. // TODO
  1838. SoldierTaskMontage = Interface->GetInteractionMontage(this);
  1839. PlayAnimMontage(SoldierTaskMontage);
  1840. }
  1841. break;
  1842. }
  1843. }
  1844.  
  1845. void ASoldier::OnRep_InteractionActor()
  1846. {
  1847. // Setup empty timer on clients so they also know the interaction time remaining
  1848. IInteractionInterface * Interface = Cast<IInteractionInterface>(InteractionActor);
  1849. if (Interface)
  1850. {
  1851. GetWorld()->GetTimerManager().SetTimer(TimerHandle_SoldierTask, Interface->GetInteractionLength(), false);
  1852. }
  1853. else
  1854. {
  1855. GetWorld()->GetTimerManager().ClearTimer(TimerHandle_SoldierTask);
  1856. StopInteract();
  1857. }
  1858. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement