Here Is a kind of selfie, I did a few small things for me when I did not loved A.I. in certain moments or when player can be hinted with direct images from level. Maybe you have seen such cams but... not very helped when 8 players were playing around.
Showing me the threat, objective or whatever - triggered, dispatched, etc.
Code: Select all
class CamView expands Triggers;
var Keypoint MyCam;
var() name CamTag;
var() float ViewTime;
event postbeginplay()
{
local Keypoint K;
if (CamTag == '')
{
log(Self$" report unconfigured SpectatorCam... Cya !");
Destroy();
return;
}
if (ViewTime <= 0.5)
ViewTime = 0.5;
foreach AllActors (class 'Keypoint',K,CamTag )
{
if (K != None && K.IsA('SpectatorCam'))
{
MyCam = K;
break;
}
}
}
singular event timer()
{
local PlayerPawn Player;
local Pawn P;
for ( P=Level.PawnList; P!=None; P=P.nextPawn )
{
Player = Playerpawn(P);
if ( Player != None )
{
Player.bFixedCamera = False;
Player.ViewTarget = None;
Player.bBehindView = false;
}
}
Enable('Trigger');
}
event Trigger( Actor Other, Pawn EventInstigator )
{
local PlayerPawn Player;
local Pawn P;
for ( P=Level.PawnList; P!=None; P=P.nextPawn )
{
Player = Playerpawn(P);
if ( Player != None )
{
Player.ViewTarget = MyCam;
Player.bBehindView = false;
Player.bFixedCamera = True;
}
}
SetTimer(ViewTime,False);
Disable('Trigger');
}
defaultproperties
{
bHidden=True
}
Hint: Camera can be movable attached properly to an AttachMover.
A.I. stuff. A Bidirectional BlockedPath - blocking or unblocking path by triggering
Code: Select all
class PathSwitcher extends BlockedPath;
var() bool bInitialEnabled;
event PostBeginPlay()
{
if (bInitialEnabled)
Extracost = 100000000;
else
Extracost = 0;
}
function Trigger( actor Other, pawn EventInstigator )
{
if ( ExtraCost > 0 )
ExtraCost = 0;
else
ExtraCost = 100000000;
}
defaultproperties
{
bInitialEnabled=True
}
Hint: You can implement lightning - Green = Free = Extracost = 0, Red = Blocked = Busy = Extracost 100000000.
Lost Bot - recover Navigation Networks after a previous nasty boost in wild area
Code: Select all
class NoLost extends Actor;
var() float Interval;
var() int RangeRun;
event PostBeginPlay()
{
if ( Interval > 2.00 )
SetTimer(Interval,True);
else log (Self$" don't mock with settings, loser!");
}
singular event timer()
{
local Bot aBotyMan;
local NavigationPoint N, N1;
local int BestPointDist;
BestPointDist = RangeRun;
foreach AllActors (class 'Bot', aBotyMan)
{
if ( aBotyMan != None && aBotyMan.Health > 0 )
{
if ( aBotyMan.Enemy == None && !NearbyNode(aBotyMan) )
{
if ( aBotyMan.MoveTarget == None )
foreach aBotyMan.RadiusActors ( class 'NavigationPoint', N, RangeRun )
{
if ( N != None )
{
if (VSize(N.Location-aBotyMan.Location) <= BestPointDist && FastTrace(N.Location,aBotyMan.Location))
{
N1 = N;
BestPointDist = Vsize(N.Location - aBotyMan.Location);
}
}
}
if ( N1 != None && aBotyMan.CanSee(N1))
{
aBotyMan.Target = N1;
aBotyMan.RoamTarget = N1;
aBotyMan.MoveTarget = N1;
aBotyMan.bCamping = False;
aBotyMan.TweenToRunning(0.1);
aBotyMan.GotoState('Roaming','SpecialNavig');
}
}
}
}
}
function bool NearbyNode(Bot aBotyMan)
{
local bool bIsNearby;
local Pathnode P;
bIsNearby = False;
foreach aBotyMan.RadiusActors( class 'Pathnode', P , 710 )
{
if ( P != None && FastTrace(P.Location,aBotyMan.Location) )
{
bIsNearby = True;
break;
}
}
return bIsNearby;
}
defaultproperties
{
Interval=3.800000
RangeRun=2000
}
Hint: Normally should not be a problem in Water as long as default Bot turns into Swimming from running automatically, else except WaterZones - also you can fix Bot stuck in water due to physics bugs putting it into swim mode and pointing it to a Visible node.
"Moron" is not jumping near a ledge and run in place constantly. Simon says: Jump!
Code: Select all
class Bot_Jumper expands Triggers;
var() bool bOnceOnly, bEnabled;
var() class<Bot> LimitedToClass;
var Bot Pending;
var() float Frequency;
var() int JumpZ;
event Timer()
{
Pending.SetPhysics(PHYS_Falling);
Pending.Velocity = Pending.GroundSpeed * Vector(Rotation);
if ( JumpZ != 0 )
Pending.Velocity.Z = JumpZ;
else
Pending.Velocity.Z = FMax(200, Pending.JumpZ);
Pending.DesiredRotation = Rotation;
Pending.Acceleration = Vector(Rotation) * Pending.AccelRate;
Pending.bJumpOffPawn = true;
Pending.SetFall();
}
function Touch( actor Other )
{
if ( bEnabled )
if ( Other.IsA('Bot')
&& ((LimitedToClass == None) || (Other.Class == LimitedToClass)) )
{
Pending = Bot(Other);
SetTimer(Frequency, false);
if ( bOnceOnly )
{
Disable('Touch');
Disable('Trigger');
}
}
}
function Trigger( actor Other, pawn EventInstigator )
{
if ( bEnabled )
{
bEnabled = False;
Disable('Touch');
}
else
{
bEnabled = True;
Enable('Touch');
}
}
defaultproperties
{
bOnceOnly=False
bDirectional=True
JumpZ=324
Frequency=0.1
}
Hint: Make it jump from a ramp when it needs to walk around for an enemy and turn it off when enemy died.
Simulated Fear
Code: Select all
class Bot_Runner expands Triggers;
var() bool bOnceOnly, bEnabled;
var() class<Bot> LimitedToClass;
var Bot Pending;
var() float Frequency;
var NavigationPoint MyPoint;
var() name PointTag;
event PostBeginPlay()
{
FindMyPoint();
}
function FindMyPoint()
{
local NavigationPoint N;
if ( PointTag != '' )
foreach RadiusActors(class'NavigationPoint',N,3000)
{
if ( N != None && N.Tag == PointTag )
{
MyPoint = N;
break;
log ("Point Set "$N);
}
}
}
singular event Timer()
{
if ( MyPoint!=None && bEnabled && Pending.health > 0 )
{
Pending.Velocity = Pending.GroundSpeed * Vector(Rotation);
if ( Level.Game.IsA('TeamGamePlus') )
TeamGamePlus(Level.Game).FindSpecialAttractionFor(Pending)==False;
Pending.MoveTarget = MyPoint;
Pending.MoveTimer = 1.00;
Pending.GotoState('Roaming', 'SpecialNavig');
}
}
function Touch( actor Other )
{
if ( bEnabled ) //for first usage active
if ( Other.IsA('Bot') && ((LimitedToClass == None) || (Other.Class == LimitedToClass)) )
{
Pending = Bot(Other);
SetTimer(Frequency, false);
if ( bOnceOnly )
{
Disable('Touch');
Disable('Trigger');
}
}
}
function Trigger( actor Other, pawn EventInstigator )
{
if ( bEnabled )
{
Disable('Touch');
bEnabled = False;
}
else
{
bEnabled = True;
Enable('Touch');
}
}
defaultproperties
{
bEnabled=True
bOnceOnly=False
bDirectional=True
Frequency=0.1
}
Hint: Combined with a crappy sound might return the feeling of a Bot scared running away.
Shoot that...
Code: Select all
class Bot_Hunter expands Triggers;
var() bool bOnceOnly, bEnabled;
var() class<Bot> LimitedToClass;
var Bot Pending;
var() float Frequency;
var Actor MyPoint;
var() name PointTag;
event PostBeginPlay()
{
FindMyPoint();
}
function FindMyPoint()
{
local Actor A;
if ( PointTag != '' )
foreach RadiusActors(class'Actor',A,700)
{
if ( A != None && A.Tag == PointTag )
{
MyPoint = A;
break;
log ("Point Set "$A);
}
}
}
event Timer()
{
if ( MyPoint != None && bEnabled && Pending.health > 0 )
{
if ( Level.Game.IsA('TeamGamePlus') )
TeamGamePlus(Level.Game).FindSpecialAttractionFor(Pending)==False;
if ( MyPoint.bIsPawn )
{
Pending.DesiredRotation = Rotation;
Pending.Velocity=Vect(0,0,0);
Pending.Target=MyPoint;
Pending.Enemy=Pawn(MyPoint);
Pending.GotoState('RangedAttack');
}
else
{
Pending.DesiredRotation = Rotation;
Pending.Velocity=Vect(0,0,0);
Pending.Target=MyPoint;
Pending.RoamTarget=MyPoint;
Pending GotoState('Roaming','ShootDecoration');
/*
Pending.bShootSpecial=True;
Pending.FireWeapon();
Pending.bFire = 0;
Pending.bAltFire = 0;
*/
}
}
}
function Touch( actor Other )
{
if ( bEnabled )
if ( Other.IsA('Bot') && ((LimitedToClass == None) || (Other.Class == LimitedToClass)) )
{
Pending = Bot(Other);
SetTimer(Frequency, false);
if ( bOnceOnly )
{
Disable('Touch');
Disable('Trigger');
}
}
}
function Trigger( actor Other, pawn EventInstigator )
{
if ( bEnabled )
{
Disable('Touch');
bEnabled = False;
}
else
{
bEnabled = True;
Enable('Touch');
}
}
defaultproperties
{
bEnabled=True
bOnceOnly=True
bDirectional=True
Frequency=0.1
}
Bot touching this thing will attack that if is pawn or will shot it if is other thing (there are 2 options in here).
Hint: Fire a decoration to spawn a better weapon, else kill a pawn FortStandard like.
Wait...
Code: Select all
class Bot_Pauser expands Triggers;
var() bool bOnceOnly, bEnabled;
var() class<Bot> LimitedToClass;
var Bot Pending;
var() float Frequency;
event Timer()
{
Pending.SetPhysics(PHYS_Falling);
Pending.MoveTarget = None;
Pending.MoveTimer = -1.00;
Pending.Acceleration = vect(0,0,0);
Pending.Velocity = vect(0,0,0);
Pending.SpecialPause = 1.00;
}
function Touch( actor Other )
{
if ( bEnabled )
if ( Other.IsA('Bot')
&& ((LimitedToClass == None) || (Other.Class == LimitedToClass)) )
{
Pending = Bot(Other);
SetTimer(Frequency, false);
if ( bOnceOnly )
{
Disable('Touch');
Disable('Trigger');
}
}
}
function Trigger( actor Other, pawn EventInstigator )
{
if ( bEnabled )
{
bEnabled = False;
Disable('Touch');
}
else
{
bEnabled = True;
Enable('Touch');
}
}
defaultproperties
{
bOnceOnly=False
Frequency=0.1
}
Hint: If a previous Jumper makes it too jumpy just block it when it needs to avoid falling.
We can debate more as needed.
Edit:
It is not really ONP based on touchers (only 4 touchers holds UT), I was writing that code without Cut, without adds in HUD to spread errors, is based on Camera used into Assault and you can toy with ShowTime dispatching mission (specific to MH) Here is a redone of an initially Unsigned map, No Bot Support, no many playerstarts, nothing too interesting. I have set a few tiny custom things. If you try it with 3 Bots probably will run as supposed, it might work with many - is about FearSpot at begining. If touchers are filled up then the rest of team will be ignored - is more an experiment but is playable in living-room.FraGnBraG wrote: The camera "selfie" code - is this what they did in ONP?
Content: Runner, Monster Teamer, Jumper, Camera, Bot Pathing, stuff added to balance difficulty, is a kind of work at home not very intended for highly loaded servers but you might have ideas from this one.
HuntNode:
How works ? It simply lock path if Bot encounter an enemy in purpose to not race like an idiot and to mind the enemy more properly. If doesn't have enemy will continue to move - recommended for MH v5.03 in order "Freelance", in the rest of fixed MH-s will work normally.
Code: Select all
class HuntNode expands PathNode;
var Bot PendingBot;
event int SpecialCost(Pawn Seeker)
{
local Bot B;
B = Bot(Seeker);
if ( !Seeker.bIsPlayer ) //Monster Not allowed
return 100000000;
if ( B == None ) //Human support
return 0;
if ( B != None )
{
if ( B.Enemy == None )
return 0; //No enemy = Move
else
return 100000000; //else see whatever habits
}
return 100000000;
}
Previous Enhanced PathNode can be in MyLevel without to be abused. It is recommended around lasts Nodes to Waypoint blocking entire road if enemy is on sight. Else 12 Waypoints = 12 Nodes. It must be bSpecialCost = True (using Editor's Console). Mention no. 2 - I set default properties 46 height and 22 radius - smaller than common PathNode and it's able to link smaller places than usual PathNode (which might address Monsters too) and a thin Bot can use such paths correctly. I've been toying with such stuff and looks like works like a charm.