Well, not for long!
Presenting, UPawn. Well, it's not done yet, but this pre-alpha code compiles. Whenever it does something I'll test it.
In fact, this is a remade version of Pawn, which uses the projectile physics to be able to walk on surfaces in a flexible way, but that's not it! It also supports Fun, and in the future, it'll have many more features!
Code: Select all
//=============================================================================
// UPawn.
//=============================================================================
class UPawn expands Actor;
enum PawnType
{
PT_None,
PT_Native,
PT_New,
PT_Both
};
enum PawnPhysics
{
PP_Walking,
PP_Falling,
PP_Swimming,
PP_Flying
};
enum NavigationClass
{
NC_Breadcrumb,
Nc_Native
};
struct WeaponUse
{
var() float MinRange, MaxRange;
var() float AverageDmg;
var() float SplashRange;
var() float ProjSpeed;
var() float ShootRate;
};
struct AnyPawn
{
var() PawnType ThisType;
var() Pawn Native;
var() UPawn New;
};
// UPhysics.
var(UPhysics) float MaxFloorPitch;
var(UPhysics) Vector MovementBob;
var(UPhysics) float JumpSpeed;
var(UPhysics) float WalkSpeed;
var(UPhysics) AnyPawn Mount;
// Artificial Intelligence of UPawn.
var(AI) float EyeHeight;
var(AI) float Cowardness;
var(AI) float Smartness;
var(AI) float Boredness;
var(AI) float Eagerness; // how fast the fun of playing only a single Toy is lost
var(AI) class<Weapon> FavoriteGun;
var(AI) WeaponUse GunStats;
var(AI) Pawn Enemies[32];
var(AI) Pawn PriorityEnemy;
var(AI) NavigationClass NavType;
var Actor Toy;
var float ToyStrenght;
var int PlayTimes;
// Inventory stuff.
var(PawnInv) Inventory StartingInv[64];
var(PawnInv) Weapon CurrentWeapon;
var(Anim) float IdleSpeed;
var(Anim) float BoredModifier; // multiplies idle anim speed when bored
var Rotator FloorNormal;
var Vector WalkOffset;
var Vector OldVel;
var Actor NvCurrent;
var Actor NvNext;
var int PathSize;
var Inventory Inv;
var float CurrentSpeed;
var name InterruptingWalk;
var name OldState;
var bool bMoving;
simulated function PreBeginPlay()
{
local Vector v, n;
v = Location;
v.Z -= 16384;
Trace(v, n, v);
FloorNormal = Rotator(n);
}
simulated function bool ActorCloser(Actor Other, Actor aFrom)
{
return aFrom == None || VSize(Other.Location - Location) < VSize(aFrom.Location - Location);
}
simulated function WalkToward(Actor Target, float Speed, bool bStrafe)
{
WalkNormal(Rotator(Target.Location - Location).Yaw, VSize(Location - Target.Location), Speed, bStrafe);
}
simulated function WalkTo(Vector Target, float Speed, bool bStrafe)
{
WalkNormal(Rotator(Target - Location).Yaw, VSize(Location - Target), Speed, bStrafe);
}
simulated function WalkNormal(float Angle, float Distance, float Speed, bool bStrafe)
{
local Rotator Dir;
Dir = FloorNormal;
Dir.Yaw = Angle;
if ( !bStrafe )
SetRotation(Dir);
WalkOffset += Vector(Dir) * Distance;
CurrentSpeed = WalkSpeed * Speed;
OldState = GetStateName();
GoToState('Walking');
}
simulated function Actor NextTo(Actor Target)
{
local Breadcrumb Closest, B;
local NavigationHelper H;
if ( Breadcrumb(NvCurrent) != None )
{
foreach AllActors(class'Breadcrumb', B)
if ( ActorCloser(B, Closest) )
Closest = B;
NvNext = Breadcrumb(NvCurrent).FindPathToBreadcrumb(Closest).Next;
}
else if ( NavigationPoint(NvCurrent) != None )
{
H = Spawn(class'NavigationHelper', self);
H.LoadPathToward(Target);
NvNext = H.Helped(true);
}
return NvNext;
}
simulated function bool Walkable(vector Normal)
{
return Rotator(Normal).Pitch / 65535 < MaxFloorPitch;
}
simulated function StopWalking(name NewState)
{
if ( IsInState('Walking') )
InterruptingWalk = NewState;
}
simulated function Tick(float TimeDelta)
{
if ( bMoving )
{
Velocity = OldVel;
bMoving = false;
}
}
simulated function GotFun(Actor Source, float Strenght)
{
Boredness -= Strenght;
if ( Source == Toy )
{
ToyStrenght -= PlayTimes * Eagerness - Strenght;
PlayTimes++;
return;
}
if ( Strenght > ToyStrenght )
{
Toy = Source;
ToyStrenght = Strenght;
PlayTimes = 0;
}
}
simulated function TickMove(Vector NewLocation)
{
Velocity = NewLocation - Location;
OldVel = Velocity;
bMoving = true;
}
simulated function HitWall(vector HitNormal, Actor Wall)
{
Landed(HitNormal);
}
simulated function Landed(vector Normal)
{
if ( !Walkable(Normal) )
return;
FloorNormal = Rotator(Normal);
}
auto state Idle
{
function Timer()
{
Boredness += 1;
}
Begin:
SetTimer(0.5, true);
if ( Boredness > 16 )
GoToState('Bored');
LoopAnim('Idle', IdleSpeed);
}
function Roam()
{
local Vector v, Norm, f;
v = Location + VRand() * 60;
while ( !FastTrace(v) )
v = Location + VRand() * 60;
f = v;
f.Z -= CollisionHeight * 1.6;
Trace(v, Norm, f, v);
WalkTo(v, 0.9, false);
}
state Bored
{
function Timer()
{
Boredness += 1;
if ( FRand() < Eagerness )
Roam();
}
Begin:
LoopAnim('Idle', IdleSpeed + BoredModifier);
if ( Boredness > 36 )
Roam();
}
state Walking
{
function EndWalk()
{
GoToState(OldState);
}
function Tick(float TimeDelta)
{
while ( VSize(WalkOffset) > (CurrentSpeed * 2.0) )
{
if ( InterruptingWalk != 'None' )
{
EndWalk();
GoToState(InterruptingWalk);
}
else
{
TickMove(Location + Normal(WalkOffset) * CurrentSpeed);
WalkOffset -= Normal(WalkOffset);
}
}
EndWalk();
}
}
