// 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;
}
示例#2
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();
	}
}
示例#11
0
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(); }