class Troll extends Pawn;
#exec TEXTURE IMPORT NAME=Face0 FILE=Textures\Face0.bmp GROUP=Skins FLAGS=2
#exec TEXTURE IMPORT NAME=Face1 FILE=Textures\Face1.bmp GROUP=Skins FLAGS=2
#exec TEXTURE IMPORT NAME=Face2 FILE=Textures\Face2.bmp GROUP=Skins FLAGS=2
var() Texture WanderingFace;
var() Texture AttackFace;
var() Texture PainFace;
var() float MaxWallTime;
var() float WanderRadius;
var() float TrollRadius;
var() float AttackRadius;
var() bool bRedeemerResistant;
var() int Step;
var vector SpawnLoc;
var Pawn Enemy;
var Pawn NearestPawn;
var bool bCanHurt;
function PreSetMovement()
{
bCanJump = false;
bCanWalk = false;
bCanSwim = false;
bCanFly = true;
MinHitWall = -0.6;
bCanOpenDoors = false;
bCanDoSpecial = false;
}
function SetMovementPhysics()
{
SetPhysics(PHYS_Flying);
}
function Spawned()
{
SpawnLoc = Location;
PreSetMovement();
SetMovementPhysics();
Log(self$" spawned");
}
function ChooseDest()
{
local float homeDist;
local vector direction;
homeDist = VSize(SpawnLoc - Location);
if ( Enemy == None && ( NearestPawn == None || homeDist > WanderRadius || (homeDist > WanderRadius / 2 && FRand() > 0.8) ) )
{
Destination = SpawnLoc;
return;
}
direction = normal((NearestPawn.Location + VRand() * 700) - Location);
Destination = Location + direction * Step;
}
function FindNearestPawn()
{
local Pawn P, M;
local float mdist, dist;
mdist = 99999;
for (P = Level.PawnList; P != None; P = P.NextPawn)
{
if (P.IsA('PlayerPawn') || P.IsA('ScriptedPawn') || P.IsA('Bot') || P.IsA('Bots')) // remove this line for more madness
{
dist = VSize(Location - P.Location);
if (dist < mdist)
{
mdist = dist;
M = P;
}
}
}
NearestPawn = M;
}
auto state Wandering
{
function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation,
Vector momentum, name damageType)
{
if (Damage < 60 || (bRedeemerResistant && damageType == 'RedeemerDeath'))
return;
Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType);
if (Health <= 0)
GoToState('Dying');
Texture = PainFace;
SetTimer(0.5, false);
}
function Timer()
{
Texture = WanderingFace;
}
function Tick(float deltaTime)
{
FindNearestPawn();
if (NearestPawn != None && VSize(Location - NearestPawn.Location) <= TrollRadius)
GoToState('Trolling');
}
Begin:
//Log("Wandering");
Texture = WanderingFace;
Enemy = None;
Move:
ChooseDest();
TurnTo(Destination);
MoveTo(Destination, airspeed);
Goto('Move');
}
state Trolling
{
function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation,
Vector momentum, name damageType)
{
if (Damage < 60 || (bRedeemerResistant && damageType == 'RedeemerDeath'))
return;
Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType);
if (Health <= 0)
GoToState('Dying');
}
function Tick(float deltaTime)
{
local float dist;
dist = VSize(Location - Enemy.Location);
if (Enemy == None || dist > TrollRadius)
GoToState('Wandering');
if (dist <= AttackRadius && bCanHurt)
Hurt();
}
function Hurt()
{
HurtRadius(50 + 20 * frand(), AttackRadius, 'butthurt', 200000, Location);
SetTimer(frand(), false);
bCanHurt = false;
}
function Timer()
{
bCanHurt = true;
}
Begin:
bCanHurt = true;
if (NearestPawn != None)
Enemy = NearestPawn;
else
GoToState('Wandering');
//Log(self$" hates "$Enemy);
Texture = AttackFace;
Move:
if (Enemy != None)
{
TurnToward(Enemy);
MoveToward(Enemy, airspeed * 1.5);
}
else
GoToState('Wandering');
Goto('Move');
}
state Dying
{
Begin:
Acceleration = vect(0,0,0);
SetPhysics(PHYS_None);
Texture = AttackFace;
DrawScale *= 2;
Sleep(0.2);
spawn(class'ShockWave');
Sleep(1);
spawn(class'WarExplosion');
Destroy();
}
defaultproperties
{
WanderingFace=Texture'Troll.Skins.Face0'
AttackFace=Texture'Troll.Skins.Face1'
PainFace=Texture'Troll.Skins.Face2'
DrawType=DT_Sprite
Style=STY_Masked
DrawScale=0.400000
CollisionRadius=50.000000
CollisionHeight=50.000000
Texture=Texture'Troll.Skins.Face0'
Health=1000
Step=300
AirSpeed=300.000000
AccelRate=1000.000000
bCollideWorld=false
WanderRadius=10000.000000
TrollRadius=1000.000000
AttackRadius=200.000000
bRedeemerResistant=true
}