// Returns true if the weapon hold by the character should be reloaded, false otherwise bool AMurphysLawCharacter::ShouldReload() const { return HasWeaponEquipped() && !GetEquippedWeapon()->IsReloading && GetEquippedWeapon()->GetNumberOfAmmoLeftInMagazine() <= 0 && GetEquippedWeapon()->GetNumberOfAmmoLeftInInventory() > 0; }
void cMonster::AddRandomWeaponDropItem(cItems & a_Drops, short a_LootingLevel) { MTRand r1; if (r1.randInt() % 200 < ((m_DropChanceWeapon * 200) + (a_LootingLevel * 2))) { if (!GetEquippedWeapon().IsEmpty()) a_Drops.push_back(GetEquippedWeapon()); } }
// Called when the player press a key to change his character's weapon void AMurphysLawCharacter::EquipWeapon(int32 Index) { // Checks if the index passed in parameter is within the boundaries of our Inventory if (Index >= Inventory->NumberOfWeaponInInventory) return; // Don't try to re-equip the weapon we already have in hand if (Index == CurrentWeaponIndex) return; // Allows the character to change weapon even if the current weapon is reloading GetEquippedWeapon()->IsReloading = false; // Plays a sound when switching weapon if available if (SwitchingWeaponSound != nullptr) { UGameplayStatics::PlaySoundAtLocation(this, SwitchingWeaponSound, GetActorLocation()); } // If the server modifies the value of the property, it is sent to the clients automatically if (Role == ROLE_Authority) { Server_ChangeCurrentWeapon_Implementation(Index); } else { // If a client wants to modify the value, it has to send a request to the server Server_ChangeCurrentWeapon(Index); } }
void AMurphysLawCharacter::Fire() { // check if we have a weapon equipped if (HasWeaponEquipped()) { // if the weapon has been able to fire if (GetEquippedWeapon()->Fire(this)) { // Stop the character from running SetIsRunning(false); // try and play a firing animation if specified if (FireAnimation != nullptr) { // Get the animation object for the arms mesh UAnimInstance* AnimInstance = Mesh1P->GetAnimInstance(); if (AnimInstance != nullptr) { AnimInstance->Montage_Play(FireAnimation, 1.f); } } // check for bullet collisions ComputeBulletCollisions(); } // We reload the weapon if it is empty and we have bullets left in our inventory if (ShouldReload()) { Reload(); } } }
void AMurphysLawCharacter::Aim() { if (HasWeaponEquipped()) { FirstPersonCameraComponent->FieldOfView = GetEquippedWeapon()->AimFactor; IsCharacterAiming = true; } }
bool AMurphysLawCharacter::CanPlayerMove() { bool CanMove = true; AMurphysLawBaseWeapon* CurrentWeapon = GetEquippedWeapon(); if (CurrentWeapon) CanMove = !(IsCrouched && CurrentWeapon->IsReloading); return CanMove; }
// Refills ammos for the current equipped weapon void AMurphysLawCharacter::ReceiveAmmo(const int32 NumberOfAmmo) { GetEquippedWeapon()->AddAmmoInInventory(NumberOfAmmo); // If the equipped weapon is empty when picking up ammos, it auto-reloads if (ShouldReload()) { Reload(); } }
// Called when the player press the Reload key void AMurphysLawCharacter::Reload() { // Checks if we have a weapon equipped if (HasWeaponEquipped()) { // If the weapon has been able to reload if (GetEquippedWeapon()->Reload()) { SetIsRunning(false); } } }
float AMurphysLawCharacter::GetDeliveredDamage(const FHitResult& CollisionResult) const { float DeliveredDamage = GetEquippedWeapon()->ComputeCollisionDamage(CollisionResult.Distance); FString BoneName = CollisionResult.BoneName.ToString(); if (BoneName == SOCKET_HEAD) DeliveredDamage *= FACTOR_HEADSHOT; else if (BoneName == SOCKET_SPINE) DeliveredDamage *= FACTOR_CHESTSHOT; return DeliveredDamage; }
// Refills ammos for the collected weapon or collects it if character didn't have it yet void AMurphysLawCharacter::CollectWeapon(class AMurphysLawBaseWeapon* Weapon) { Inventory->CollectWeapon(Weapon); // If the equipped weapon is empty when picking up the weapon and it's the same, it auto-reloads if (HasWeaponEquipped() && GetEquippedWeapon()->IsOfSameType(Weapon) && ShouldReload()) { Reload(); } }
void RPG_InventoryHandler::DebugDisplayInventory() { const float verticalOffset = 350.f; //@todo: Get the character's height here & replace offset magic number VString msg, tempLine; //@todo: Is there a less crufty way to build these strings? // add inventory list for (int i = 0; i < m_inventoryCollection.Count (); ++i) { tempLine.Format("Item #%i - %s\n", i, m_inventoryCollection.GetAt(i)->GetName().AsChar()); msg += tempLine; } tempLine.Format("Equipped:\n"); msg += tempLine; // add equipped weapon info if (GetEquippedWeapon()) { tempLine.Format("Equipped weapon: %s (Dmg: %.1f%%%% - %.1f%%%%, Spd: %.1f%%%%, Rng: %.1f)\n", GetEquippedWeapon()->GetName().AsChar(), GetEquippedWeapon()->GetMinDamage(), GetEquippedWeapon()->GetMaxDamage(), GetEquippedWeapon()->GetSpeed(), GetEquippedWeapon()->GetRange() ); } else { tempLine.Format("Equipped weapon: None\n"); } msg += tempLine; // add equipped armor info tempLine.Format("Equipped armor: %s (%i), %s (%i), %s (%i),\n %s (%i), %s (%i), %s (%i)\n", GetEquippedArmor(ES_Helmet) ? GetEquippedArmor(ES_Helmet)->GetName().AsChar() : "<None>", GetEquippedArmor(ES_Helmet) ? GetEquippedArmor(ES_Helmet)->GetArmorValue() : 0, GetEquippedArmor(ES_Chest) ? GetEquippedArmor(ES_Chest)->GetName().AsChar() : "<None>", GetEquippedArmor(ES_Chest) ? GetEquippedArmor(ES_Chest)->GetArmorValue() : 0, GetEquippedArmor(ES_Gloves) ? GetEquippedArmor(ES_Gloves)->GetName().AsChar() : "<None>", GetEquippedArmor(ES_Gloves) ? GetEquippedArmor(ES_Gloves)->GetArmorValue() : 0, GetEquippedArmor(ES_Shoulder) ? GetEquippedArmor(ES_Shoulder)->GetName().AsChar() : "<None>", GetEquippedArmor(ES_Shoulder) ? GetEquippedArmor(ES_Shoulder)->GetArmorValue() : 0, GetEquippedArmor(ES_Belt) ? GetEquippedArmor(ES_Belt)->GetName().AsChar() : "<None>", GetEquippedArmor(ES_Belt) ? GetEquippedArmor(ES_Belt)->GetArmorValue() : 0, GetEquippedArmor(ES_Boots) ? GetEquippedArmor(ES_Boots)->GetName().AsChar() : "<None>", GetEquippedArmor(ES_Boots) ? GetEquippedArmor(ES_Boots)->GetArmorValue() : 0 ); msg += tempLine; // display the message const hkvVec3 vPos = m_characterOwner->GetPosition() + hkvVec3(0.0f, 0.0f, verticalOffset); Vision::Message.DrawMessage3D(msg, vPos); }
// Executed when CurrentWeaponIndex is replicated void AMurphysLawCharacter::OnRep_CurrentWeaponIndex(int32 OldIndex) { auto OldWeapon = Inventory->GetWeapon(OldIndex); auto OldFullMeshWeapon = Inventory->GetFullMeshWeapon(OldIndex); auto NewFullMeshWeapon = Inventory->GetFullMeshWeapon(CurrentWeaponIndex); // Hide the old weapons if (OldWeapon != nullptr) OldWeapon->SetActorHiddenInGame(true); if (OldFullMeshWeapon != nullptr) OldFullMeshWeapon->SetActorHiddenInGame(true); // And show the new ones if (HasWeaponEquipped()) GetEquippedWeapon()->SetActorHiddenInGame(false); if (NewFullMeshWeapon != nullptr) NewFullMeshWeapon->SetActorHiddenInGame(false); }
// Makes the character die void AMurphysLawCharacter::Die() { Dead = true; IMurphysLawIController* PlayerController = Cast<IMurphysLawIController>(Controller); if (PlayerController) { PlayerController->OnKilled(TimeToRespawn); } // Disable collisions for the actor as he's dead SetActorEnableCollision(false); // Hide the current weapon of the player before destroying it if (HasWeaponEquipped()) { GetEquippedWeapon()->SetActorHiddenInGame(true); Inventory->GetFullMeshWeapon(CurrentWeaponIndex)->SetActorHiddenInGame(true); } }
// Reports if the character has a weapon equipped bool AMurphysLawCharacter::HasWeaponEquipped() const { return CurrentWeaponIndex != NO_WEAPON_VALUE && GetEquippedWeapon() != nullptr; }
// Check for bullet collisions void AMurphysLawCharacter::ComputeBulletCollisions() { // Only look for pawns FCollisionObjectQueryParams CollisionObjectQueryParams; CollisionObjectQueryParams.AddObjectTypesToQuery(ECollisionChannel::ECC_PhysicsBody); CollisionObjectQueryParams.AddObjectTypesToQuery(ECollisionChannel::ECC_Destructible); CollisionObjectQueryParams.AddObjectTypesToQuery(ECollisionChannel::ECC_WorldStatic); // Remove self from query potential results since we are the first to collide with the ray FCollisionQueryParams RayQueryParams; RayQueryParams.AddIgnoredActor(this); // Ray starting coordinates const FVector CollisionRayStart = GetFirstPersonCameraComponent()->GetComponentLocation(); const FVector CollisionRayInitialDirection = GetFirstPersonCameraComponent()->GetComponentTransform().GetRotation().GetAxisX(); // Group damage of touched objects together const float MaxFragmentDeviationRadian = FMath::DegreesToRadians(GetEquippedWeapon()->GetMaxFragmentDeviationAngle(IsCharacterAiming)); bool AtLeastOneHit = false; // Trace lines to detect pawn for (int32 i = 0; i < GetEquippedWeapon()->GetNumberOfEmittedFragments(); ++i) { // Ray ending coordinates const FVector CollisionRayAngledDirection = FMath::VRandCone(CollisionRayInitialDirection, MaxFragmentDeviationRadian); const FVector CollisionRayEnd = CollisionRayStart + (CollisionRayAngledDirection * GetEquippedWeapon()->GetMaxTravelDistanceOfBullet()); FHitResult CollisionResult; bool HasHit = GetWorld()->LineTraceSingleByObjectType(CollisionResult, CollisionRayStart, CollisionRayEnd, CollisionObjectQueryParams, RayQueryParams); if (HasHit) { // Simple damage amount considering the distance to the target depending on the bone hit float DeliveredDamage = GetDeliveredDamage(CollisionResult); FPointDamageEvent CollisionDamageEvent(DeliveredDamage, CollisionResult, CollisionRayAngledDirection, UDamageType::StaticClass()); // If the actor we hit is a hittable actor and an enemy, we have at least one hit so we'll show the Hit Marker if (IsHittableActor(CollisionResult.GetActor()) && !MurphysLawUtils::IsInSameTeam(CollisionResult.GetActor(), this)) { AtLeastOneHit = true; } if (Role == ROLE_Authority) { CollisionResult.GetActor()->TakeDamage(DeliveredDamage, CollisionDamageEvent, GetController(), this); } else { Server_TransferDamage(CollisionResult.GetActor(), DeliveredDamage, CollisionDamageEvent, GetController(), this); } } } // If there was at least one hit, we show the HitMarker if (AtLeastOneHit) { auto MyController = Cast<AMurphysLawPlayerController>(GetController()); if (MyController != nullptr && MyController->GetHUDInstance() != nullptr) { MyController->GetHUDInstance()->ShowHitMarker(); } } }
/** Defines a world-space point where an ai should look Since the gun is located in the center of the body, it is a good focal point */ AActor* AMurphysLawCharacter::GetFocalPoint() const { return GetEquippedWeapon(); }