rott/kf_sources/ScrnStoryGame/Classes/KF_BreakerBoxNPC_SE.uc
2026-07-14 20:27:09 +07:00

166 lines
5.1 KiB
Ucode

/*
--------------------------------------------------------------
KF_BreakerBoxNPC_SE
--------------------------------------------------------------
Enhanced version of KF_BreakerBoxNPC:
- TickEvent can be set by map author.
- Doesn't trigger TickEvent when inactive
- can retain visibility while inactive
- can be started active
- Min and max threat rating
- Threat rating for ScrN Balance mod
Author : PooSH
Original Author: Alex Quick
--------------------------------------------------------------
*/
class KF_BreakerBoxNPC_SE extends KF_BreakerBoxNPC;
var(Events) name TickEvent;
var(AI) float MinAIThreatRating, MaxAIThreatRating; // only if parent method return value > 0
// used in AssessThreatTo()
var protected transient KFMonsterController LastThreatMonster;
var protected transient float LastThreatTime, LastThreat;
// restrict healing
function bool GiveHealth(int HealAmount, int HealMax)
{
return false;
}
function bool HealDamage(int Amount, Controller Healer, class<DamageType> DamageType)
{
return false;
}
simulated function PostBeginPlay()
{
Super(KF_StoryNPC_Static).PostbeginPlay();
CheckHealthCondition(self);
}
function GetEvents(out array<name> TriggeredEvents, out array<name> ReceivedEvents)
{
super.GetEvents(TriggeredEvents, ReceivedEvents);
if( TickEvent != '' )
TriggeredEvents[TriggeredEvents.length] = TickEvent;
}
function SetActive(bool On)
{
Super(KF_StoryNPC_Static).SetActive(On);
}
simulated function Tick(float DeltaTime)
{
Super(KF_StoryNPC_Static).Tick(DeltaTime);
if( TickEvent != '' && bActive && !bDestroyed && Level.TimeSeconds - LastTriggerEventTime > 1.0)
{
LastTriggerEventTime = Level.TimeSeconds;
TriggerEvent(TickEvent, self, self);
}
}
/**
Monster threat assessment functionality
Changes by PooSH:
1) KFGameType.bUseZEDThreatAssessment set to true, i.e. in regular game new AssessThreatTo()
function will be used too.
2) Distance between monster and player will always be in place.
3) AssessThreatTo will always return value > 0. Because zeds should not ignore players.
4) Added randomization - zeds can choose different targets in the same circumstances.
5) Blood smell. Wounded players will attract zeds slightly more than their healthy teammates.
* @param Monster Monster's controller, for which we are calculating the threat level
* @param CheckDistance Not used!
* @return threat level between 0 and 100, where 100 is the max threat level.
*
* @author PooSH
*/
function float AssessThreatTo(KFMonsterController Monster, optional bool CheckDistance)
{
local float DistancePart, RandomPart, TacticalPart;
local float DistanceSquared; // squared distance is calculated faster
if ( !Level.Game.IsA('ScrnStoryGameInfo') ) {
LastThreat = super.AssessThreatTo(Monster, CheckDistance);
// don't use MinAIThreatRating for vanilla game, cuz then zeds won't focus on players at all
if ( LastThreat > MaxAIThreatRating )
LastThreat = MaxAIThreatRating;
return LastThreat;
}
// the following code is for ScrnBalance only
if(Monster == none || KFMonster(Monster.Pawn) == none)
{
return -1.f;
}
if(bNoThreatToZEDs ||
TeamIndex == 255 ||
Health <= 0 ||
!bActive ||
!bDamageable ||
(!IsThreateningTo(Monster.Pawn)) )
{
return -1.f;
}
if ( LastThreatMonster == Monster && LastThreatTime == Level.TimeSeconds )
return LastThreat; // threat level for the given monster has been calculated already during the current tick
DistanceSquared = VSizeSquared(Monster.Pawn.Location - Location);
DistancePart = 65.0;
RandomPart = MaxAIThreatRating * 0.35;
// TacticalPart is useless for static NPCs
/*
// let zeds smell blood within 25m radius - wounded players attract zeds more
if ( DistanceSquared < 1562500.0 )
TacticalPart += RandomPart * 0.40 * (HealthMax - Health) / HealthMax;
// more chance to attack the same enemy multiple times
if ( Monster.Enemy == self || Monster.Target == self )
TacticalPart += RandomPart * 0.25;
// more chance to focus on the player, who are attacking the monster
if ( KFMonster(Monster.Pawn).LastDamagedBy == self)
TacticalPart += RandomPart * 0.25;
RandomPart = 100.0 - DistancePart - TacticalPart;
*/
// If target is closer than 1 meter, max DistancePart value will be used,
// otherwise DistancePart is lowering by 10% per meter
// 1 meter = 50 ups (2500 squared)
if ( DistanceSquared > 2500.0 )
DistancePart /= 1.0 + DistanceSquared / 250000.0;
RandomPart *= frand();
// save threat level for this tick
LastThreatMonster = Monster;
LastThreatTime = Level.TimeSeconds;
LastThreat = DistancePart + TacticalPart + RandomPart;
//LastThreat *= InventoryThreatModifier();
LastThreat += BaseAIThreatRating;
LastThreat = fclamp(LastThreat, MinAIThreatRating, MaxAIThreatRating);
return LastThreat;
}
defaultproperties
{
MaxAIThreatRating=40.000000
bWorldGeometry=True
bBlockHitPointTraces=True
}