Prepare fixtures

This commit is contained in:
dkanus 2026-07-14 20:27:09 +07:00
commit 9c94356263
6021 changed files with 722805 additions and 22 deletions

View file

@ -0,0 +1,26 @@
class ACTION_BlowUpPipebombs extends ScriptedAction;
var (Action) bool bInstantExplode; // instantly explode or wait for count down?
function bool InitActionFor(ScriptedController C)
{
local PipeBombProjectile P;
foreach C.DynamicActors(Class'PipeBombProjectile',P)
{
if( !P.bHidden )
{
P.bEnemyDetected = true; // blow me up
if ( bInstantExplode ) {
P.CountDown = 0;
}
}
}
return false;
}
defaultproperties
{
ActionString="Blow up pipebombs"
}

View file

@ -0,0 +1,151 @@
class AnimatedDecoration extends Decoration;
#exec OBJ LOAD FILE=Foundry_anim.ukx
var() bool bActive;
var bool bLoop;
var() float ActivationDelay;
var() bool bRandomActivationDelay;
var bool bPendingState; // bActive value, which will be set on timer
var() const name Animation;
var() const bool bHiddenWhenInactive;
var(Sound) const bool bAmbientSoundOnlyWhenActive;
replication
{
reliable if( bNetInitial && Role == Role_Authority )
Animation, bHiddenWhenInactive, bAmbientSoundOnlyWhenActive;
reliable if( (bNetInitial || bNetDirty) && Role == Role_Authority )
bActive, bLoop;
}
function PostBeginPlay()
{
if ( bActive ) {
bActive = false;
DelayedActivation(true);
}
else
SetActive(false);
}
function DelayedActivation(bool bActivate)
{
bPendingState = bActivate;
if ( ActivationDelay > 0 ) {
if ( bRandomActivationDelay )
SetTimer(fmax(ActivationDelay*frand(), 0.01), false);
else
SetTimer(ActivationDelay*frand(), false);
}
else
SetActive(bActivate);
}
simulated function Timer()
{
SetActive(bPendingState);
}
simulated function PostNetReceive()
{
SetActive(bActive);
}
simulated function SetActive(bool value)
{
if ( bActive != value ) {
bActive = value;
if ( Role == ROLE_Authority )
NetUpdateTime = Level.TimeSeconds - 1;
}
if ( Level.NetMode != NM_DedicatedServer ) {
if ( bActive ) {
if ( bLoop )
LoopAnim(Animation);
else {
PlayAnim(Animation);
// set inactive when animation ends
bPendingState = false;
SetTimer(GetAnimDuration(Animation), false);
}
if ( bAmbientSoundOnlyWhenActive )
AmbientSound = default.AmbientSound;
}
else {
StopAnimating();
if ( bAmbientSoundOnlyWhenActive )
AmbientSound = none;
}
if ( bHiddenWhenInactive )
bHidden = !bActive;
}
}
state() TriggerTurnsOn
{
function BeginState()
{
bLoop = true;
}
function Trigger( actor Other, pawn EventInstigator )
{
Instigator = EventInstigator;
DelayedActivation(true);
}
}
state() TriggerPlayOnce extends TriggerTurnsOn
{
function BeginState()
{
bLoop = false;
}
}
state() TriggerTurnsOff
{
function Trigger( actor Other, pawn EventInstigator )
{
Instigator = EventInstigator;
SetActive(false);
}
}
state() TriggerToggle
{
function BeginState()
{
bLoop = true;
}
function Trigger( actor Other, pawn EventInstigator )
{
Instigator = EventInstigator;
if ( bActive )
SetActive(false);
else
DelayedActivation(true);
}
}
defaultproperties
{
bLoop=True
bStatic=False
bStasis=False
bAlwaysRelevant=True
RemoteRole=ROLE_SimulatedProxy
Mesh=SkeletalMesh'Foundry_anim.Steamengine_Wheel'
bNetNotify=True
}

View file

