Oh !
thanx for the help.
Here is my code :
// Fill out your copyright notice in the Description page of Project Settings.
#include "BaseCharacter.h"
#include "Items/Ammo/Ammo.h"
#include "TacticalOps.h"
#include "Game/BaseGameMode.h "
#include "Components/CapsuleComponent.h"
FOnBaseCharacterEquipWeapon ABaseCharacter::NotifyEquipWeapon;
FOnBaseCharacterUnEquipWeapon ABaseCharacter::NotifyUnEquipWeapon;
// Vault
#define VAULT_SWEEP_DIST 20.f
#define VAULT_SWEEP_SPHERE_RADIUS 20.f
#define MIN_VAULT_HEIGHT 70.f
#define MAX_VAULT_HEIGHT 130.f
// Sets default values
ABaseCharacter::ABaseCharacter(const FObjectInitializer & ObjectInitializer) :Super(ObjectInitializer)
{
Mesh1P = ObjectInitializer.CreateDefaultSubobject<USkeletalMeshComponent>(this, TEXT("PawnMesh1P"));
Mesh1P->SetupAttachment(GetCapsuleComponent());
Mesh1P->bOnlyOwnerSee = true;
Mesh1P->bOwnerNoSee = false;
Mesh1P->bCastDynamicShadow = false;
Mesh1P->bReceivesDecals = false;
Mesh1P->VisibilityBasedAnimTickOption = EVisibilityBasedAnimTickOption::OnlyTickPoseWhenRendered;
Mesh1P->PrimaryComponentTick.TickGroup = TG_PrePhysics;
Mesh1P->SetCollisionObjectType(ECC_Pawn);
Mesh1P->SetCollisionEnabled(ECollisionEnabled::NoCollision);
Mesh1P->SetCollisionResponseToAllChannels(ECR_Ignore);
GetMesh()->bOnlyOwnerSee = false;
GetMesh()->bOwnerNoSee = true;
GetMesh()->bReceivesDecals = false;
GetMesh()->SetCollisionObjectType(ECC_Pawn);
GetMesh()->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
//GetMesh()->SetCollisionResponseToChannel(COLLISION_WEAPON, ECR_Block);
//GetMesh()->SetCollisionResponseToChannel(COLLISION_PROJECTILE, ECR_Block);
GetMesh()->SetCollisionResponseToChannel(ECC_Visibility, ECR_Block);
//GetCapsuleComponent()->SetCollisionResponseToChannel(ECC_Camera, ECR_Ignore);
//GetCapsuleComponent()->SetCollisionResponseToChannel(COLLISION_PROJECTILE, ECR_Block);
//GetCapsuleComponent()->SetCollisionResponseToChannel(COLLISION_WEAPON, ECR_Ignore);
}
void ABaseCharacter::PostInitializeComponents()
{
Super::PostInitializeComponents();
if (Role == ROLE_Authority)
{
Health = HealthMax;
SpawnDefaultInventory();
}
// play respawn effects
if (GetNetMode() != NM_DedicatedServer)
{
/*if (RespawnFX)
{
UGameplayStatics::SpawnEmitterAtLocation(this, RespawnFX, GetActorLocation(), GetActorRotation());
}
if (RespawnSound)
{
UGameplayStatics::PlaySoundAtLocation(this, RespawnSound, GetActorLocation());
}*/
}
}
// Called when the game starts or when spawned
void ABaseCharacter::BeginPlay()
{
Super::BeginPlay();
}
void ABaseCharacter::Destroyed()
{
Super::Destroyed();
DestroyInventory();
}
///////////////////////////////////////////////////////
//inventory
void ABaseCharacter::AddPickable(APickable* Picked)
{
if (Picked ) //&& Role == ROLE_Authority a definir plus tard
{
if (ABaseWeapon* weapon = Cast <ABaseWeapon>(Picked))
{
AddWeapon(weapon);
}
else {
Picked->OnEnterInventory(this);
Inventory.AddUnique(Picked);
CurrentInventoryWeight = CurrentInventoryWeight + Picked->Weight;
Picked->IsPickable = false;
}
}
}
void ABaseCharacter::AddWeapon(ABaseWeapon* weapon)
{
if (weapon->WeapKind == EWeaponKind::SideGun)
{
if (SideGun == NULL)
{
weapon->OnEnterInventory(this);
Inventory.AddUnique(weapon);
SideGun = weapon;
weapon->CurrentSlot = EWeaponSlot::SideGun;
if (CurrentWeapon == NULL)
{
EquipSideGun();
}
}
else
{
RemoveWeapon(SideGun);
ThrowPickable(SideGun);
SideGun = NULL;
weapon->OnEnterInventory(this);
Inventory.AddUnique(weapon);
SideGun = weapon;
weapon->CurrentSlot = EWeaponSlot::SideGun;
EquipSideGun();
}
}
else
if (weapon->WeapKind == EWeaponKind::Shotgun || weapon->WeapKind == EWeaponKind::Rifle || weapon->WeapKind == EWeaponKind::SMG)
{
if (PrimaryWeapon == NULL)
{
weapon->OnEnterInventory(this);
Inventory.AddUnique(weapon);
PrimaryWeapon = weapon;
weapon->CurrentSlot = EWeaponSlot::Primary;
if (CurrentWeapon != NULL)
{
}
else EquipPrimary();
return;
}
if (PrimaryWeapon != NULL && SecondaryWeapon == NULL)
{
weapon->OnEnterInventory(this);
Inventory.AddUnique(weapon);
SecondaryWeapon = weapon;
weapon->CurrentSlot = EWeaponSlot::Secondary;
}
if (PrimaryWeapon != NULL && SecondaryWeapon != NULL)
{
if (CurrentWeapon == PrimaryWeapon)
{
RemoveWeapon(PrimaryWeapon);
ThrowPickable(PrimaryWeapon);
weapon->OnEnterInventory(this);
Inventory.AddUnique(weapon);
PrimaryWeapon = weapon;
weapon->CurrentSlot = EWeaponSlot::Primary;
}
if (CurrentWeapon == SecondaryWeapon)
{
RemoveWeapon(SecondaryWeapon);
ThrowPickable(SecondaryWeapon);
weapon->OnEnterInventory(this);
Inventory.AddUnique(weapon);
SecondaryWeapon = weapon;
weapon->CurrentSlot = EWeaponSlot::Secondary;
}
else
RemoveWeapon(PrimaryWeapon);
ThrowPickable(PrimaryWeapon);
weapon->OnEnterInventory(this);
Inventory.AddUnique(weapon);
PrimaryWeapon = weapon;
weapon->CurrentSlot = EWeaponSlot::Primary;
}
}
weapon->IsPickable = false;
}
bool ABaseCharacter::CanAddInventory(APickable* PickableToAdd)
{
if (PickableToAdd)
{
float Pickableweight = PickableToAdd->Weight;
if (ABaseWeapon* weapon = Cast <ABaseWeapon>(PickableToAdd))
{
return true;
}
else
{
if (Pickableweight + CurrentInventoryWeight < MaxInventoryWeight)
return true;
}
}
return false;
}
void ABaseCharacter::EquipWeapon( EWeaponSlot weaponslot)
{
if (Role == ROLE_Authority)
{
switch (weaponslot)
{
case (EWeaponSlot::Primary):
if (PrimaryWeapon != NULL)
{
CurrentWeapon = PrimaryWeapon;
CurrentWeapon->OnEquip(CurrentWeapon);
}
break;
case (EWeaponSlot::Secondary):
if (SecondaryWeapon != NULL)
{
CurrentWeapon = SecondaryWeapon;
CurrentWeapon->OnEquip(CurrentWeapon);
}
break;
case (EWeaponSlot::SideGun):
if (SideGun != NULL)
{
CurrentWeapon = SideGun;
CurrentWeapon->OnEquip(CurrentWeapon);
}
break;
}
}
else
{
ServerEquipWeapon( weaponslot);
}
}
bool ABaseCharacter::ServerEquipWeapon_Validate(EWeaponSlot weaponslot)
{
return true;
}
void ABaseCharacter::ServerEquipWeapon_Implementation( EWeaponSlot weaponslot)
{
EquipWeapon( weaponslot);
}
void ABaseCharacter::DestroyInventory()
{
if (Role < ROLE_Authority)
{
return;
}
// remove all weapons from inventory and destroy them
for (int32 i = Inventory.Num() - 1; i >= 0; i--)
{
APickable* Weapon = Inventory*;
if (Weapon)
{
//RemovePickable(Weapon);
Weapon->Destroy();
}
}
}
void ABaseCharacter::RemoveWeapon(class ABaseWeapon* weapon)
{
if (weapon && Role == ROLE_Authority)
{
weapon->OnLeaveInventory();
Inventory.RemoveSingle(weapon);
}
}
//on jette sur le sol l'objet dont on ne veut plus
void ABaseCharacter::ThrowPickable(APickable* PickableThrow)
{
PickableThrow->IsPickable = true;
//A compléter
}
void ABaseCharacter::SpawnDefaultInventory()
{
if (Role < ROLE_Authority)
{
return;
}
int32 NumWeaponClasses = DefaultInventoryClasses.Num();
for (int32 i = 0; i < NumWeaponClasses; i++)
{
if (DefaultInventoryClasses*)
{
FActorSpawnParameters SpawnInfo;
SpawnInfo.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
ABaseWeapon* NewWeapon = GetWorld()->SpawnActor<ABaseWeapon>(DefaultInventoryClasses*, SpawnInfo);
AddWeapon(NewWeapon);
}
}
}
void ABaseCharacter::EquipPrimary()
{
if (CurrentWeapon != PrimaryWeapon && PrimaryWeapon != NULL)
{//si current weapon n'est pas nul alors il faut déséquiper currrentweapon
if (CurrentWeapon!=NULL)
{
//EWeaponSlot SlotToDesequip=CurrentWeapon->CurrentSlot;
UnequipWeapon(CurrentWeapon);
EquipWeapon(EWeaponSlot::Primary);
}
else
{
EquipWeapon(EWeaponSlot::Primary);
}
}
}
void ABaseCharacter::EquipSecondary()
{
if (CurrentWeapon != SecondaryWeapon && SecondaryWeapon != NULL)
{//si current weapon n'est pas nul alors il faut déséquiper currrentweapon
if (CurrentWeapon != NULL)
{
EWeaponSlot SlotToDesequip = CurrentWeapon->CurrentSlot;
//UnequipWeapon();
EquipWeapon(EWeaponSlot::Secondary);
}
else
{
EquipWeapon(EWeaponSlot::Secondary);
}
}
}
void ABaseCharacter::EquipSideGun()
{
}
void ABaseCharacter::EquipThrowable()
{
}
void ABaseCharacter::OnNextWeapon()
{
if (CurrentWeapon != NULL)
{
switch (CurrentWeapon->CurrentSlot)
{
case (EWeaponSlot::Primary):
if (SecondaryWeapon != NULL)
{
UnequipWeapon(PrimaryWeapon);
EquipSecondary();
return;
}
if (SideGun != NULL)
{
UnequipWeapon(PrimaryWeapon);
EquipSideGun();
return;
}
if (Throwable!=NULL)
{
UnequipWeapon(PrimaryWeapon);
EquipThrowable();
}
break;
case(EWeaponSlot::Secondary):
if (SideGun != NULL)
{
UnequipWeapon(SecondaryWeapon);
EquipSideGun();
return;
}
if (Throwable != NULL)
{
UnequipWeapon(SecondaryWeapon);
EquipThrowable();
}
if (PrimaryWeapon != NULL)
{
UnequipWeapon(SecondaryWeapon);
EquipPrimary();
return;
}
break;
}
}
else
if (PrimaryWeapon != NULL)
{
EquipPrimary();
}
}
void ABaseCharacter::OnPreviousWeapon()
{
if (CurrentWeapon != NULL)
{
switch (CurrentWeapon->CurrentSlot)
{
case (EWeaponSlot::Primary):
if (Throwable != NULL)
{
EquipThrowable();
}
break;
if (SideGun != NULL)
{
EquipSideGun();
return;
}
if (SecondaryWeapon != NULL)
{
EquipSecondary();
return;
}
}
}
}
void ABaseCharacter::UnequipWeapon(ABaseWeapon* WeaponToUnequip)
{
if (CurrentWeapon != NULL)
{
CurrentWeapon->OnUnEquip();
CurrentWeapon = NULL;
}
}
/////////////////////////////////////////////////////////
//Replication
void ABaseCharacter::GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME_CONDITION(ABaseCharacter, Inventory,COND_OwnerOnly);
//DOREPLIFETIME(ABaseCharacter, DefaultInventoryClasses);
DOREPLIFETIME(ABaseCharacter, CurrentWeapon);
DOREPLIFETIME(ABaseCharacter,PrimaryWeapon );
DOREPLIFETIME(ABaseCharacter, SecondaryWeapon);
DOREPLIFETIME(ABaseCharacter, SideGun);
DOREPLIFETIME(ABaseCharacter, Health);
}
void ABaseCharacter::OnRep_CurrentWeapon(class ABaseWeapon* LastWeapon)
{
LastWeapon->SetOwningPawn(this);
}
//////////////////////////////////////////////////////
//Inputs
// Called to bind functionality to input
void ABaseCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
check(PlayerInputComponent);
PlayerInputComponent->BindAxis("MoveForward", this, &ABaseCharacter::MoveForward);
PlayerInputComponent->BindAxis("MoveForward", this, &ABaseCharacter::MoveRight);
PlayerInputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput);
PlayerInputComponent->BindAxis("TurnRate", this, &ABaseCharacter::TurnAtRate);
PlayerInputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput);
PlayerInputComponent->BindAxis("LookUpRate", this, &ABaseCharacter::LookUpAtRate);
PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ABaseCharacter::Jump);
PlayerInputComponent->BindAction("Jump", IE_Released, this, &ABaseCharacter::StopJumping);
//PlayerInputComponent->BindAction("Crouch", IE_Pressed, this, &ABaseCharacter::Crouch);
//PlayerInputComponent->BindAction("Crouch", IE_Released, this, &ABaseCharacter::StopCrouching);
PlayerInputComponent->BindAction("FireMode", IE_Pressed, this, &ABaseCharacter::ChangeFireMode);
PlayerInputComponent->BindAction("Fire", IE_Pressed, this, &ABaseCharacter::Fire);
PlayerInputComponent->BindAction("Reload", IE_Pressed, this, &ABaseCharacter::Reload);
PlayerInputComponent->BindAction("NextWeapon", IE_Pressed, this, &ABaseCharacter::OnNextWeapon);
PlayerInputComponent->BindAction("PreviousWeapon", IE_Pressed, this, &ABaseCharacter::OnPreviousWeapon);
PlayerInputComponent->BindAction("EquipPrimary", IE_Pressed, this, &ABaseCharacter::EquipPrimary);
PlayerInputComponent->BindAction("EquipSecondary", IE_Pressed, this, &ABaseCharacter::EquipSecondary);
}
void ABaseCharacter::MoveForward(float Val)
{
if (Controller && Val != 0.f)
{
// Limit pitch when walking or falling
const bool bLimitRotation = (GetCharacterMovement()->IsMovingOnGround() || GetCharacterMovement()->IsFalling());
const FRotator Rotation = bLimitRotation ? GetActorRotation() : Controller->GetControlRotation();
const FVector Direction = FRotationMatrix(Rotation).GetScaledAxis(EAxis::X);
AddMovementInput(Direction, Val);
}
}
void ABaseCharacter::MoveRight(float Val)
{
if (Val != 0.f)
{
const FQuat Rotation = GetActorQuat();
const FVector Direction = FQuatRotationMatrix(Rotation).GetScaledAxis(EAxis::Y);
AddMovementInput(Direction, Val);
}
}
void ABaseCharacter::TurnAtRate(float Val)
{
// calculate delta for this frame from the rate information
AddControllerYawInput(Val * BaseTurnRate * GetWorld()->GetDeltaSeconds());
}
void ABaseCharacter::LookUpAtRate(float Val)
{
// calculate delta for this frame from the rate information
AddControllerPitchInput(Val * BaseLookUpRate * GetWorld()->GetDeltaSeconds());
}
void ABaseCharacter::Jump()
{
FCollisionQueryParams QueryParams;
QueryParams.AddIgnoredActor(this);
const float CapsuleHalfHeight = GetCapsuleComponent()->GetScaledCapsuleHalfHeight();
const float CapsuleRadius = GetCapsuleComponent()->GetScaledCapsuleRadius();
const FVector ForwardVector = GetActorForwardVector();
const FVector SweepStart = GetActorLocation() + FVector(0.f, 0.f, CapsuleHalfHeight) + ForwardVector * (CapsuleRadius + VAULT_SWEEP_DIST);
const FVector SweepEnd = SweepStart - FVector(0.f, 0.f, CapsuleHalfHeight * 2.f);
FHitResult Hit;
if (GetWorld()->SweepSingleByChannel(Hit, SweepStart, SweepEnd, FQuat::Identity, ECC_Pawn, FCollisionShape::MakeSphere(VAULT_SWEEP_SPHERE_RADIUS), QueryParams))
{
const float ObstacleHeight = Hit.ImpactPoint.Z - SweepEnd.Z;
if (ObstacleHeight > MIN_VAULT_HEIGHT && ObstacleHeight < MAX_VAULT_HEIGHT)
{
Vault();
return;
}
}
Super::Jump();
}
void ABaseCharacter::Vault()
{
//PlayAnimMontage(VaultMontage);
}
bool ABaseCharacter::IsFirstPerson() const
{
return IsAlive() && Controller && Controller->IsLocalPlayerController();
}
bool ABaseCharacter::IsAlive() const
{
return Health > 0;
}
USkeletalMeshComponent* ABaseCharacter::GetPawnMesh() const
{
return IsFirstPerson() ? Mesh1P : GetMesh();
}
USkeletalMeshComponent* ABaseCharacter::GetSpecifcPawnMesh(bool WantFirstPerson) const
{
return WantFirstPerson == true ? Mesh1P : GetMesh();
}
FName ABaseCharacter::GetWeaponAttachPoint() const
{
return WeaponAttachPoint;
}
/////////////////////////////////////////////////////
//Damage
float ABaseCharacter::TakeDamage(float Damage, struct FDamageEvent const& DamageEvent, class AController* EventInstigator, class AActor* DamageCauser)
{
if (Health <= 0.f)
{
return 0.f;
}
// Modify based on game rules.
ABaseGameMode* const Game = GetWorld()->GetAuthGameMode<ABaseGameMode>();
Damage = Game ? Game->ModifyDamage(Damage, this, DamageEvent, EventInstigator, DamageCauser) : 0.f;
const float ActualDamage = Super::TakeDamage(Damage, DamageEvent, EventInstigator, DamageCauser);
if (ActualDamage > 0.f)
{
Health -= ActualDamage;
if (Health <= 0)
{
Die(ActualDamage, DamageEvent, EventInstigator, DamageCauser);
}
/*else
{
PlayHit(ActualDamage, DamageEvent, EventInstigator ? EventInstigator->GetPawn() : NULL, DamageCauser);
}
MakeNoise(1.0f, EventInstigator ? EventInstigator->GetPawn() : this);*/
}
return ActualDamage;
}
bool ABaseCharacter::Die(float KillingDamage, FDamageEvent const& DamageEvent, AController* Killer, AActor* DamageCauser)
{
/*if (!CanDie(KillingDamage, DamageEvent, Killer, DamageCauser))
{
return false;
}*/
Health = FMath::Min(0.0f, Health);
// if this is an environmental death then refer to the previous killer so that they receive credit (knocked into lava pits, etc)
/*UDamageType const* const DamageType = DamageEvent.DamageTypeClass ? DamageEvent.DamageTypeClass->GetDefaultObject<UDamageType>() : GetDefault<UDamageType>();
Killer = GetDamageInstigator(Killer, *DamageType);
AController* const KilledPlayer = (Controller != NULL) ? Controller : Cast<AController>(GetOwner());
GetWorld()->GetAuthGameMode<AShooterGameMode>()->Killed(Killer, KilledPlayer, this, DamageType);
NetUpdateFrequency = GetDefault<AShooterCharacter>()->NetUpdateFrequency;
GetCharacterMovement()->ForceReplicationUpdate();
OnDeath(KillingDamage, DamageEvent, Killer ? Killer->GetPawn() : NULL, DamageCauser);*/
return true;
}
//////////////////////////////////////////////////////////////////////////
// Animations
float ABaseCharacter::PlayAnimMontage(class UAnimMontage* AnimMontage, float InPlayRate, FName StartSectionName)
{
USkeletalMeshComponent* UseMesh = GetPawnMesh();
if (AnimMontage && UseMesh && UseMesh->AnimScriptInstance)
{
return UseMesh->AnimScriptInstance->Montage_Play(AnimMontage, InPlayRate);
}
return 0.0f;
}
void ABaseCharacter::StopAnimMontage(class UAnimMontage* AnimMontage)
{
USkeletalMeshComponent* UseMesh = GetPawnMesh();
if (AnimMontage && UseMesh && UseMesh->AnimScriptInstance &&
UseMesh->AnimScriptInstance->Montage_IsPlaying(AnimMontage))
{
UseMesh->AnimScriptInstance->Montage_Stop(AnimMontage->BlendOut.GetBlendTime(), AnimMontage);
}
}
void ABaseCharacter::StopAllAnimMontages()
{
USkeletalMeshComponent* UseMesh = GetPawnMesh();
if (UseMesh && UseMesh->AnimScriptInstance)
{
UseMesh->AnimScriptInstance->Montage_Stop(0.0f);
}
}
//////////////////////////////////////////////////////////////////////
//Fire and weapons management
void ABaseCharacter::Fire()
{
if (CanFire())
{
if (Role == ROLE_Authority)
{
TriggerPulled = true;
CurrentWeapon->WeaponFire(true);
}
else ServerFire();
}
}
void ABaseCharacter::OnStopFire()
{
TriggerPulled = false;
CurrentWeapon->WeaponFire(false);
}
bool ABaseCharacter::CanFire()
{
if (CurrentWeapon != NULL && !IsReloading && CurrentWeapon->GetIsEquiped())
{
return true;
}
else return false;
}
bool ABaseCharacter::ServerFire_Validate()
{
return true;
}
void ABaseCharacter::ServerFire_Implementation()
{
Fire();
}
void ABaseCharacter::ChangeFireMode()
{
if (CurrentWeapon != NULL)
{
CurrentWeapon->SetCurrentFireMode();
}
}
int8 ABaseCharacter::GetAmmo(EAmmoKind Ammo)
{
int8 AmmoToReturn = 0;
for (int32 i = Inventory.Num() - 1; i >= 0; i--)
{
APickable* Ammotocheck = Inventory*;
if (AAmmo* ItemTocheck = Cast<AAmmo>(Ammotocheck))
{
if (ItemTocheck != NULL && ItemTocheck->AmmoType == Ammo)
{
AmmoToReturn = ItemTocheck->AmmoCount;
if (CurrentWeapon->HasFastExtandedMag)
{
ItemTocheck->GetAmmo(CurrentWeapon->MaxAmmoWithExtandedMag);
}
else
{
ItemTocheck->GetAmmo(CurrentWeapon->MaxAmmo);
}
}
}
}
return AmmoToReturn;
}
void ABaseCharacter::Reload()
{
if (Role == ROLE_Authority)
{
if (CurrentWeapon != NULL)
{
IsReloading = true;
CurrentWeapon->WeaponReload();
IsReloading = false;
}
}
else ServerReload();
}
bool ABaseCharacter::ServerReload_Validate()
{
return true;
}
void ABaseCharacter::ServerReload_Implementation()
{
Reload();
}