79 lines
9.2 KiB
C++
79 lines
9.2 KiB
C++
#include "IronsGame.h"
|
|
#include "Camera/CameraComponent.h"
|
|
#include "GameFramework/SpringArmComponent.h"
|
|
#include "GameFramework/CharacterMovementComponent.h"
|
|
#include "Components/CapsuleComponent.h"
|
|
#include "Components/StaticMeshComponent.h"
|
|
#include "Kismet/GameplayStatics.h"
|
|
#include "EngineUtils.h"
|
|
#include "DrawDebugHelpers.h"
|
|
#include "Sound/SoundBase.h"
|
|
|
|
namespace {
|
|
void Sound(UWorld* World,const TCHAR* Name,float Volume){FString P=FString::Printf(TEXT("/Game/IRONSPORE/Audio/%s.%s"),Name,Name);if(auto S=LoadObject<USoundBase>(nullptr,*P))UGameplayStatics::PlaySound2D(World,S,Volume);}
|
|
void Blast(UWorld* W,FVector P,float Damage,float Radius){for(TActorIterator<AIronsEnemy> I(W);I;++I){float D=FVector::Dist(I->GetActorLocation(),P);float Amount=gf::radialDamage(Damage,D*.01f,Radius*.01f);if(Amount>0)I->Hit(Amount);}DrawDebugSphere(W,P,Radius,20,FColor::Orange,false,.35f,0,3);}
|
|
}
|
|
AIronsCharacter::AIronsCharacter(){
|
|
PrimaryActorTick.bCanEverTick=true;
|
|
GetCapsuleComponent()->InitCapsuleSize(65,160);
|
|
Body=CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MechBody"));Body->SetupAttachment(GetRootComponent());Body->SetRelativeLocation(FVector(0,0,-160));Body->SetCollisionEnabled(ECollisionEnabled::NoCollision);
|
|
Arm=CreateDefaultSubobject<USpringArmComponent>(TEXT("ShoulderArm"));Arm->SetupAttachment(GetRootComponent());Arm->TargetArmLength=600;Arm->SocketOffset=FVector(0,125,90);Arm->bUsePawnControlRotation=true;
|
|
Camera=CreateDefaultSubobject<UCameraComponent>(TEXT("DualViewCamera"));Camera->SetupAttachment(Arm);Camera->FieldOfView=70;
|
|
bUseControllerRotationYaw=true;GetCharacterMovement()->bOrientRotationToMovement=false;GetCharacterMovement()->JumpZVelocity=700;GetCharacterMovement()->GravityScale=2.04f;GetCharacterMovement()->MaxStepHeight=65;GetCharacterMovement()->AirControl=.5f;
|
|
}
|
|
UIronsGameInstance* AIronsCharacter::Host()const{return Cast<UIronsGameInstance>(GetGameInstance());}
|
|
void AIronsCharacter::BeginPlay(){Super::BeginPlay();Body->SetStaticMesh(LoadObject<UStaticMesh>(nullptr,TEXT("/Game/IRONSPORE/Art/Mechs/SM_MechScout.SM_MechScout")));Body->SetRelativeRotation(FRotator(0,-90,0));if(auto H=Host()){int Chassis=H->Core().state().run.chassis;Body->SetRelativeScale3D(Chassis==0?FVector(.85f,.85f,.92f):Chassis==2?FVector(1.15f,1.13f,1.05f):FVector::OneVector);}}
|
|
void AIronsCharacter::SwitchView(){bCockpit=!bCockpit;Arm->TargetArmLength=bCockpit?0:600;Arm->SocketOffset=bCockpit?FVector(25,0,125):FVector(0,125,90);Body->SetVisibility(!bCockpit,true);}
|
|
void AIronsCharacter::Tick(float Dt){
|
|
Super::Tick(Dt);auto H=Host();auto PC=Cast<AIronsController>(GetController());if(!H||!H->bReady||!PC||!PC->Playing())return;
|
|
auto& S=H->Core();auto& R=S.state().run;
|
|
GetCharacterMovement()->MaxWalkSpeed=(H->Combat.boost>0?S.catalog().chassis[R.chassis].boostSpeed:S.moveSpeed())*100;
|
|
Camera->SetFieldOfView(FMath::FInterpTo(Camera->FieldOfView,bAim?50.f:bCockpit?78.f:70.f,Dt,12));
|
|
if(H->Combat.boost>0){FVector D=GetLastMovementInputVector();if(D.IsNearlyZero())D=GetActorForwardVector();GetCharacterMovement()->Velocity=D.GetSafeNormal()*GetCharacterMovement()->MaxWalkSpeed+FVector(0,0,GetVelocity().Z);}
|
|
if(PC->IsInputKeyDown(FKey(*H->Keys[4]))&&!GetCharacterMovement()->IsMovingOnGround()){float Lift=S.lift(Dt);if(Lift>0)GetCharacterMovement()->Velocity.Z=Lift*100;}
|
|
if(R.armor<=0&&H->FinishSortie(true))PC->ReturnHome();
|
|
}
|
|
void AIronsCharacter::ReceiveHit(float Damage){auto H=Host();if(!H||!H->Core().state().run.active)return;H->Core().takeDamage(H->Combat,Damage);DamageTime=GetWorld()->GetTimeSeconds();Sound(GetWorld(),TEXT("S_Impact"),H->MasterVolume*.6f);}
|
|
void AIronsCharacter::Shoot(bool Secondary){
|
|
auto H=Host();if(!H||!H->Core().fire(H->Combat,Secondary))return;
|
|
auto& S=H->Core();auto P=S.catalog().part(Secondary?1:0,S.state().run.equipment[Secondary?1:0]);if(!P)return;
|
|
FVector Eye=Camera->GetComponentLocation(),Dir=Camera->GetForwardVector(),End=Eye+Dir*18000;
|
|
FCollisionQueryParams Q(SCENE_QUERY_STAT(IronsAim),true,this);FHitResult Aim;GetWorld()->LineTraceSingleByChannel(Aim,Eye,End,ECC_Visibility,Q);FVector TargetPoint=Aim.bBlockingHit?Aim.ImpactPoint:End;
|
|
FVector Muzzle=GetActorLocation()+GetActorForwardVector()*125+GetActorRightVector()*75+FVector(0,0,45);
|
|
float Damage=S.shotDamage(Secondary),Radius=S.blastRadius(Secondary)*100;
|
|
if(Secondary&&P->guided){
|
|
FActorSpawnParameters Params;Params.Owner=this;auto Missile=GetWorld()->SpawnActor<AIronsProjectile>(Muzzle,(TargetPoint-Muzzle).Rotation(),Params);Missile->Damage=Damage;Missile->Radius=Radius;Missile->Velocity=(TargetPoint-Muzzle).GetSafeNormal()*2200;
|
|
float Best=.96f;for(TActorIterator<AIronsEnemy> I(GetWorld());I;++I){float Dot=FVector::DotProduct(Dir,(I->GetActorLocation()-Eye).GetSafeNormal());if(Dot>Best){Best=Dot;Missile->Target=*I;}}
|
|
}else if(Secondary){Blast(GetWorld(),Muzzle+Dir*700,Damage,Radius);}
|
|
else {
|
|
FHitResult Hit;GetWorld()->LineTraceSingleByChannel(Hit,Muzzle,TargetPoint+Dir*15,ECC_Visibility,Q);
|
|
FVector Impact=Hit.bBlockingHit?Hit.ImpactPoint:TargetPoint;
|
|
if(Radius>0)Blast(GetWorld(),Impact,Damage,Radius);else if(auto E=Cast<AIronsEnemy>(Hit.GetActor()))E->Hit(Damage);
|
|
DrawDebugLine(GetWorld(),Muzzle,Impact,P->id=="coil"?FColor::Cyan:FColor(255,185,75),false,.07f,0,P->id=="coil"?5:2);
|
|
if(Hit.bBlockingHit)DrawDebugSphere(GetWorld(),Impact,15,8,FColor::Orange,false,.12f);
|
|
}
|
|
FireFlash=.1f;Sound(GetWorld(),Secondary?TEXT("S_Secondary"):TEXT("S_Shot"),H->MasterVolume*.55f);
|
|
}
|
|
AIronsEnemy::AIronsEnemy(){PrimaryActorTick.bCanEverTick=true;Body=CreateDefaultSubobject<UStaticMeshComponent>(TEXT("EnemyBody"));SetRootComponent(Body);Body->SetCollisionProfileName(TEXT("BlockAllDynamic"));}
|
|
void AIronsEnemy::BeginPlay(){Super::BeginPlay();if(EntityId.IsEmpty())EntityId=GetName();if(auto H=Cast<UIronsGameInstance>(GetGameInstance()))H->Core().registerEnemy(TCHAR_TO_UTF8(*EntityId),Type,bTerminal);
|
|
Body->SetStaticMesh(LoadObject<UStaticMesh>(nullptr,Type==1?TEXT("/Engine/BasicShapes/Sphere.Sphere"):Type==2||Type>=4?TEXT("/Engine/BasicShapes/Cube.Cube"):TEXT("/Game/IRONSPORE/Art/Mechs/SM_MechScout.SM_MechScout")));
|
|
SetActorScale3D(FVector(Type==3?1.5f:Type==1?1.1f:Type==2?1.7f:.8f));
|
|
if(Type>=4)SetActorScale3D(FVector(2.1f,.35f,2.3f));
|
|
}
|
|
void AIronsEnemy::Hit(float Damage){auto H=Cast<UIronsGameInstance>(GetGameInstance());if(!H)return;bool Dead=H->Core().damageEnemy(TCHAR_TO_UTF8(*EntityId),Damage);if(Type>=4)DrawDebugSphere(GetWorld(),GetActorLocation(),90,10,FColor::Cyan,false,.15f,0,5);if(Dead){
|
|
if(Type!=1){FActorSpawnParameters Params;auto Loot=GetWorld()->SpawnActor<AIronsMarker>(GetActorLocation()+FVector(0,0,50),FRotator::ZeroRotator,Params);Loot->Kind=TEXT("loot");Loot->ItemId=Type==3?TEXT("reactive_guard"):Type==2?TEXT("cells"):TEXT("alloy");Loot->Quantity=Type==2?3:Type==3?1:4;Loot->SourceKey=TEXT("wreck-")+EntityId;}
|
|
SetActorHiddenInGame(true);SetActorEnableCollision(false);SetActorTickEnabled(bTerminal&&!H->Core().state().run.routeCompleted);DrawDebugSphere(GetWorld(),GetActorLocation()+FVector(0,0,120),150,12,FColor::Orange,false,.6f,0,8);
|
|
}}
|
|
void AIronsEnemy::Tick(float Dt){
|
|
Super::Tick(Dt);auto PC=Cast<AIronsController>(UGameplayStatics::GetPlayerController(this,0));auto H=Cast<UIronsGameInstance>(GetGameInstance());if(!PC||!PC->Playing()||!H||!PC->Mech())return;
|
|
if(Type>=4){if(Type==5){FVector L=GetActorLocation();L.X=-3500+FMath::Sin(GetWorld()->GetTimeSeconds())*450;SetActorLocation(L);}return;}
|
|
auto P=PC->Mech();FVector Origin=GetActorLocation()+FVector(0,0,Type==1?0:160),Target=P->GetActorLocation();FHitResult Hit;FCollisionQueryParams Q(SCENE_QUERY_STAT(IronsAI),true,this);GetWorld()->LineTraceSingleByChannel(Hit,Origin,Target,ECC_Visibility,Q);
|
|
auto D=H->Core().stepEnemy(TCHAR_TO_UTF8(*EntityId),Dt,FVector::Dist(Origin,Target)*.01f,!Hit.bBlockingHit||Hit.GetActor()==P);
|
|
if(D.fire){P->ReceiveHit(D.damage);DrawDebugLine(GetWorld(),Origin,Target,FColor::Red,false,.12f,0,2);}
|
|
if(D.moveSpeed>0){FVector Delta=(Target-Origin).GetSafeNormal2D()*D.moveSpeed*100*Dt;SetActorLocation(GetActorLocation()+Delta,true);SetActorRotation(FRotator(0,(Target-Origin).Rotation().Yaw,0));}
|
|
if(D.fly){FVector L=GetActorLocation();L.Z=350+FMath::Sin(GetWorld()->GetTimeSeconds()*1.7f)*60;SetActorLocation(L);}
|
|
}
|
|
AIronsProjectile::AIronsProjectile(){PrimaryActorTick.bCanEverTick=true;Body=CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Missile"));SetRootComponent(Body);Body->SetCollisionEnabled(ECollisionEnabled::NoCollision);Body->SetStaticMesh(LoadObject<UStaticMesh>(nullptr,TEXT("/Engine/BasicShapes/Sphere.Sphere")));SetActorScale3D(FVector(.2f));InitialLifeSpan=8;}
|
|
void AIronsProjectile::Tick(float Dt){Super::Tick(Dt);if(auto PC=Cast<AIronsController>(UGameplayStatics::GetPlayerController(this,0));!PC||!PC->Playing())return;if(IsValid(Target)&&!Target->IsHidden()){FVector Desired=(Target->GetActorLocation()+FVector(0,0,110)-GetActorLocation()).GetSafeNormal()*2200;Velocity=FMath::VInterpTo(Velocity,Desired,Dt,4);}
|
|
FVector Start=GetActorLocation(),End=Start+Velocity*Dt;FHitResult Hit;FCollisionQueryParams Q(SCENE_QUERY_STAT(IronsMissile),true,GetOwner());GetWorld()->LineTraceSingleByChannel(Hit,Start,End,ECC_Visibility,Q);if(Hit.bBlockingHit){Blast(GetWorld(),Hit.ImpactPoint,Damage,Radius);Destroy();}else SetActorLocation(End);}
|