@ -0,0 +1,196 @@
class FoundryWife extends KF_StoryNPC_Spawnable_SE;
#exec OBJ LOAD FILE=KF_Solider9_Trip_T.utx
#exec OBJ LOAD FILE=KF_FemaleVoiceOne.uax
var Actor OriginalScriptedFocus;
var transient float TimeTillNextAttack;
var() localized string strFocusOnUser;
simulated function PostBeginPlay()
{
super.PostBeginPlay();
ShieldStrength=200; // ShieldStrength is transient, so can't be set in defaultproperties
}
simulated function Tick(float DeltaTime)
{
Super.Tick(DeltaTime);
if ( TimeTillNextAttack > 0 ) {
TimeTillNextAttack -= DeltaTime;
if ( TimeTillNextAttack <= 0 )
AttackEnemy();
}
}
function TakeDamage(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, class<DamageType> damageType, optional int HitIdx )
{
//local class<KFWeaponDamageType> KFDamType;
local ScriptedController SC;
super.TakeDamage( Damage, instigatedBy, hitlocation, momentum, damageType, HitIdx );
if ( Health <= 0 )
return;
SC = ScriptedController(Controller);
if ( Monster(instigatedBy) != none && SC != none && ( SC.Enemy == none || frand() < 0.5) ) {
// shoot that bitch
SC.Enemy = instigatedBy;
AttackEnemy();
}
// else if ( KFHumanPawn(instigatedBy) != none && PlayerController(instigatedBy.Controller) != none
// && instigatedBy.Controller.bIsPlayer )
// {
// KFDamType = KFWeaponDamageType(damageType);
// if ( KFDamType != none ) {
// Follow the player who slapped my the butt
// if ( KFDamType.default.bCheckForHeadShots )
// SC.MyPlayerController = PlayerController(instigatedBy.Controller);
// }
// }
}
function RestoreScriptedFocus()
{
local ScriptedController SC;
SC = ScriptedController(Controller);
if ( SC != none && OriginalScriptedFocus != none ) {
SC.ScriptedFocus = OriginalScriptedFocus;
OriginalScriptedFocus = none;
}
}
// this is lame, but it is better than nothing
// todo: make a scripted controller, which can act like a bot and return to the script
function AttackEnemy()
{
local ScriptedController SC;
SC = ScriptedController(Controller);
if ( SC == none )
return;
if ( SC.Enemy == none || SC.Enemy.Controller == none
|| SC.Enemy.bDeleteMe || SC.Enemy.Health <= 0
|| (!SC.CanSee(SC.Enemy) && !SC.Enemy.Controller.CanSee(self)) )
{
if ( SC.ScriptedFocus == SC.Enemy )
RestoreScriptedFocus();
SC.Enemy = none;
SC.NumShots = -1;
return;
}
if ( SC.NumShots > 0 )
return; // already shooting
if ( Weapon == none || !Weapon.CanAttack(SC.Enemy) ) {
SC.SwitchToBestWeapon();
}
// 20% chance to use other weapon
// while ( Weapon != none && frand() < 0.1 )
// Weapon = Weapon.NextWeapon(Weapon, Weapon);
if ( Weapon == none || !Weapon.CanAttack(SC.Enemy) ) {
// screw that enemy - let players to deal with it
if ( SC.ScriptedFocus == SC.Enemy )
RestoreScriptedFocus();
SC.Enemy = none;
SC.NumShots = -1;
return;
}
//bIgnorePlayFiring = false;
if ( SC.ScriptedFocus != SC.Enemy ) {
if ( OriginalScriptedFocus == none ) {
OriginalScriptedFocus = SC.ScriptedFocus;
}
SC.ScriptedFocus = SC.Enemy;
}
SC.bShootTarget = true;
SC.NumShots = 1;
// if ( SC.NumShots <= 1 ) {
// if ( KFMeleeGun(Weapon) != none ) {
// SC.NumShots = RandRange(1, 3);
// SC.bShootSpray = false;
// }
// else {
// SC.NumShots = RandRange(1, 10);
// SC.bShootSpray = true;
// }
// }
SC.WeaponFireAgain(0,false);
TimeTillNextAttack = Weapon.RefireRate();
}
function UsedBy( Pawn user )
{
local ScriptedController SC;
if ( !bActive )
return;
super.UsedBy(user);
SC = ScriptedController(Controller);
if ( SC != none && SC.MyPlayerController != none && SC.MyPlayerController != user.Controller
&& KFHumanPawn(user) != none && PlayerController(user.Controller) != none )
{
SC.MyPlayerController = PlayerController(user.Controller);
if ( strFocusOnUser != "" )
user.ClientMessage( strFocusOnUser, 'CriticalEvent' );
}
}
defaultproperties
{
strFocusOnUser="Now I will follow you, my darling!"
bBleed=True
MinBleedDamage=5.000000
MaxBleedDamage=20.000000
bActivateOnHealing=True
bActivateOnHealingOnlyOnce=True
HealthPctToActivate=0.800000
DeathEvent="FoundryWifeDied"
UseEvent="FoundryWifeUsed"
bHealthBarOnlyIfVisible=True
bUseCoverAnim=False
TouchMessage="Press <USE> to interact"
TouchMessageType="CriticalEvent"
bTouchable=True
bUsable=True
BleedingSounds(0)=SoundGroup'KF_FemaleVoiceOne.Automatic_Commands.Auto_Dying'
BleedingSounds(1)=SoundGroup'KF_FemaleVoiceOne.Automatic_Commands.Auto_Dying'
BleedingSounds(2)=SoundGroup'KF_FemaleVoiceOne.SUPPORT.MEDIC'
BleedingSounds(3)=SoundGroup'KF_FemaleVoiceOne.SUPPORT.MEDIC'
BleedingSounds(4)=SoundGroup'KF_FemaleVoiceOne.SUPPORT.MEDIC'
MinTimeBetweenBleedSounds=12.000000
BleedOutInterval=5.000000
NPCName="Jessica Aldridge"
BaseAIThreatRating=0.000000
bInitialFireAtWill=True
bShowHealthBar=False
NPCHealth=500.000000
StartingHealthPct=0.750000
ActivationEvent="FoundryWifeHealed"
MaxCarryWeight=25.000000
ShieldStrengthMax=200.000000
bNoDefaultInventory=False
AIScriptTag="FoundryWifeAI"
GroundSpeed=120.000000
HealthMax=500.000000
Health=375
Mesh=SkeletalMesh'KF_Soldier_Trip.Female_Soldier'
Skins(0)=FinalBlend'KF_Solider9_Trip_T.Female_Soldier.FinalBlend_Female_Hair_fb'
Skins(1)=Combiner'KF_Solider9_Trip_T.Female_Soldier.Female_Soldier_CMB'
}

View file

@ -0,0 +1,26 @@
class FoundryWorker extends KF_StoryNPC_Spawnable_SE;
simulated function PostBeginPlay()
{
super.PostBeginPlay();
ShieldStrength=200; // ShieldStrength is transient, so can't be set in defaultproperties
}
defaultproperties
{
ZombieDamageReduction=0.500000
NPCName="William Aldridge"
bStartActive=True
BaseAIThreatRating=0.000000
bShowHealthBar=False
NPCHealth=200.000000
StartingHealthPct=1.000000
HealedEvent=
TorchBatteryLife=5000000
ShieldStrengthMax=200.000000
AIScriptTag="FoundryWorkerAI"
GroundSpeed=120.000000
Mesh=SkeletalMesh'KF_Soldier_Trip.foundry1_soldier'
Skins(0)=Combiner'KF_Soldier2_Trip_T.Uniforms.Foundry1_Soldier_cmb'
}

View file

@ -0,0 +1,287 @@
class PipeBombPlaceable extends PipeBombProjectile
placeable;
var(PipeBombProjectile) int TeamIndex; // team which "placed" pipebomb. Use to avoid unnecessary friendly fire
var(PipeBombProjectile) int EnemyCountdown; // Countdown to explosion after enemy detected
var(PipeBombProjectile) bool bTriggerOnEnemy; // team which "placed" pipebomb. Use to avoid unnecessary friendly fire
var(PipeBombProjectile) bool bImmuneToDamage; // team which "placed" pipebomb. Use to avoid unnecessary friendly fire
var(PipeBombProjectile) float MyDamage;
var(PipeBombProjectile) float MyDamageRadius;
var(PipeBombProjectile) float MyMomentumTransfer;
static function PreloadAssets()
{
}
static function bool UnloadAssets()
{
return true;
}
simulated function PostBeginPlay()
{
if ( Level.NetMode != NM_DedicatedServer)
{
BombLight = Spawn(class'PipebombLight',self);
BombLight.SetBase(self);
}
// removed initial velocity
Countdown = EnemyCountdown;
Damage = MyDamage;
DamageRadius = MyDamageRadius;
MomentumTransfer = MyMomentumTransfer;
PlacedTeam = TeamIndex;
SetTimer(1.0, True); // this projectile is supposed to be placed in a map, so arm it immediately
}
function Timer()
{
local Pawn CheckPawn;
local float ThreatLevel;
if( !bHidden && !bTriggered )
{
if( ArmingCountDown >= 0 )
{
ArmingCountDown -= 0.1;
if( ArmingCountDown <= 0 )
{
SetTimer(1.0,True);
}
}
else
{
// Check for enemies
if( !bEnemyDetected )
{
bAlwaysRelevant=false;
PlaySound(BeepSound,,0.5,,50.0);
if ( bTriggerOnEnemy ) {
foreach VisibleCollidingActors( class 'Pawn', CheckPawn, DetectionRadius, Location )
{
if( CheckPawn == Instigator || KFGameType(Level.Game).FriendlyFireScale > 0 &&
CheckPawn.PlayerReplicationInfo != none &&
CheckPawn.PlayerReplicationInfo.Team.TeamIndex == PlacedTeam )
{
// Make the thing beep if someone on our team is within the detection radius
// This gives them a chance to get out of the way
ThreatLevel += 0.001;
}
else
{
if( (CheckPawn != Instigator) && (CheckPawn.Role == ROLE_Authority) &&
((CheckPawn.PlayerReplicationInfo != none && CheckPawn.PlayerReplicationInfo.Team.TeamIndex != PlacedTeam) ||
CheckPawn.GetTeamNum() != PlacedTeam))
{
if( KFMonster(CheckPawn) != none )
{
ThreatLevel += KFMonster(CheckPawn).MotionDetectorThreat;
if( ThreatLevel >= ThreatThreshhold )
{
bEnemyDetected=true;
SetTimer(0.15,True);
}
}
else
{
bEnemyDetected=true;
SetTimer(0.15,True);
}
}
}
}
if( ThreatLevel >= ThreatThreshhold )
{
bEnemyDetected=true;
SetTimer(0.15,True);
}
else if( ThreatLevel > 0 )
{
SetTimer(0.5,True);
}
else
{
SetTimer(1.0,True);
}
}
else {
SetTimer(1.0,True);
}
}
// Play some fast beeps and blow up
else
{
bAlwaysRelevant=true;
Countdown--;
if( CountDown > 0 )
{
PlaySound(BeepSound,SLOT_Misc,2.0,,150.0);
}
else
{
Explode(Location, vector(Rotation));
}
}
}
}
else
{
Destroy();
}
}
simulated function Explode(vector HitLocation, vector HitNormal)
{
super.Explode(HitLocation, HitNormal);
TriggerEvent(Event, self, Instigator);
}
function Trigger( actor Other, pawn EventInstigator )
{
if ( !bHidden && !bTriggered ) {
Instigator = EventInstigator;
Explode(Location, vector(Rotation));
}
}
function TakeDamage( int Damage, Pawn InstigatedBy, Vector Hitlocation, Vector Momentum, class<DamageType> damageType, optional int HitIndex)
{
if ( bImmuneToDamage )
return;
Instigator = InstigatedBy;
super.TakeDamage(Damage, InstigatedBy, Hitlocation, Momentum, damageType, HitIndex);
}
simulated function HurtRadius( float DamageAmount, float DamageRadius, class<DamageType> DamageType, float Momentum, vector HitLocation )
{
local actor Victims;
local float damageScale, dist;
local vector dir;
local int NumKilled;
local KFMonster KFMonsterVictim;
local Pawn P;
local KFPawn KFP;
local array<Pawn> CheckedPawns;
local int i;
local bool bAlreadyChecked;
if ( bHurtEntry )
return;
bHurtEntry = true;
foreach CollidingActors (class 'Actor', Victims, DamageRadius, HitLocation)
{
// don't let blast damage affect fluid - VisibleCollisingActors doesn't really work for them - jag
if( (Victims != self) && (Hurtwall != Victims) && (Victims.Role == ROLE_Authority) && !Victims.IsA('FluidSurfaceInfo')
&& ExtendedZCollision(Victims)==None )
{
if( (Instigator==None || Instigator.Health<=0) && KFPawn(Victims)!=None )
Continue;
dir = Victims.Location - HitLocation;
dist = FMax(1,VSize(dir));
dir = dir/dist;
damageScale = 1 - FMax(0,(dist - Victims.CollisionRadius)/DamageRadius);
if ( Instigator == None || Instigator.Controller == None )
{
Victims.SetDelayedDamageInstigatorController( InstigatorController );
}
P = Pawn(Victims);
if( P != none )
{
for (i = 0; i < CheckedPawns.Length; i++)
{
if (CheckedPawns[i] == P)
{
bAlreadyChecked = true;
break;
}
}
if( bAlreadyChecked )
{
bAlreadyChecked = false;
P = none;
continue;
}
KFMonsterVictim = KFMonster(Victims);
if( KFMonsterVictim != none && KFMonsterVictim.Health <= 0 )
{
KFMonsterVictim = none;
}
KFP = KFPawn(Victims);
if( KFMonsterVictim != none )
{
damageScale *= KFMonsterVictim.GetExposureTo(Location + 15 * -Normal(PhysicsVolume.Gravity));
}
else if( KFP != none )
{
// don't hurt the same team
if ( KFP.PlayerReplicationInfo != none && KFP.PlayerReplicationInfo.Team != none
&& KFP.PlayerReplicationInfo.Team.TeamIndex == PlacedTeam )
damageScale = 0;
else {
damageScale *= KFP.GetExposureTo(Location + 15 * -Normal(PhysicsVolume.Gravity));
// Reduce damage to poeple so I can make the damage radius a bit bigger for killing zeds
damageScale *= 0.5;
}
}
CheckedPawns[CheckedPawns.Length] = P;
if ( damageScale <= 0)
{
P = none;
continue;
}
else
{
//Victims = P;
P = none;
}
}
Victims.TakeDamage(damageScale * DamageAmount,Instigator,Victims.Location - 0.5 * (Victims.CollisionHeight + Victims.CollisionRadius)
* dir,(damageScale * Momentum * dir),DamageType);
if( Role == ROLE_Authority && KFMonsterVictim != none && KFMonsterVictim.Health <= 0 )
{
NumKilled++;
}
if (Vehicle(Victims) != None && Vehicle(Victims).Health > 0)
{
Vehicle(Victims).DriverRadiusDamage(DamageAmount, DamageRadius, InstigatorController, DamageType, Momentum, HitLocation);
}
}
}
bHurtEntry = false;
}
defaultproperties
{
TeamIndex=255
EnemyCountdown=5
bTriggerOnEnemy=True
MyDamage=1500.000000
ArmingCountDown=0.000000
ExplodeSounds(0)=SoundGroup'Inf_Weapons.antitankmine.antitankmine_explode01'
ExplodeSounds(1)=SoundGroup'Inf_Weapons.antitankmine.antitankmine_explode02'
ExplodeSounds(2)=SoundGroup'Inf_Weapons.antitankmine.antitankmine_explode03'
StaticMesh=StaticMesh'KF_pickups2_Trip.Supers.Pipebomb_Pickup'
}

View file

@ -0,0 +1,11 @@
<html>
<head><title>Index of /kf_sources/FoundryObj/Classes/</title></head>
<body>
<h1>Index of /kf_sources/FoundryObj/Classes/</h1><hr><pre><a href="../">../</a>
<a href="ACTION_BlowUpPipebombs.uc">ACTION_BlowUpPipebombs.uc</a> 01-Jul-2020 18:11 507
<a href="AnimatedDecoration.uc">AnimatedDecoration.uc</a> 01-Jul-2020 18:11 2901
<a href="FoundryWife.uc">FoundryWife.uc</a> 01-Jul-2020 18:11 5688
<a href="FoundryWorker.uc">FoundryWorker.uc</a> 01-Jul-2020 18:11 742
<a href="PipeBombPlaceable.uc">PipeBombPlaceable.uc</a> 01-Jul-2020 18:11 8136
</pre><hr></body>
</html>