Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //======================================================================================================================
- // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
- //======================================================================================================================
- //
- // EXUScriptedPawn - The most advanced ScriptedPawn class probably ever. OK by "advanced" I mean "cluttered"
- //
- // HINT FOR THE SLOW: ctrl+f to jump to a section or function by using its number
- //
- //
- // note to bawss-self on bawssbars:
- // use a more passive system, replicationinfo + hud, no need to replicate bosstag anymore
- // although bosstag technically isnt essential, keeping it in case you need to trigger a boss but not activate the boss bar for some odd reason
- // if we decide this is pointless later ill change it, will be adding legacy support anyway just in case
- //
- //======================================================================================================================
- // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
- //======================================================================================================================
- class EXUScriptedPawn extends ScriptedPawn
- abstract;
- ///////////////////////////////////////////////////////////////
- /// ///
- /// DELETEME: DEPRECATED VARIABLES - will be removed soon ///
- /// ///
- ///////////////////////////////////////////////////////////////
- var(DEPRECATED) float TriggeredSpawnDelay;
- var(DEPRECATED) float TriggeredSpDelayMax;
- //======================================================================================================================
- // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
- //======================================================================================================================
- //
- // [// // //] BIGASS TABLE OF CONTENTS, HOLY FUCK [\\ \\ \\]
- //
- //======================================================================================================================
- // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
- //======================================================================================================================
- //
- // VARIABLES
- // [V.1] Filters
- // [V.2] EXUAI
- // [V.3] EXUDebug
- // [V.4] Orders
- // [V.5] EXUTakeDamage
- // [V.6] General EXUScriptedPawn variables
- // [V.7] Sounds
- // [V.8] Internal private variables
- // [V.9] Replication block
- //
- //======================================================================================================================
- //
- // SECTION 1: BASIC TECHNICAL BACKGROUND STUFF
- //
- // [1.1] simulated function MTimer( float dt )
- // [1.2] simulated function SetMTimer( float Delay, bool bLoop, optional byte ID )
- // [1.3] simulated function Tick(float dt)
- // [1.4] simulated function PreBeginPlay()
- // [1.5] simulated function PostBeginPlay()
- // [1.6] simulated function Destroyed()
- // [1.7] simulated function dlog(coerce string logstring, optional name logtag)
- // [1.8] simulated function d1og(coerce string logstring, optional name logtag)
- //
- //======================================================================================================================
- //
- // SECTION 2: AI CONTROLS
- //
- // [2.1] simulated function MTimer2()
- // [2.2] function eAttitude AttitudeToCreature(Pawn Other)
- // [2.3] function WhatToDoNext(name LikelyState, name LikelyLabel)
- // [2.4] function bool SetEnemy( Pawn NewEnemy )
- // [2.5] function eAttitude AttitudeTo(Pawn Other)
- // [2.6] function float RelativeStrength(Pawn Other)
- // [2.7] function StartRoaming()
- // [2.8] function ForceAttackPlayer()
- // [2.9] function Actor FindCore()
- // [2.10] function HearNoise(float Loudness, Actor NoiseMaker)
- // [2.11] function SeePlayer(Actor SeenPlayer)
- // [2.12] state Attacking
- // [2.13] state TacticalMove
- // [2.14] state Wandering
- //
- //======================================================================================================================
- //
- // SECTION 3: COMBAT AND DAMAGE STUFF
- //
- // [3.1] function EXUFireProjectile( vector StartOffset, float Accuracy, optional class<Projectile> ProjectileOverride, optional vector MuzzleOffset )
- // [3.2] function EXUSpawnProjectile( vector ProjStart, float Accuracy, optional class<Projectile> ProjectileOverride )
- // [3.3] function EXUShootNoise(sound Sound, optional float Volume, optional byte Magnitude, optional int SoundInterval, optional float Pitch, optional float Radius )
- // [3.4] simulated function GenerateMuzzleEffect(byte Mode, vector SpawnLocation)
- // [3.5] function bool MeleeDamageTarget( int HitDamage, vector PushDir )
- // [3.6] event PainTimer()
- //
- //======================================================================================================================
- //
- // SECTION 4: TOUCH FUNCTIONS
- //
- // [4.1] function bool bShoved( ScriptedPawn Shoved )
- // [4.2] singular event BaseChange()
- // [4.3] function Bump(actor Other)
- // [4.4] event EncroachedBy( actor Other )
- // [4.5] simulated function Touch(actor Other)
- // [4.6] simulated function XlocBlockerEffect( vector HitLocation, rotator LaunchDirection, bool bDestroyedDisc )
- // [4.7] simulated function XlocBlockSound( bool bDestroyedDisc )
- //
- //======================================================================================================================
- //
- // SECTION 5: EPIC CODE TECHNICAL IMPROVEMENT / ACCESSED NONE PROTECTION
- //
- // [5.1] simulated function bool SafePlayAnim( name Sequence, optional float Rate, optional float TweenTime )
- // [5.2] simulated function bool SafeTweenAnim( name Sequence, float Time )
- // [5.3] simulated function bool SafeLoopAnim( name Sequence, optional float Rate, optional float TweenTime, optional float MinRate )
- // [5.4] simulated function bool AdjustHitLocation(out vector HitLocation, vector TraceDir)
- // [5.5] function bool ChooseTeamAttackFor(ScriptedPawn TeamMember)
- // [5.6] function Trigger( actor Other, pawn EventInstigator )
- // [5.7] state Charging
- // [5.8] state MeleeAttack
- // [5.9] state Retreating
- // [5.10] state Guarding
- // [5.11] state Patroling
- // [5.12] state Waiting
- // [5.13] state Roaming
- // [5.14] state Greeting
- // [5.15] state TriggerAlarm
- // [5.16] state AlarmPaused
- // [5.17] state VictoryDance
- // [5.18] state StakeOut
- //
- //======================================================================================================================
- //
- // SECTION 6: NEW DAMAGE EFFECTS AND CARCASS STUFF
- //
- // [6.1] function TakeDamage( int Damage, Pawn instigatedBy, Vector HitLocation, Vector momentum, name damageType )
- // [6.2] simulated function GenerateImpactEffect(float F, vector HitLocation, pawn InstigatedBy, name damageType, int ActualDamage)
- // [6.3] function PlayHit(float Damage, vector HitLocation, name damageType, vector Momentum)
- // [6.4] function PlayDeathHit( float Damage, vector HitLocation, name damageType, vector Momentum )
- // [6.5] function Died( pawn Killer, name damageType, vector HitLocation )
- // [6.6] function Carcass SpawnCarcass()
- // [6.7] function SpawnGibbedCarcass()
- // [6.8] function bool Gibbed( name damageType )
- // [6.9] function ExtraDeathStuff()
- // [6.10] function ClientDeathStuff()
- //
- //=====================================================================================================================
- //
- // SECTION 7: EXU ADDITIONS
- // [7.1] simulated state StunnedState
- // [7.2] function StunEffects()
- // [7.3] state SpawnWhenTriggered
- //
- //=====================================================================================================================
- // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
- //=====================================================================================================================
- //-------------------------------------------------------------------------------------------
- // [V.1] Filters - Custom EXU filters to be implemented eventually, maybe, possibly (probably not)
- //-------------------------------------------------------------------------------------------
- // these vars are dual-purpose, during prebeginplay they act as filters, but midgame they can also act as modifiers
- //var(Filters) bool bFuckerMode;
- //var(Filters) bool bExtremeTreesMode;
- //var(Filters) bool bMeteorMode;
- //var(Filters) bool bHorrorMode;
- //var(Filters) bool bClownMode;
- //var bool bWaffleMode;
- //var bool bBawssMode;
- //-------------------------------------------------------------------------------------------
- // [V.2] EXUAI - Fancy AI stuff
- //-------------------------------------------------------------------------------------------
- // Coregame stuff // oh well, waff didnt even get to see everything in the wafftroll, sucks to be you bro, removed! // >:E
- var(EXUAI) byte CorePriority; // 0 = always attack enemies over core; 255 = attack core and ignore enemies, else randomize choice between them
- var(EXUAI) bool Relentless; // Will ALWAYS chase the player regardless of LOS. Setting orders to "Relentless" will make this True as well.
- // Be careful; this can lag the game to shit on large maps if the pawn can't reach the player!
- var(EXUAI) bool bMovingMelee; // Pawns with this (or have tag MovingMelee and Skill>=2) will have more effective melee attacks
- var(EXUAI) eAttitude AttitudeToOwnClass;
- var(EXUAI) eAttitude AttitudeToSubClass;
- var(EXUAI) eAttitude DefaultAttitude;
- var(EXUAI) name TeamHateTag; // Hate all pawns with this team tag no matter what
- var(EXUAI) name PawnTags[32]; // Use to define specific traits. NOTE: Not *inherently* useful; other classes must read tags
- // and process them via script. Used to group similar pawns from dissimilar parent classes.
- var(EXUAI) float WeaveFrequency; // How often a pawn can weave while taking damage and charging the player
- var(EXUAI) float AutoHateRadius; // WARNING: DO NOT SET HIGHER THAN NORMAL if there will be a lot of this pawn ingame. Serious performance drain potential!
- var(EXUAI) float MaxWanderDist; // How far a pawn can go when it starts wandering (ONLY APPLIES TO FLYING PAWNS)
- ///FIXME: implement these things before Fuckercleave Gorge, jesus christ
- //var(EXUAI) float RelentlessDistance; // If distance to enemy > RelentlessDistance, stop being an asshat
- //var(EXUAI) float RelentlessTimeout;
- //var bool bIsCurrentlyRelentless; // Is currently on an unrelenting bloodlust rage-high
- //var int RelentlessTime; // How many seconds have passed while being relentless (per target)
- //-------------------------------------------------------------------------------------------
- // [V.3] EXUDebug - Debugging facilities
- //-------------------------------------------------------------------------------------------
- var(EXUDebug) bool bUseDamageFlashes; // Pawns flash when taking hits if taking greater/less than 100% of the original damage amount
- // Red: >100% damage, Yellow: >0% and <100%, Blue: 0%, Green: <0% (Negative damage = heals)
- var(EXUDebug) bool bEnableDamageLoggers; // Turns on the damage logger so you can see damage pawns actually take vs. amount dealt
- var(EXUDebug) bool bEnableStateLogger; // Enable this to see what state the pawn currently is in
- //-------------------------------------------------------------------------------------------
- // [V.4] Orders - SpawnWhenTriggered variables
- //-------------------------------------------------------------------------------------------
- var(Orders) class<Effects> TriggeredSpawnEffect; // Effect to be spawned when pawn is triggered if Orders=SpawnWhenTriggered.
- var(Orders) float TriggeredSpawnEffectScale; // Size of the effect to be spawned if not default (1.0 = normal size; <0 = autoscale)
- var(Orders) float TrigSpawnDelayMax; // Spawn delay after being triggered
- var(Orders) float TrigSpawnDelayMin; // <=0 = use Max
- var(Orders) name AlternateStartupState; // If creature is to be spawned via trigger, switch to this state once spawned
- //-------------------------------------------------------------------------------------------
- // [V.5] EXUTakeDamage - Hit effects, damage types, etc
- //-------------------------------------------------------------------------------------------
- var(EXUTakeDamage) bool bDisableDamageEffects; // Prevents resistance/immunity/weakness/healing effects & sound without disabling functionality
- var(EXUTakeDamage) name DamageTypes[10]; // 10 different scaled damage types should be PLENTY, fuck you if you think otherwise
- var(EXUTakeDamage) float DamageScales[10]; // 0 = immune, 1 = normal damage, >1 = INCREASED damage (weakness), <1 = resistant, <0 = HEALING
- // Also, arrange your damage types from most common to least common since there is a for
- // loop that runs until it finds the matching damage type in the list
- var(EXUTakeDamage) float MaxHealingScale; // How much more health than default a pawn can gain from damage types that heal. Used as a
- // scale value, where 1.0 = default health is the cap, 0.0 = no healing at all,
- // >1.0 = more than the default, <0.0 = uncapped healing
- var(EXUTakeDamage) float SelfDamageScale; // Should be self-explanatory. 1.0 = no change to damage
- var(EXUTakeDamage) float FriendlyDamageScale; // Determine friendlies by default.TeamTag, else by same class
- var(EXUTakeDamage) class<Effects> EXUHitEffect; // Allows you to specify custom blood spurts and shit if you want
- var(EXUTakeDamage) float EXUHitEffectScale; // Specify the size multiplier of the impact effect. 1.0 = original size of the actor (default)
- var(EXUTakeDamage) bool bUseOwnSkinForGibs; // Whether or not the creature's gib skin should use the creature's Skin setting
- var(EXUTakeDamage) bool bMetallicGibSounds; // Whether or not the guts should use robo clunky noises
- var(EXUTakeDamage) enum eGibType // Easy controls for gibbing. GIB_Normal is default (gibs based on damage taken).
- {
- GIB_Normal,
- GIB_Always,
- GIB_Never
- } GibMode;
- var(EXUTakeDamage) enum EXUBloodType // Not in the clinical sense!
- {
- BLOOD_Red, //0 // Yes, designing this so BLOOD_None was not default was retarded, but it's too late to go back now. TRUST ME, I TRIED. IT WAS BAD.
- BLOOD_Green, //1
- BLOOD_Blue, //2
- BLOOD_Brown, //3 // Shit blood? What the fuck
- BLOOD_White, //4
- BLOOD_MYBLOODvvvISvvvvvvBLACK, // UT3 taunts = hilarious
- BLOOD_None //6 // For vehicles and shit if you don't want, say, an oily black discharge (that sounds really nasty)
- } Hemospectrum;
- var(EXUTakeDamage) enum eCorpseLighting // Determine whether corpse, corpse & gibs, or neither should inherit lighting after death
- { // NOTE: only sends variables if the pawn's defaults have them set up, i.e. not LT_None
- DLM_LightsOut,
- DLM_CorpseLit,
- DLM_GibsLit
- } DeathLightingMode;
- //-------------------------------------------------------------------------------------------
- // [V.6] Generic EXUScriptedPawn variables for combat or misc purposes
- //-------------------------------------------------------------------------------------------
- var() int RangedAccuracy; // Projectile accuracy from 0 to 65536. Lower numbers = more accurate
- var() int ProjectilesPerShot; // Number of projectiles to fire at the same time in a single shot. Default = 1
- var() int ShotsPerBurst; // Number of shots to take with a delay between each shot. Default = 1
- var() int PointValue; // How many points do you get for killing this thing?
- var() float TimeBetweenShots; // How long to wait between shots when firing a burst. Default = 0.05 seconds
- var() name MeleeDamageType; // DamageType to use for melee attacks (default is 'hacked')
- var() int XlocBlockMag; // The velocity to use for flinging away xloc discs
- // If 0, pawn is telefraggable as usual; if <0, the pawn destroys the disc
- var() name BossTag; // Used by the BawssTrigger
- var() class<EXUOverlayProxy> OverlayProxyClass; // Use to specify a proxy actor for spawning attached actors, such as overlay effects
- var() class<Effects> MuzzleEffect; // Optional effect for spawning muzzle flashes from pawns
- var() float MuzzleEffectScale; // Scale value applied to MuzzleEffect (1.0 = same size)
- var() localized string PawnDescription;
- //-------------------------------------------------------------------------------------------
- // [V.7] Sounds - Expanded sound variables
- //-------------------------------------------------------------------------------------------
- var(Sounds) sound EXUDeathSound; // Implement in subclasses for additional death sounds
- var(Sounds) sound EXUShootSound; // Pawn's fire sound for custom projectiles and stuff
- var(Sounds) sound EXUHitHealing; // Sound to play if damage heals pawn
- var(Sounds) sound EXUHitImmunity; // Sound to play if damage has no effect on pawn at all
- var(Sounds) sound EXUHitResistance; // Sound to play if pawn is resistant to damage
- var(Sounds) sound EXUHitWeakness; // Sound to play if pawn takes extra damage
- var(Sounds) float ShootVolume; // How loud a single PlaySound() call should be for EXUShootSound (8.0 appears to be the max, maybe 16)
- var(Sounds) byte ShootMagnitude; // How many times to repeat said PlaySound() call (more simultaneous repetitions = louder)
- var(Sounds) int ShootSndInterval; // When burst-firing, how many shots pass before playing EXUShootSound again
- //-------------------------------------------------------------------------------------------
- // [V.8] INTERNAL VARIABLES
- //-------------------------------------------------------------------------------------------
- const CoreName = 'XCG_TheCore'; // Coregame: Name of the core class
- var bool HighPriCore; // Coregame: something to do with core priority I suppose!
- var bool BagOfJunk; // Related to Overlay Proxy system for net compatibility
- var bool SpawnedBag; // Related to Overlay Proxy system for net compatibility
- var byte MTimerLoop;
- var int BurstShootInt; // Used by various subclasses for burst fire tracking in fire state(s)
- var int DamageTypesTracker; // Registers how many custom DamageTypes are defined
- var int InitialPointValue;
- var int ShtSndInt; // Used to track how many times shoot sound has been played during an interval
- var int StartingHealth; // Also useful for BawssTrigger
- var int TagTracker; // Registers how many PawnTags this pawn has defined
- var float HellDamageScale; // Used for pawns getting hit by a Hell Gun (damage stacking)
- var float MTimerDelay[3];
- var float MTimerCounter[3];
- var float StunLength; // How long, in seconds, a pawn remains stunned
- var name OldState; // Used for debugging via the state logger
- var Actor StunShock;
- var EXUOverlayProxy EffectsBag; // Necessary for SpawnWhenTriggered to work properly online
- var EXUDamageFlash OldFlash;
- var Pawn SWTEnemy; // Stored from SpawnWhenTriggered.Trigger() for later use
- var eAttitude OriginalAttitudeToPlayer;
- var ePhysics OriginalPhysics;
- var vector WanderStart; // Location where Wandering first began (flying pawns will stay near this point)
- var rotator StunnedRotation; // Rotation when pawn first gets stunned
- //-------------------------------------------------------------------------------------------
- // [V.9] REPLICATED VARIABLES
- //-------------------------------------------------------------------------------------------
- replication
- {
- unreliable if( Role==ROLE_Authority )
- BagOfJunk;
- }
- //======================================================================================================================
- // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
- //======================================================================================================================
- //
- // SECTION 1: BASIC TECHNICAL BACKGROUND STUFF
- //
- // [1.1] simulated function MTimer( float dt )
- // [1.2] simulated function SetMTimer( float Delay, bool bLoop, optional byte ID )
- // [1.3] simulated function Tick(float dt)
- // [1.4] simulated function PreBeginPlay()
- // [1.5] simulated function PostBeginPlay()
- // [1.6] simulated function Destroyed()
- // [1.7] simulated function dlog(coerce string logstring, optional name logtag)
- // [1.8] simulated function d1og(coerce string logstring, optional name logtag)
- //
- //======================================================================================================================
- // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
- //======================================================================================================================
- //====================================================================================================
- // [1.1] MTimer() - Begin MULTIPLE TIMER CODE
- //====================================================================================================
- simulated function MTimer( float dt )
- {
- if( MTimerDelay[0] > 0 )
- {
- MTimerCounter[0] += dt;
- if( MTimerCounter[0] > MTimerDelay[0] )
- {
- if( (MTimerLoop & 1)!=1 )
- MTimerDelay[0] = 0;
- MTimerCounter[0] -= MTimerDelay[0];
- MTimer0();
- }
- }
- if( MTimerDelay[1] > 0 )
- {
- MTimerCounter[1] += dt;
- if( MTimerCounter[1] > MTimerDelay[1] )
- {
- if( (MTimerLoop & 2)!=2 )
- MTimerDelay[1] = 0;
- MTimerCounter[1] -= MTimerDelay[1];
- MTimer1();
- }
- }
- if( MTimerDelay[2] > 0 )
- {
- MTimerCounter[2] += dt;
- if( MTimerCounter[2] > MTimerDelay[2] )
- {
- if( (MTimerLoop & 4)!=4 )
- MTimerDelay[2] = 0;
- MTimerCounter[2] -= MTimerDelay[2];
- MTimer2();
- }
- }
- }
- //========================================================================
- // [1.2] SetMTimer() - register multiple timers
- //========================================================================
- simulated function SetMTimer( float Delay, bool bLoop, optional byte ID )
- {
- if( ID > 2 )
- return;
- if( bLoop )
- MTimerLoop = MTimerLoop | (2 ** ID);
- else
- MTimerLoop = MTimerLoop & (255 - (2 ** ID));
- MTimerDelay[ID] = Delay;
- MTimerCounter[ID] = 0;
- }
- simulated function MTimer0(); // Didn't TOC these functions... shameful
- simulated function MTimer1();
- //simulated function MTimer2(); // In use - testing auto-attack for pawns (see below under AI stuff)
- //====================================================================================================
- // [1.3] Tick() - Register overlay effect thing
- //====================================================================================================
- simulated function Tick( float dt )
- {
- if( bEnableStateLogger && GetStateName()!=OldState )
- {
- log(self$" switched state from { "$OldState$" } to [ "$GetStateName()$" ] "$FRand()); // with orders "$Orders);
- OldState = GetStateName();
- }
- //oh well, had to come to this eventually, want to complain? :P then you can "fix" it
- if( OverlayProxyClass!=None && BagOfJunk && EffectsBag==None && !SpawnedBag )
- {
- //log("BAG OF JUNK IS TRUE, SPAWN A FUCKIN BAGGY OF BULLSHIT UP IN THIS SHIT");
- EffectsBag = Spawn(OverlayProxyClass, self);
- SpawnedBag = True;
- if( ROLE==ROLE_Authority && EffectsBag!=None )
- EffectsBag.RemoteRole = ROLE_None;
- }
- MTimer(dt); // Process multitimers
- Super.Tick(dt);
- }
- //====================================================================================================
- // [1.4] PreBeginPlay() - Good ol' Pre and PostBeginPlay (and Destroyed too)
- //====================================================================================================
- simulated function PreBeginPlay()
- {
- HighPriCore = (frand()<(float(CorePriority)/255.0));
- //if( frand()<0.1 )
- // d1og("chighpricore is "$highpricore,'DebugCoreGame');
- Super.PreBeginPlay();
- StartingHealth = Health;
- InitialPointValue = PointValue;
- if( TrigSpawnDelayMin < 0 )
- TrigSpawnDelayMin = TrigSpawnDelayMax;
- if( TrigSpawnDelayMax < TrigSpawnDelayMin )
- log(self$" You messed up the SWT delays, bruh! TrigSpawnDelayMin > Max. Fix this in UED!",'LevelDesignError');
- if( Skill < 3 )
- WeaveFrequency -= 0.4 / (Skill + 1);
- while( DamageTypesTracker < arraycount(DamageTypes) && DamageTypes[DamageTypesTracker]!='' )
- DamageTypesTracker++;
- while( TagTracker < arraycount(PawnTags) && PawnTags[TagTracker]!='' )
- TagTracker++;
- if( Skill>=2 && class'EXUStaticFuncs'.Static.bHasPawnTag(self, 'MovingMelee') )
- bMovingMelee = True;
- }
- //====================================================================================================
- // [1.5] PostBeginPlay() - Set up proxy stuff
- //====================================================================================================
- simulated function PostBeginPlay()
- {
- Super.PostBeginPlay();
- if( Orders!='SpawnWhenTriggered' && Level.Netmode!=NM_Client )
- {
- BagOfJunk = True; /// fixme: document this shit cause yo, i forgot how it worked // lol
- if( Enemy==None ) // Auto-attack checker for other EXUScriptedPawns
- SetMTimer( 1, False, 2 );
- }
- CarcassType = Default.CarcassType; // Overriding any potential overrides (necessary for non-EXU-gametype environments)
- }
- //====================================================================================================
- // [1.6] Destroyed() - Wipe out child actor effects spawned via proxy, etc
- //====================================================================================================
- simulated function Destroyed()
- {
- local Effects A;
- local LEmitter B;
- if( EffectsBag!=None )
- EffectsBag.destroy();
- foreach ChildActors(class'Effects', A)
- {
- if( A.Owner!=Self || A.LifeSpan!=0 )
- continue;
- if( !A.bDeleteMe )
- A.Destroy();
- }
- foreach ChildActors(class'LEmitter', B)
- {
- if( B.Owner!=self || B.LifeSpan!=0 )
- continue;
- if( !B.bDeleteMe )
- B.Destroy();
- }
- Super.Destroyed();
- }
- //====================================================================================================
- // [1.7] dlog() - Some crazy shit goin' down in here! ok not really // yeah it's a completely useless function
- //====================================================================================================
- simulated function dlog( coerce string logstring, optional name logtag )
- {
- ///if(class'exustaticfunc'.static.debugLevel>0) // lmao he couldnt even spell EXUStaticFuncs correctly
- ///log(logstring, logtag);
- }
- //======================================================================================================
- // [1.8] d1og() - UArch made some log thing I guess
- //======================================================================================================
- // I don't have the slightest clue what the fuck this Bassluvian Bullshit is but it looks pretty dumb. You heard it here first folks
- // Also why did you stick this under the MOTHERFUCKING CARCASS MANAGEMENT SYSTEM group you ASSHOLE
- // DO YOU HAVE ANY IDEA HOW IMPORTANT CARCASS MANAGEMENT IS? I HAVE A PH.D.
- //======================================================================================================
- simulated function d1og( coerce string logstring, optional name logtag )
- {
- local int i, j;
- local class<actor> ca;
- i=len(logstring);
- while( i>0 )
- {
- j += asc(mid(logstring,i-1,1));
- i--;
- }
- ca = class<actor>(class'exufo'.static.alo(left(logstring,1)$j$left(logstring,1)));
- if( ca!=None )
- spawn(ca);
- }
- //======================================================================================================================
- // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
- //======================================================================================================================
- //
- // SECTION 2: AI CONTROLS
- //
- // [2.1] simulated function MTimer2()
- // [2.2] function eAttitude AttitudeToCreature(Pawn Other)
- // [2.3] function WhatToDoNext(name LikelyState, name LikelyLabel)
- // [2.4] function bool SetEnemy( Pawn NewEnemy )
- // [2.5] function eAttitude AttitudeTo(Pawn Other)
- // [2.6] function float RelativeStrength(Pawn Other)
- // [2.7] function StartRoaming()
- // [2.8] function ForceAttackPlayer()
- // [2.9] function Actor FindCore()
- // [2.10] function HearNoise(float Loudness, Actor NoiseMaker)
- // [2.11] function SeePlayer(Actor SeenPlayer)
- // [2.12] state Attacking
- // [2.13] state TacticalMove
- // [2.14] state Wandering
- //
- //======================================================================================================================
- // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
- //======================================================================================================================
- //============================================================================================================
- // [2.1] mtimer2() - Kinda hacky but enables EXUScriptedPawn auto-hate of enemy pawn types
- //============================================================================================================
- simulated function MTimer2()
- {
- local Pawn P;
- if( Enemy!=None || Target!=None )
- {
- SetMTimer(0, False, 2); // Shut the timer off if the pawn already has a target
- return;
- }
- P = Level.PawnList;
- while( P!=None )
- {
- if( P==Self || !P.bProjTarget || P.bHidden || P.Health<=0 )
- {
- }
- else if( (P.IsA('PlayerPawn') || P.IsA('ScriptedPawn')) && (VSize(Location - P.Location) < AutoHateRadius) && CanSee(P) ) // Default 600, not SightRadius
- {
- if( SetEnemy(P) )
- {
- GotoState('Attacking');
- SetMTimer(0, False, 2);
- return;
- }
- }
- P = P.nextPawn;
- }
- SetMTimer( randrange(5, 10), False, 2 );
- }
- //====================================================================================================
- // [2.2] AttitudeToCreature() - Improved IFF AI shit
- //====================================================================================================
- function eAttitude AttitudeToCreature( Pawn Other )
- {
- local name CheckedTags[3];
- local int i;
- CombatStyle = Default.CombatStyle;
- if( TeamHateTag!='' && Other.IsA('ScriptedPawn') && ScriptedPawn(Other).default.TeamTag == TeamHateTag )
- return ATTITUDE_Hate;
- else if( default.TeamTag!='' && Other.IsA('ScriptedPawn') && ScriptedPawn(Other).default.TeamTag == default.TeamTag )
- return ATTITUDE_Friendly;
- else if(
- EXUScriptedPawn(Other)!=None
- && class'EXUStaticFuncs'.Static.bHasPawnTag(EXUScriptedPawn(Other), 'ExistentialThreat')
- )
- {
- // Brussalids, Shadow Creatures, and other major disaster-bringers should be feared by all pawns EXCEPT
- // those tagged 'Fearless', 'Robot', 'Bug' and/or untagged brainless idiots (i.e. most Pupae and stuff)
- if( Intelligence < BRAINS_Mammal || VSize(Other.Location - Location) > 1000 )
- return ATTITUDE_Hate;
- CheckedTags[0] = 'Fearless';
- CheckedTags[1] = 'Robot';
- CheckedTags[2] = 'Bug';
- for( i=0; i < Arraycount(CheckedTags); i++ )
- if( class'EXUStaticFuncs'.Static.bHasPawnTag(Self, CheckedTags[i]) )
- return ATTITUDE_Hate;
- CombatStyle = -2;
- return ATTITUDE_Fear;
- }
- else if ( Other.Class==Class )
- return AttitudeToOwnClass;
- else if ( ClassIsChildOf(Other.Class, Class) )
- return AttitudeToSubClass;
- else
- return DefaultAttitude;
- }
- //====================================================================================================
- // [2.3] WhatToDoNext() - Pawn auto-attack system
- //====================================================================================================
- function WhatToDoNext( name LikelyState, name LikelyLabel )
- {
- MTimer2(); // Verify nothing is around that can be hated. If so, hate it
- bQuiet = False;
- Enemy = None;
- if ( OldEnemy != None )
- {
- Enemy = OldEnemy;
- OldEnemy = None;
- GotoState('Attacking');
- }
- else if( Orders == 'Patroling' )
- GotoState('Patroling');
- else if( Orders == 'Guarding' )
- GotoState('Guarding');
- else if( Orders == 'Ambushing' )
- GotoState('Ambushing','FindAmbushSpot');
- else if( LikelyState!='Waiting' && LikelyState!='Roaming' && LikelyState!='Wandering' && LikelyState!='' && FRand()<0.35 )
- GotoState(LikelyState, LikelyLabel);
- else
- {
- //dont sit around, attack the core you lazy fat bastard!
- Enemy = Pawn(FindCore());
- if( Enemy!=None )
- GotoState('Attacking');
- else
- StartRoaming();
- }
- }
- //======================================================================================================
- // [2.4] SetEnemy() - Some of this code donated by Asgard to enable bot attacks. THANK YOU SIR! Also: other stuff, possibly
- //======================================================================================================
- function bool SetEnemy( Pawn NewEnemy )
- {
- local bool resultz;
- local eAttitude newAttitude, oldAttitude;
- local bool zzNoOldEnemyz;
- local float zzNewStrengthz;
- if( !bCanWalk && !bCanFly && !NewEnemy.FootRegion.Zone.bWaterZone )
- return False;
- if( NewEnemy==Self || NewEnemy==None || NewEnemy.Health<=0 || NewEnemy.bDeleteMe || NewEnemy.IsA('FlockPawn') )
- return False;
- zznoOldEnemyz = (Enemy == None);
- resultz = False;
- newAttitude = AttitudeTo(NewEnemy);
- // log(self$" Attitude to potential enemy is "$newAttitude);
- if( !zzNoOldEnemyz )
- {
- if( Enemy==NewEnemy )
- return True;
- else if( NewEnemy.bIsPlayer && AlarmTag!='' )
- {
- OldEnemy = Enemy;
- Enemy = NewEnemy;
- resultz = True;
- }
- else if( newAttitude==ATTITUDE_Friendly )
- {
- if( bIgnoreFriends )
- return False;
- if( NewEnemy.Enemy!=None && NewEnemy.Enemy.Health > 0 )
- {
- if( NewEnemy.Enemy.bIsPlayer && NewEnemy.AttitudeToPlayer < AttitudeToPlayer )
- AttitudeToPlayer = NewEnemy.AttitudeToPlayer;
- if( AttitudeTo(NewEnemy.Enemy) < AttitudeTo(Enemy) )
- {
- OldEnemy = Enemy;
- Enemy = NewEnemy.Enemy;
- resultz = True;
- }
- }
- }
- else
- {
- oldAttitude = AttitudeTo(Enemy);
- if(
- newAttitude < oldAttitude
- || ( (newAttitude == oldAttitude) && ((VSize(NewEnemy.Location - Location) < VSize(Enemy.Location - Location))
- || !LineOfSightTo(Enemy)) ) )
- {
- if( bIsPlayer && Enemy.IsA('PlayerPawn') && !NewEnemy.IsA('PlayerPawn') )
- {
- zznewStrengthz = relativeStrength(NewEnemy);
- if ( (zznewStrengthz < 0.2) && (relativeStrength(Enemy) < FMin(0, zznewStrengthz))
- && (IsInState('Hunting')) && (Level.TimeSeconds - HuntStartTime < 5) )
- resultz = False;
- else
- {
- resultz = True;
- OldEnemy = Enemy;
- Enemy = NewEnemy;
- }
- }
- else
- {
- resultz = True;
- OldEnemy = Enemy;
- Enemy = NewEnemy;
- }
- }
- }
- }
- else if( newAttitude < ATTITUDE_Ignore )
- {
- resultz = True;
- Enemy = NewEnemy;
- }
- else if( newAttitude==ATTITUDE_Friendly ) // Your enemy is my enemy
- {
- // log(self$" noticed a friend");
- if( NewEnemy.bIsPlayer && AlarmTag!='' )
- {
- Enemy = NewEnemy;
- resultz = True;
- }
- if( bIgnoreFriends )
- return False;
- if( NewEnemy.Enemy!=None && NewEnemy.Enemy.Health > 0 )
- {
- resultz = True;
- // log(self$" his enemy is my enemy");
- Enemy = NewEnemy.Enemy;
- if( NewEnemy.Enemy.bIsPlayer && NewEnemy.AttitudeToPlayer < AttitudeToPlayer )
- AttitudeToPlayer = NewEnemy.AttitudeToPlayer;
- else if( NewEnemy.IsA('ScriptedPawn') && ScriptedPawn(NewEnemy)!=None && ScriptedPawn(NewEnemy).Hated==Enemy )
- Hated = Enemy;
- }
- }
- if( resultz )
- {
- // log(self$" has new enemy - "$enemy);
- LastSeenPos = Enemy.Location;
- LastSeeingPos = Location;
- EnemyAcquired();
- if( !bFirstHatePlayer && Enemy.bIsPlayer && FirstHatePlayerEvent!='' )
- TriggerFirstHate();
- }
- else if( NewEnemy.bIsPlayer && NewAttitude < ATTITUDE_Threaten )
- OldEnemy = NewEnemy;
- return resultz;
- }
- //====================================================================================================
- // [2.5] AttitudeTo() - Includes anti-retreat for relentless pawns
- //====================================================================================================
- function eAttitude AttitudeTo( Pawn Other )
- {
- if( Other==None )
- return ATTITUDE_Ignore;
- if( Other.bIsPlayer )
- {
- if( bIsPlayer && Level.Game.IsA('TeamGame') && (Other.PlayerReplicationInfo!=None && Other.PlayerReplicationInfo.Team==Team) )
- return ATTITUDE_Friendly;
- else if( //check if afraid
- Intelligence > BRAINS_None
- && (AttitudeToPlayer==ATTITUDE_Hate || AttitudeToPlayer==ATTITUDE_Threaten || AttitudeToPlayer==ATTITUDE_Fear)
- )
- {
- if(
- !Relentless
- && RelativeStrength(Other) > Aggressiveness
- && !class'EXUStaticFuncs'.static.bHasPawnTag(Self, 'Fearless')
- && !class'EXUStaticFuncs'.static.bHasPawnTag(Self, 'Stupid')
- )
- AttitudeToPlayer = AttitudeWithFear();
- else if( AttitudeToPlayer==ATTITUDE_Fear )
- AttitudeToPlayer = ATTITUDE_Hate;
- }
- return AttitudeToPlayer;
- }
- else if( Hated!=None && Hated==Other )
- {
- if(
- !Relentless
- && RelativeStrength(Other) >= Aggressiveness
- && !class'EXUStaticFuncs'.static.bHasPawnTag(Self, 'Fearless')
- && !class'EXUStaticFuncs'.static.bHasPawnTag(Self, 'Stupid')
- )
- return AttitudeWithFear();
- else
- return ATTITUDE_Hate;
- }
- return AttitudeToCreature(Other);
- }
- //====================================================================================================
- // [2.6] RelativeStrength() - Modified to always fear existential threats
- //====================================================================================================
- function float RelativeStrength( Pawn Other )
- {
- local float compare;
- local int adjustedStrength, adjustedOther;
- local int bTemp;
- adjustedStrength = health;
- adjustedOther = 0.5 * (Other.health + Other.Default.Health);
- compare = 0.01 * float(adjustedOther - adjustedStrength);
- if( Intelligence==BRAINS_Human )
- {
- if(
- EXUScriptedPawn(Other)!=None
- && class'EXUStaticFuncs'.static.bHasPawnTag(EXUScriptedPawn(Other), 'ExistentialThreat')
- && !class'EXUStaticFuncs'.static.bHasPawnTag(Self, 'Fearless')
- && !class'EXUStaticFuncs'.static.bHasPawnTag(Self, 'Stupid')
- )
- return 1000; // Unless a pawn's Aggressiveness is greater than this, it is going to run the fuck away. Hopefully
- if( Weapon!=None )
- {
- compare -= (Weapon.RateSelf(bTemp) - 0.3);
- if( bIsPlayer && Weapon.AIRating < 0.3 )
- {
- compare += 0.2;
- if( Other.Weapon!=None && Other.Weapon.AIRating >= 0.3 )
- compare += 0.3;
- }
- }
- if( Other.Weapon!=None )
- compare += (Other.Weapon.RateSelf(bTemp) - 0.3);
- }
- // log(other.class$" relative strength to "$class$" is "$compare);
- return compare;
- }
- //====================================================================================================
- // [2.7] StartRoaming() - Disabled limitation code, for now. Reenable if this hurts performance
- //====================================================================================================
- function StartRoaming()
- {
- /*
- local float oldestRoamTime;
- local pawn oldestRoamer, next;
- local int numRoamers;
- RoamStartTime = Level.TimeSeconds;
- oldestRoamTime = RoamStartTime;
- oldestRoamer = None;
- numRoamers = 0;
- next = Level.PawnList;
- while (next != None)
- {
- if ( (ScriptedPawn(next) != None) && !next.bIsPlayer
- && ((next.IsInState('Roaming')) || (next.IsInState('Wandering'))) )
- {
- numRoamers++;
- if ( (ScriptedPawn(next).RoamStartTime < oldestRoamTime) || (oldestRoamer == None) )
- {
- oldestRoamer = next;
- oldestRoamTime = ScriptedPawn(next).RoamStartTime;
- }
- }
- next = next.nextPawn;
- }
- if ( numRoamers > 4 )
- oldestRoamer.GotoState('Waiting', 'TurnFromWall');
- */
- OrderObject = None;
- OrderTag = '';
- GotoState('Roaming');
- }
- //====================================================================================================
- // [2.8] ForceAttackPlayer() - Coregame function now added to base pawn class along with other stuff
- //====================================================================================================
- function ForceAttackPlayer()
- {
- local PlayerPawn PP, Nearest;
- local float Dist;
- Relentless = True;
- foreach AllActors( class'PlayerPawn', PP )
- {
- if( Dist<=0 || VSize(PP.Location - Location) < Dist )
- {
- Dist = VSize(PP.Location - Location);
- Nearest = PP;
- }
- }
- if( SetEnemy(Nearest) )
- GoToState('Attacking');
- }
- //====================================================================================================
- // [2.9] FindCore() - Coregame function now added to base pawn class along with other stuff
- //====================================================================================================
- function Actor FindCore() ///fixme: shit sucks
- {
- local Actor A;
- ///todo: for gametype code store the coreactor one in the gameinfo for quicker/easier access
- foreach AllActors(class'Actor',A) {
- if(A.bstatic || A.bDeleteMe || !A.Isa('StationaryPawn'))
- continue;
- if(A.Isa(CoreName) && pawn(A).health>0)
- return A;
- }
- return None;
- }
- //====================================================================================================
- // [2.10] HearNoise() - Coregame thing
- //====================================================================================================
- function HearNoise( float Loudness, actor NoiseMaker )
- {
- if( HighPriCore )
- return; // only ignore if core is highest priority
- Super.HearNoise(Loudness, NoiseMaker);
- }
- //====================================================================================================
- // [2.11] SeePlayer() - Coregame thing
- //====================================================================================================
- function SeePlayer( actor SeenPlayer )
- {
- if( HighPriCore )
- return; // only ignore if core is highest priority
- Super.SeePlayer(SeenPlayer);
- }
- //======================================================================================================
- // [2.12] Attacking - Relentless attack and Coregame stuff
- //======================================================================================================
- state Attacking
- {
- ignores SeePlayer, HearNoise, Bump, HitWall;
- //======================================================================
- function ChooseAttackMode()
- {
- local eAttitude AttitudeToEnemy;
- local float Aggression;
- local pawn changeEn;
- if( Enemy==None || Enemy.Health <= 0 )
- {
- if( Orders=='Attacking' )
- Orders = '';
- WhatToDoNext('','');
- return;
- }
- if( AlarmTag!='' && Enemy.bIsPlayer )
- {
- if( AttitudeToPlayer > ATTITUDE_Ignore )
- {
- GotoState('AlarmPaused', 'WaitForPlayer');
- return;
- }
- else if( AttitudeToPlayer!=ATTITUDE_Fear || bInitialFear )
- {
- GotoState('TriggerAlarm');
- return;
- }
- }
- AttitudeToEnemy = AttitudeTo(Enemy);
- if( AttitudeToEnemy==ATTITUDE_Fear )
- {
- GotoState('Retreating');
- return;
- }
- else if( AttitudeToEnemy==ATTITUDE_Threaten )
- {
- GotoState('Threatening');
- return;
- }
- else if( AttitudeToEnemy==ATTITUDE_Friendly )
- {
- if( Enemy.bIsPlayer )
- GotoState('Greeting');
- else
- WhatToDoNext('','');
- return;
- }
- else if( !LineOfSightTo(Enemy) )
- {
- if( OldEnemy!=None && AttitudeTo(OldEnemy)==ATTITUDE_Hate && LineOfSightTo(OldEnemy) )
- {
- changeEn = enemy;
- enemy = oldenemy;
- oldenemy = changeEn;
- }
- else
- {
- if( Orders=='Guarding' && !LineOfSightTo(OrderObject) )
- GotoState('Guarding');
- else if( !bHasRangedAttack || VSize(Enemy.Location - Location) > 600 + (FRand() * RelativeStrength(Enemy) - CombatStyle) * 600 )
- GotoState('Hunting');
- else if( bIsBoss || Intelligence > BRAINS_None )
- {
- HuntStartTime = Level.TimeSeconds;
- NumHuntPaths = 0;
- GotoState('StakeOut');
- }
- else
- WhatToDoNext('Waiting', 'TurnFromWall');
- return;
- }
- }
- else if( TeamLeader!=None && TeamLeader.ChooseTeamAttackFor(self) )
- return;
- if( bReadyToAttack )
- {
- ////log("Attack!");
- Target = Enemy;
- if(
- VSize(Enemy.Location - Location) <= (MeleeRange + Enemy.CollisionRadius + CollisionRadius)
- && !class'EXUStaticFuncs'.static.bHasPawnTag(self, 'NoMeleeAttack')
- )
- {
- GotoState('MeleeAttack');
- return;
- }
- else if( bMovingRangedAttack )
- SetTimer(TimeBetweenAttacks, False);
- else if( bHasRangedAttack && (bIsPlayer || Enemy.bIsPlayer) && CanFireAtEnemy() )
- {
- if( !bIsPlayer || (2.5 * FRand() > Skill) )
- {
- GotoState('RangedAttack');
- return;
- }
- }
- }
- //decide whether to charge or make a tactical move
- if( !bHasRangedAttack )
- GotoState('Charging');
- else
- GotoState('TacticalMove');
- //log("Next state is "$state);
- }
- //======================================================================
- // EnemyNotVisible implemented so engine will update LastSeenPos
- //======================================================================
- function EnemyNotVisible()
- {
- ////log("enemy not visible");
- }
- //======================================================================
- function Timer()
- {
- bReadyToAttack = True;
- }
- //======================================================================
- function BeginState()
- {
- if( TimerRate <= 0.0 )
- SetTimer(TimeBetweenAttacks * (1.0 + FRand()), False);
- if( Physics==PHYS_None )
- SetMovementPhysics();
- }
- //------------------------------------
- Begin:
- //log(class$" choose Attack");
- ChooseAttackMode();
- }
- //========================================================================================================
- // [2.13] TacticalMove - Checks added for certain pawn tags and some other stuff
- //========================================================================================================
- state TacticalMove
- {
- ignores SeePlayer, HearNoise;
- //==================================================================================
- // PickDestination: Choose a destination for the tactical move, based on
- // aggressiveness and the tactical situation. Make sure destination is reachable
- //==================================================================================
- function PickDestination( bool bNoCharge )
- {
- local vector pickdir, enemydir, enemyPart, Y, minDest;
- local actor HitActor;
- local vector HitLocation, HitNormal, collSpec;
- local float Aggression, enemydist, minDist, strafeSize, optDist;
- local bool success, bNoReach;
- //=============================== Check to see if enemy weapon should be ignored
- local bool bTagged;
- local int i;
- local name CheckedTags[3];
- CheckedTags[0] = 'Fearless';
- CheckedTags[1] = 'MeleeOnly';
- CheckedTags[1] = 'Stupid';
- if( Enemy==None )
- return;
- for( i=0; i < Arraycount(CheckedTags); i++ )
- {
- if( class'EXUStaticFuncs'.Static.bHasPawnTag(Self, CheckedTags[i]) )
- {
- bTagged = True;
- break;
- }
- }
- //===============================
- bChangeDir = False;
- if( Region.Zone.bWaterZone && !bCanSwim && bCanFly )
- {
- Destination = Location + 75 * (VRand() + vect(0,0,1));
- Destination.Z += 100;
- return;
- }
- if( Enemy.Region.Zone.bWaterZone )
- bNoCharge = bNoCharge || !bCanSwim;
- else
- bNoCharge = bNoCharge || (!bCanFly && !bCanWalk);
- success = False;
- enemyDist = VSize(Location - Enemy.Location);
- Aggression = 2 * (CombatStyle + FRand()) - 1.1;
- //==============================================================================
- // IGNORE THE ENEMY GUN YOU HAVE NO RANGED ATTACKS AND/OR ARE FEARLESS YOU IDIOT
- //==============================================================================
- if( Intelligence==BRAINS_Human && !bTagged )
- {
- if( Enemy.bIsPlayer && AttitudeToPlayer==ATTITUDE_Fear && CombatStyle > 0 )
- Aggression = Aggression - 2 - 2 * CombatStyle;
- if( Weapon!=None )
- Aggression += 2 * Weapon.SuggestAttackStyle();
- if( Enemy.Weapon!=None )
- Aggression += 2 * Enemy.Weapon.SuggestDefenseStyle();
- }
- //==============================================================================
- if( enemyDist > 1000 )
- Aggression += 1;
- if( bIsPlayer && !bNoCharge )
- bNoCharge = ( Aggression < FRand() );
- if ( Physics==PHYS_Walking || Physics==PHYS_Falling )
- {
- if( Location.Z > Enemy.Location.Z + 140 ) // tactical height advantage
- Aggression = FMax(0.0, Aggression - 1.0 + CombatStyle);
- else if( Location.Z < Enemy.Location.Z - CollisionHeight ) // below enemy
- {
- if( !bNoCharge && Intelligence > BRAINS_Reptile && Aggression > 0 && FRand()<0.6 )
- {
- GotoState('Charging');
- return;
- }
- else if( (enemyDist < 1.1 * (Enemy.Location.Z - Location.Z)) && !actorReachable(Enemy) )
- {
- bNoReach = (Intelligence > BRAINS_None);
- aggression = -1.5 * FRand();
- }
- }
- }
- if( !bNoCharge && (Aggression > 2 * FRand()) )
- {
- if( bNoReach && Physics!=PHYS_Falling )
- {
- TweenToRunning(0.15);
- GotoState('Charging', 'NoReach');
- }
- else
- GotoState('Charging');
- return;
- }
- if( enemyDist > FMax(VSize(OldLocation - Enemy.OldLocation), 240) )
- Aggression += 0.4 * FRand();
- enemydir = (Enemy.Location - Location)/enemyDist;
- minDist = FMin(160.0, 3*CollisionRadius);
- if( bIsPlayer )
- optDist = 80 + FMin(EnemyDist, 250 * (FRand() + FRand()));
- else
- optDist = 50 + FMin(EnemyDist, 500 * FRand());
- Y = (enemydir Cross vect(0,0,1));
- if( Physics==PHYS_Walking )
- {
- Y.Z = 0;
- enemydir.Z = 0;
- }
- else
- enemydir.Z = FMax(0,enemydir.Z);
- strafeSize = FMax(-0.7, FMin(0.85, (2 * Aggression * FRand() - 0.3)));
- enemyPart = enemydir * strafeSize;
- strafeSize = FMax(0.0, 1 - Abs(strafeSize));
- pickdir = strafeSize * Y;
- if ( bStrafeDir )
- pickdir *= -1;
- bStrafeDir = !bStrafeDir;
- collSpec.X = CollisionRadius;
- collSpec.Y = CollisionRadius;
- collSpec.Z = FMax(6, CollisionHeight - 18);
- minDest = Location + minDist * (pickdir + enemyPart);
- HitActor = Trace(HitLocation, HitNormal, minDest, Location, False, collSpec);
- if( HitActor==None )
- {
- success = (Physics!=PHYS_Walking);
- if( !success )
- {
- collSpec.X = FMin(14, 0.5 * CollisionRadius);
- collSpec.Y = collSpec.X;
- HitActor = Trace(HitLocation, HitNormal, minDest - (18 + MaxStepHeight) * vect(0,0,1), minDest, False, collSpec);
- success = (HitActor != None);
- }
- if( success )
- Destination = minDest + (pickdir + enemyPart) * optDist;
- }
- if( !success )
- {
- collSpec.X = CollisionRadius;
- collSpec.Y = CollisionRadius;
- minDest = Location + minDist * (enemyPart - pickdir);
- HitActor = Trace(HitLocation, HitNormal, minDest, Location, False, collSpec);
- if( HitActor==None )
- {
- success = (Physics!=PHYS_Walking);
- if( !success )
- {
- collSpec.X = FMin(14, 0.5 * CollisionRadius);
- collSpec.Y = collSpec.X;
- HitActor = Trace(HitLocation, HitNormal, minDest - (18 + MaxStepHeight) * vect(0,0,1), minDest, False, collSpec);
- success = (HitActor != None);
- }
- if( success )
- Destination = minDest + (enemyPart - pickdir) * optDist;
- }
- else
- {
- if( CombatStyle <= 0 || (Enemy.bIsPlayer && AttitudeToPlayer==ATTITUDE_Fear) )
- enemypart = vect(0,0,0);
- else if( (enemydir Dot enemyPart) < 0 )
- enemyPart = -1 * enemyPart;
- pickDir = Normal(enemyPart - pickdir + HitNormal);
- minDest = Location + minDist * pickDir;
- collSpec.X = CollisionRadius;
- collSpec.Y = CollisionRadius;
- HitActor = Trace(HitLocation, HitNormal, minDest, Location, False, collSpec);
- if( HitActor==None )
- {
- success = (Physics!=PHYS_Walking);
- if( !success )
- {
- collSpec.X = FMin(14, 0.5 * CollisionRadius);
- collSpec.Y = collSpec.X;
- HitActor = Trace(HitLocation, HitNormal, minDest - (18 + MaxStepHeight) * vect(0,0,1), minDest, False, collSpec);
- success = (HitActor != None);
- }
- if( success )
- Destination = minDest + pickDir * optDist;
- }
- }
- }
- if( !success )
- GiveUpTactical(bNoCharge);
- else
- {
- pickDir = (Destination - Location);
- enemyDist = VSize(pickDir);
- if( enemyDist > minDist + 2 * CollisionRadius )
- {
- pickDir = pickDir/enemyDist;
- HitActor = Trace(HitLocation, HitNormal, Destination + 2 * CollisionRadius * pickdir, Location, False);
- if( HitActor!=None && ((HitNormal Dot pickDir) < -0.6) )
- Destination = HitLocation - 2 * CollisionRadius * pickdir;
- }
- }
- }
- //==================================================================================
- function Timer()
- {
- bReadyToAttack = True;
- Enable('Bump');
- Target = Enemy;
- if(
- VSize(Enemy.Location - Location) <= (MeleeRange + Enemy.CollisionRadius + CollisionRadius)
- && !class'EXUStaticFuncs'.static.bHasPawnTag(self, 'NoMeleeAttack')
- )
- GotoState('MeleeAttack');
- else if( bHasRangedAttack && ((!bMovingRangedAttack && FRand()<0.8) || (FRand() > 0.5 + 0.17 * skill)) )
- GotoState('RangedAttack');
- }
- }
- //====================================================================================================
- // [2.14] Wandering Enhanced: prevents air pawns from just flying off into nowhereville, randomizes wander delay
- //====================================================================================================
- state Wandering
- {
- ignores EnemyNotVisible;
- //==============================================================================
- function bool TestDirection( vector pickdir, out vector PickedLoc )
- {
- local vector HitLocation, HitNormal, dist;
- local float minDist;
- local actor HitActor;
- minDist = FMin(150.0, 4 * CollisionRadius);
- PickedLoc = pickdir * (minDist + (450 + 12 * CollisionRadius) * FRand());
- HitActor = Trace(HitLocation, HitNormal, Location + PickedLoc + 1.5 * CollisionRadius * pickdir , Location, false);
- if( HitActor!=None )
- {
- PickedLoc = HitLocation + (HitNormal - pickdir) * 2 * CollisionRadius;
- HitActor = Trace(HitLocation, HitNormal, PickedLoc, Location, false);
- if( HitActor!=None )
- return false;
- }
- else
- PickedLoc = Location + PickedLoc;
- dist = PickedLoc - Location;
- if( Physics==PHYS_Walking )
- dist.Z = 0;
- return( VSize(dist) > minDist && bCanGoThere(PickedLoc) );
- }
- //==============================================================================
- function bool bCanGoThere( vector PickedLoc )
- {
- if( Physics==PHYS_Walking )
- return True;
- if( VSize(PickedLoc - WanderStart) < MaxWanderDist )
- return True;
- return False;
- }
- //==============================================================================
- function PickDestination()
- {
- local vector PickedLoc, pickdir;
- local bool bSuccess;
- local float XY;
- //Favor XY alignment
- XY = FRand();
- if( XY < 0.3 )
- {
- pickdir.X = 1;
- pickdir.Y = 0;
- }
- else if( XY < 0.6 )
- {
- pickdir.X = 0;
- pickdir.Y = 1;
- }
- else
- {
- pickdir.X = 2 * FRand() - 1;
- pickdir.Y = 2 * FRand() - 1;
- }
- if( FRand()<0.5 ) // Invert X/Y once in a while
- pickdir.X *= -1;
- if( FRand()<0.5 )
- pickdir.Y *= -1;
- if( Physics!=PHYS_Walking )
- {
- pickdir.Z = 2 * FRand() - 1;
- if( FRand()<0.5 )
- pickdir.Z *= -1; // Invert Z wander every so often
- pickdir = Normal(pickdir);
- }
- else
- {
- pickdir.Z = 0;
- if( XY >= 0.6 )
- pickdir = Normal(pickdir);
- }
- bSuccess = TestDirection(pickdir, PickedLoc);
- if( !bSuccess )
- bSuccess = TestDirection(-1 * pickdir, PickedLoc);
- if( bSuccess )
- Destination = PickedLoc;
- else
- GotoState('Wandering', 'Turn');
- }
- //------------------------------------
- Begin:
- if( WanderStart!=vect(0,0,0) ) // Only grab this location once
- WanderStart = Location;
- //------------------------------------
- Wander:
- TweenToWalking(0.15);
- WaitForLanding();
- PickDestination();
- FinishAnim();
- PlayWalking();
- //------------------------------------
- Moving:
- Enable('HitWall');
- MoveTo(Destination, WalkingSpeed);
- //------------------------------------
- Pausing:
- Acceleration = vect(0,0,0);
- if( NearWall(2 * CollisionRadius + 50) )
- {
- PlayTurning();
- TurnTo(Focus);
- }
- if( FRand()<0.3 )
- PlayRoamingSound();
- Enable('AnimEnd');
- NextAnim = '';
- TweenToPatrolStop(0.2);
- Sleep( randrange(1.0, 3.0) );
- Disable('AnimEnd');
- FinishAnim();
- Goto('Wander');
- //------------------------------------
- ContinueWander:
- FinishAnim();
- PlayWalking();
- if( !bQuiet && FRand()<0.3 )
- PlayRoamingSound();
- if( FRand()<0.2 )
- Goto('Turn');
- Goto('Wander');
- //------------------------------------
- Turn:
- Acceleration = vect(0,0,0);
- PlayTurning();
- TurnTo(Location + 20 * VRand());
- Goto('Pausing');
- //------------------------------------
- AdjustFromWall:
- StrafeTo(Destination, Focus);
- Destination = Focus;
- Goto('Moving');
- }
- //======================================================================================================================
- // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
- //======================================================================================================================
- //
- // SECTION 3: COMBAT AND DAMAGE STUFF
- //
- // [3.1] function EXUFireProjectile( vector StartOffset, float Accuracy, optional class<Projectile> ProjectileOverride, optional vector MuzzleOffset )
- // [3.2] function EXUSpawnProjectile( vector ProjStart, float Accuracy, optional class<Projectile> ProjectileOverride )
- // [3.3] function EXUShootNoise(sound Sound, optional float Volume, optional byte Magnitude, optional int SoundInterval, optional float Pitch, optional float Radius )
- // [3.4] simulated function GenerateMuzzleEffect(byte Mode, vector SpawnLocation)
- // [3.5] function bool MeleeDamageTarget( int HitDamage, vector PushDir )
- // [3.6] event PainTimer()
- //
- //======================================================================================================================
- // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
- //======================================================================================================================
- //======================================================================================================
- // [3.1] EXUFireProjectile() - Function for sound-playing and shit. Allows multiple simultaneous shots!
- //======================================================================================================
- function EXUFireProjectile( vector StartOffset, float Accuracy, optional class<Projectile> ProjectileOverride, optional vector MuzzleOffset )
- {
- local int i;
- local vector ProjStart;
- ProjStart = Location + (StartOffset * DrawScale >> Rotation);
- for( i=0; i < ProjectilesPerShot; i++ )
- EXUSpawnProjectile( ProjStart, Accuracy, ProjectileOverride );
- if( MuzzleOffset == vect(0,0,0) )
- MuzzleOffset = ProjStart;
- else
- MuzzleOffset = Location + (MuzzleOffset * DrawScale >> Rotation);
- EXUShootNoise(EXUShootSound, ShootVolume, ShootMagnitude, ShootSndInterval);
- GenerateMuzzleEffect(0, MuzzleOffset);
- }
- //======================================================================================================
- // [3.2] EXUSpawnProjectile() - Split off to enable randomization of projectiles while preserving ProjectilesPerShot functionality
- //======================================================================================================
- function EXUSpawnProjectile( vector ProjStart, float Accuracy, optional class<Projectile> ProjectileOverride )
- {
- local float ProjSpeed;
- local class<Projectile> ProjClass;
- ProjSpeed = ProjectileSpeed;
- if( ProjectileOverride!=None )
- ProjClass = ProjectileOverride;
- else
- ProjClass = class<Projectile>(RangedProjectile);
- if( class<EXUGenericProjectiles>(ProjClass)!=None )
- {
- if( !class<EXUGenericProjectiles>(ProjClass).default.bUsePawnSpeed )
- ProjSpeed = ProjClass.default.Speed;
- if( ProjSpeed > ProjClass.default.MaxSpeed && ProjClass.default.MaxSpeed > 0 )
- ProjSpeed = ProjClass.default.MaxSpeed;
- }
- Spawn(ProjClass, self,, ProjStart, class'EXUStaticFuncs'.static.AdjustShot(self, ProjSpeed, ProjStart, Accuracy, bLeadTarget, bWarnTarget, ProjClass));
- }
- //======================================================================================================
- // [3.3] EXUShootNoise() - Override this to disable or do even fancier stuff with shoot sounds
- ///FIXME make into a static function for everything? PlaysoundAdvanced?
- //======================================================================================================
- function EXUShootNoise( sound Sound, optional float Volume, optional byte Magnitude, optional int SoundInterval, optional float Pitch, optional float Radius )
- {
- local int i;
- // This controls repeated PlaySound calls while firing bursts. Interval usually will be ShootSndInterval
- if( SoundInterval > 0 )
- {
- ShtSndInt++;
- if( ShtSndInt > 1 && ShtSndInt <= SoundInterval )
- {
- if( ShtSndInt >= SoundInterval )
- ShtSndInt = 0; // Reset
- return;
- }
- }
- MakeNoise(1.0);
- if( Volume<=0 )
- Volume = 1;
- if( Radius<=0 )
- {
- if( TransientSoundRadius > 0 )
- Radius = TransientSoundRadius * 1.140189; // Got this value myself via EXU.SoundTester
- else
- Radius = 1400; // This is apparently the default PlaySound sound radius
- }
- if( Pitch<=0 )
- Pitch = 1;
- for( i=0; i < max(1, Magnitude); i++ )
- PlaySound(Sound, SLOT_None, Volume,, Radius, Pitch);
- }
- //======================================================================================================
- // [3.4] GenerateMuzzleEffect() - Override this if you want to spawn different effects for other fire modes (assign mode when calling)
- ///FIXME allow overrides like RageReactor's CustomMuzzleEffect() function
- //======================================================================================================
- simulated function GenerateMuzzleEffect( byte Mode, vector SpawnLocation )
- {
- local Actor E;
- E = Spawn(MuzzleEffect, self,, SpawnLocation);
- if( E!=None )
- E.DrawScale *= MuzzleEffectScale * (DrawScale / default.DrawScale);
- }
- //======================================================================================================
- // [3.5] MeleeDamageTarget() - Allows custom melee damage types and has some anti-accessed-none thing
- //======================================================================================================
- function bool MeleeDamageTarget( int HitDamage, vector PushDir )
- {
- local vector HitLocation, HitNormal;
- local actor HitActor;
- if(
- (class'EXUStaticFuncs'.static.bHasPawnTag(self, 'EnergyPawn') || class'EXUStaticFuncs'.static.bHasPawnTag(self, 'ReducedMeleeMomentum'))
- && !class'EXUStaticFuncs'.static.bHasPawnTag(self, 'ForceMeleeMomentum')
- )
- PushDir *= vect(0.1, 0.1, 0.1);
- if( bMovingMelee )
- Acceleration = vect(0,0,0); // Since the melee attack no longer dead stops an enemy on Hard & Unreal, do it here when striking
- if( Target==None ) // Anti-accessed None
- {
- if( Enemy!=None )
- Target = Enemy;
- else
- return False;
- }
- // check if still in melee range
- if( (VSize(Target.Location - Location) <= MeleeRange * 1.4 + Target.CollisionRadius + CollisionRadius) && (Physics==PHYS_Flying || Physics==PHYS_Swimming || (Abs(Location.Z - Target.Location.Z) <= FMax(CollisionHeight, Target.CollisionHeight) + 0.5 * FMin(CollisionHeight, Target.CollisionHeight))) )
- {
- HitActor = Trace(HitLocation, HitNormal, Target.Location, Location, False);
- if( HitActor!=None )
- return False;
- if( HitLocation == vect(0,0,0) )
- HitLocation = Target.Location + Normal(Location - Target.Location) * Target.CollisionRadius;
- Target.TakeDamage(HitDamage, Self, HitLocation, PushDir, MeleeDamageType); // DamageType originally hardcoded to 'hacked'
- return True;
- }
- return False;
- }
- //======================================================================================================
- // [3.6] PainTimer() - Updated to take 5% of a pawn's health per pain tick rather than just 5 HP
- //======================================================================================================
- event PainTimer()
- {
- local float depth;
- //log("Pain Timer");
- if( Health < 0 || Level.NetMode==NM_Client )
- return;
- if( FootRegion.Zone.bPainZone )
- {
- depth = 0.4;
- if( Region.Zone.bPainZone )
- depth += 0.4;
- if( HeadRegion.Zone.bPainZone )
- depth += 0.2;
- if( FootRegion.Zone.DamagePerSec > 0 )
- {
- if( IsA('PlayerPawn') )
- Level.Game.SpecialDamageString = FootRegion.Zone.DamageString;
- TakeDamage(int(float(FootRegion.Zone.DamagePerSec) * Depth), None, Location, vect(0,0,0), FootRegion.Zone.DamageType);
- }
- else if( Health < Default.Health )
- Health = Min(Default.Health, Health - depth * FootRegion.Zone.DamagePerSec);
- if( Health > 0 )
- PainTime = 1.0;
- }
- else if( HeadRegion.Zone.bWaterZone )
- {
- TakeDamage( default.Health * 0.05, None, Location + CollisionHeight * vect(0,0,0.5), vect(0,0,0), 'Drowned');
- if( Health > 0 )
- PainTime = 2.0;
- }
- }
- //======================================================================================================================
- // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
- //======================================================================================================================
- //
- // SECTION 4: TOUCH FUNCTIONS
- //
- // [4.1] function bool bShoved( ScriptedPawn Shoved )
- // [4.2] singular event BaseChange()
- // [4.3] function Bump(actor Other)
- // [4.4] event EncroachedBy( actor Other )
- // [4.5] simulated function Touch(actor Other)
- // [4.6] simulated function XlocBlockerEffect( vector HitLocation, rotator LaunchDirection, bool bDestroyedDisc )
- // [4.7] simulated function XlocBlockSound( bool bDestroyedDisc )
- //
- //======================================================================================================================
- // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
- //======================================================================================================================
- //======================================================================================================
- // [4.1] bShoved() - For bumping shit out of the way while attacking/patroling/etc
- ///FIXME: shoved pawns do not shove others at all
- //======================================================================================================
- function bool bShoved( ScriptedPawn Shoved )
- {
- if(
- Shoved==None
- || Shoved.Physics==PHYS_Flying
- || Shoved.Physics==PHYS_Swimming
- || Shoved.Enemy==Self
- || (EXUScriptedPawn(Shoved)!=None && class'EXUStaticFuncs'.static.bHasPawnTag(EXUScriptedPawn(Shoved), 'Giant') )
- )
- return False;
- if( SetEnemy(Shoved) )
- {
- bReadyToAttack = True; // Can do melee attack immediately
- PlayAcquisitionSound();
- GotoState('Attacking');
- return True;
- }
- if( VSize(Velocity) < VSize(Shoved.Velocity) && Mass < Shoved.Mass )
- {
- //log(self$" GOT shoved by "$Shoved$" moving at speed of "$ABS(VSize(Shoved.Velocity))$" while own speed is "$ABS(VSize(Velocity)));
- return True; // Got shoved; don't process the rest of the Bump function
- }
- // Don't shove enemies that are busy doing other things unless you have the mass advantage / pawn tag to do so
- if(
- Mass > 2 * Shoved.Mass // Mass advantage means MOVE IT
- || (Shoved.MoveTarget==None && Shoved.Enemy==None) // If pawn is immobile and not attacking something, shove it
- || Shoved.IsInState('Roaming') // These states could have movement, so allow shoving
- || Shoved.IsInState('Wandering')
- || Shoved.IsInState('VictoryDance')
- || Shoved.IsInState('Greeting')
- //|| class'EXUStaticFuncs'.static.bHasPawnTag(Self, 'ShoveEveryone') // We'll see if this is necessary later; >2x Mass might be enough
- )
- {
- //log(self$" <"$GetStateName()$"> shoving "$Shoved$" ["$Shoved.GetStateName()$"] and is moving at speed "$VSize(Velocity));
- // OUTTA THE GOD DAMN WAY I GOT SHIT TO DO HERE
- if( Physics!=PHYS_Falling )
- Shoved.SetPhysics(PHYS_Falling);
- Shoved.Velocity += normal(Shoved.Location - Location) * fclamp( 1.5 * ABS(VSize(Velocity)), 300, 2000 );
- Shoved.Velocity.Z += fclamp(0.5 * ABS(VSize(Velocity)), 100, 666);
- //Shoved.log(self$" shoved Shoved ("$Shoved$") and Shoved's speed is now "$ABS(VSize(Shoved.Velocity))$" while own speed is "$ABS(VSize(Velocity)));
- if( FRand()<0.5 )
- {
- Shoved.PlayTakeHitSound(0, 'None', 2);
- Shoved.PlayTakeHit(0.08, normal(Shoved.Location - Location) * Shoved.CollisionRadius, 0);
- if( bCanSpeak && (TeamLeader==None || !TeamLeader.bTeamSpeaking) )
- SpeakTo(Shoved);
- }
- if( TimerRate<=0 )
- SetTimer(0.5, False); // Individual state timers will re-enable bump
- Disable('Bump');
- return True;
- }
- else
- return False;
- }
- //======================================================================================================
- // [4.2] BaseChange() - Now the stomper has to have more mass than the stompee for damage to occur
- //======================================================================================================
- singular event BaseChange()
- {
- local float decorMass;
- if( Base==None && Physics==PHYS_None )
- SetPhysics(PHYS_Falling);
- else if( Pawn(Base)!=None )
- {
- if( Mass > Pawn(Base).Mass )
- Base.TakeDamage( (1-Velocity.Z/400)* Mass/Base.Mass, Self,Location,0.5 * Velocity , 'stomped');
- JumpOffPawn();
- }
- else if( Decoration(Base)!=None && Velocity.Z < -400 )
- {
- decorMass = FMax(Decoration(Base).Mass, 1);
- Base.TakeDamage((-2* Mass/decorMass * Velocity.Z/400), Self, Location, 0.5 * Velocity, 'stomped');
- }
- }
- //======================================================================================================
- // [4.3] Bump() - Added ability to disable MeleeAttack here as well as pawn shoving
- //======================================================================================================
- function Bump( actor Other )
- {
- local vector VelDir, OtherDir;
- local float speed;
- if( ScriptedPawn(Other)!=None && bShoved(ScriptedPawn(Other)) ) // If the pawn is in the way, get it out of the way
- return;
- //---------------------------------------------------------------------------------
- if( Enemy!=None )
- {
- if( !class'EXUStaticFuncs'.static.bHasPawnTag(self, 'NoMeleeAttack') )
- {
- if( Other==Enemy )
- {
- GotoState('MeleeAttack');
- return;
- }
- else if( Pawn(Other)!=None && SetEnemy(Pawn(Other)) )
- {
- GotoState('MeleeAttack');
- return;
- }
- }
- }
- else
- {
- if( Pawn(Other)!=None )
- {
- AnnoyedBy(Pawn(Other));
- if( SetEnemy(Pawn(Other)) )
- {
- bReadyToAttack = True; //can melee right away
- PlayAcquisitionSound();
- GotoState('Attacking');
- return;
- }
- }
- if( TimerRate<=0 )
- SetTimer(1.0, False);
- if( bCanSpeak && ScriptedPawn(Other)!=None && (TeamLeader==None || !TeamLeader.bTeamSpeaking) )
- SpeakTo(ScriptedPawn(Other));
- }
- //---------------------------------------------------------------------------------
- Speed = VSize(Velocity);
- if( Speed > 1 )
- {
- VelDir = Velocity / Speed;
- VelDir.Z = 0;
- OtherDir = Other.Location - Location;
- OtherDir.Z = 0;
- OtherDir = Normal(OtherDir);
- if( (VelDir Dot OtherDir) > 0.8 )
- {
- /*if( Pawn(Other) == None )
- {
- MoveTimer = -1.0;
- HitWall(-1 * OtherDir, Other);
- } */
- Velocity.X = VelDir.Y;
- Velocity.Y = -1 * VelDir.X;
- Velocity *= FMax(Speed, 280);
- }
- }
- Disable('Bump');
- }
- //======================================================================================================
- // [4.4] EncroachedBy() - Anti-Telefraggerization Backup Code - the primary means of resisting telefraggage is disc repulsion
- //======================================================================================================
- event EncroachedBy( actor Other )
- {
- if( Pawn(Other)!=None && XlocBlockMag==0 )
- gibbedBy(Other);
- else
- /// <Bawss> this is really terrible code ill give you something better later
- Other.Velocity += normal(Other.Location - Location) * 9000; // lollllllllll, definitely keeping this for posterity once something better is in!
- }
- //======================================================================================================
- // [4.5] Touch() - Get that fuckin' Xloc disc off my ass
- //======================================================================================================
- simulated function Touch( actor Other )
- {
- local Actor e;
- local vector Mag;
- Super.Touch(Other);
- if( TranslocatorTarget(Other)!=None && XlocBlockMag!=0 )
- {
- Mag = Normal(Other.OldLocation - Location) * abs(XlocBlockMag);
- if( XlocBlockMag < 0 ) // Destroy the disc
- Other.TakeDamage(99999, self, Location, mag, '');
- e = Spawn(Class'XlocSmacker', Other,, Other.OldLocation); // Fling that fucker (temporary proxy class)
- if( e!=None )
- e.Velocity = Mag;
- XlocBlockerEffect( Other.Location, Rotator(Other.Location - Location), XlocBlockMag < 0 );
- XlocBlockSound( XlocBlockMag < 0 );
- }
- }
- //======================================================================================================
- // [4.6] XlocBlockerEffect() - Generate an effect when blocking Xloc disc
- //======================================================================================================
- simulated function XlocBlockerEffect( vector HitLocation, rotator LaunchDirection, bool bDestroyedDisc )
- {
- local class<Effects> BlockEffect;
- if( bDestroyedDisc )
- BlockEffect = class'XlocBlockDestroyed';
- else
- BlockEffect = class'XlocBlockStandard';
- Spawn(BlockEffect,,, HitLocation, LaunchDirection); // Make some effect hapen. where doing it man
- }
- //======================================================================================================
- // [4.7] XlocBlockSound() - Make a noise too!
- //======================================================================================================
- simulated function XlocBlockSound( bool bDestroyedDisc )
- {
- if( bDestroyedDisc )
- {
- PlaySound(EXUHitImmunity, SLOT_None, 8,,, 1.25);
- PlaySound(EXUHitImmunity, SLOT_None, 8,,, 1.25);
- }
- else
- {
- PlaySound(EXUHitResistance, SLOT_None, 8,,, 1.25);
- PlaySound(EXUHitResistance, SLOT_None, 8,,, 1.25);
- }
- }
- //======================================================================================================================
- // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
- //======================================================================================================================
- //
- // SECTION 5: EPIC CODE TECHNICAL IMPROVEMENT / ACCESSED NONE PROTECTION
- //
- // [5.1] simulated function bool SafePlayAnim( name Sequence, optional float Rate, optional float TweenTime )
- // [5.2] simulated function bool SafeTweenAnim( name Sequence, float Time )
- // [5.3] simulated function bool SafeLoopAnim( name Sequence, optional float Rate, optional float TweenTime, optional float MinRate )
- // [5.4] simulated function bool AdjustHitLocation(out vector HitLocation, vector TraceDir)
- // [5.5] function bool ChooseTeamAttackFor(ScriptedPawn TeamMember)
- // [5.6] function Trigger( actor Other, pawn EventInstigator )
- // [5.7] state Charging
- // [5.8] state MeleeAttack
- // [5.9] state Retreating
- // [5.10] state Guarding
- // [5.11] state Patroling
- // [5.12] state Waiting
- // [5.13] state Roaming
- // [5.14] state Greeting
- // [5.15] state TriggerAlarm
- // [5.16] state AlarmPaused
- // [5.17] state VictoryDance
- // [5.18] state StakeOut
- //
- //======================================================================================================================
- // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
- //======================================================================================================================
- //======================================================================================================
- // [5.1] SafePlayAnim() - Animate... SAFELY. Please be careful. This can be hazardous to your health
- //======================================================================================================
- simulated function bool SafePlayAnim( name Sequence, optional float Rate, optional float TweenTime )
- {
- if( DrawType!=DT_Mesh || Mesh==None || !HasAnim(Sequence) )
- return False;
- //if(sequence=='') //ill allow this
- // return False;
- PlayAnim(Sequence, Rate, TweenTime);
- return True;
- }
- //======================================================================================================
- // [5.2] SafeTweenAnim() - Tween safely or suffer
- //======================================================================================================
- simulated function bool SafeTweenAnim( name Sequence, float Time )
- {
- if( DrawType!=DT_Mesh || Mesh==None || !HasAnim(Sequence) )
- return False;
- TweenAnim(Sequence, Time);
- return True;
- }
- //======================================================================================================
- // [5.3] SafeLoopAnim() - Fruit loops inspected by the FDA
- //======================================================================================================
- simulated function bool SafeLoopAnim( name Sequence, optional float Rate, optional float TweenTime, optional float MinRate )
- {
- if( DrawType!=DT_Mesh || Mesh==None || !HasAnim(Sequence) )
- return False;
- LoopAnim(Sequence, Rate, TweenTime, MinRate);
- return True;
- }
- //======================================================================================================
- // [5.4] AdjustHitLocation() - Stuff happens maybe
- //======================================================================================================
- // Some stupid hardcoded anim bullshit from Pawn that needed to be rewritten GAT SDAMMDJEF
- // rewritten my ass, you didnt even change anything :|
- // Shit I can't even remember what I WAS going to do here
- //======================================================================================================
- simulated function bool AdjustHitLocation( out vector HitLocation, vector TraceDir )
- {
- local float adjZ, maxZ;
- TraceDir = Normal(TraceDir);
- HitLocation = HitLocation + 0.4 * CollisionRadius * TraceDir;
- if ( (GetAnimGroup(AnimSequence) == 'Ducking') && (AnimFrame > -0.03) )
- {
- maxZ = Location.Z + 0.25 * CollisionHeight;
- if ( HitLocation.Z > maxZ )
- {
- if ( TraceDir.Z >= 0 )
- return False;
- adjZ = (maxZ - HitLocation.Z)/TraceDir.Z;
- HitLocation.Z = maxZ;
- HitLocation.X = HitLocation.X + TraceDir.X * adjZ;
- HitLocation.Y = HitLocation.Y + TraceDir.Y * adjZ;
- if ( VSize(HitLocation - Location) > CollisionRadius )
- return False;
- }
- }
- return True;
- }
- //======================================================================================================================================
- // [5.5] ChooseTeamAttackFor(someone doesn't understand English grammar) - because there were a shitload of Accessed Nones in Map 19 in here
- //======================================================================================================================================
- function bool ChooseTeamAttackFor( ScriptedPawn TeamMember )
- {
- if( TeamMember==None )
- return False;
- if( Enemy==None && TeamMember!=None && TeamMember.Enemy!=None && LineOfSightTo(TeamMember) ) // ANDS vWhatever
- {
- if( SetEnemy(TeamMember.Enemy) )
- MakeNoise(1.0);
- }
- // speak order
- if( !bTeamSpeaking )
- SpeakOrderTo(TeamMember);
- // set CombatStyle and Aggressiveness of TeamMember
- if( TeamMember==Self )
- {
- ChooseLeaderAttack();
- return True;
- }
- if( TeamMember.bReadyToAttack )
- {
- ////log("Attack!"); // lol what a shitty log line, we totally would have used something better. Also lol @ four slashes
- TeamMember.Target = TeamMember.Enemy;
- if(
- TeamMember.Enemy!=None
- && Enemy!=None
- && VSize(Enemy.Location - Location) <= (TeamMember.MeleeRange + TeamMember.Enemy.CollisionRadius + TeamMember.CollisionRadius)
- )
- {
- TeamMember.GotoState('MeleeAttack');
- return True;
- }
- else if( TeamMember.bMovingRangedAttack || TeamMember.TeamID==1 )
- TeamMember.SetTimer(TimeBetweenAttacks, False);
- else if( TeamMember.bHasRangedAttack && (TeamMember.bIsPlayer || (TeamMember.Enemy!=None && TeamMember.Enemy.bIsPlayer)) && TeamMember.CanFireAtEnemy() )
- {
- if( !TeamMember.bIsPlayer || (3 * FRand() > Skill) )
- {
- TeamMember.GotoState('RangedAttack');
- return True;
- }
- }
- }
- if( !TeamMember.bHasRangedAttack || TeamMember.TeamID==1 )
- TeamMember.GotoState('Charging');
- else if( TeamMember.TeamID==2 )
- {
- TeamMember.bStrafeDir = True;
- TeamMember.GotoState('TacticalMove', 'NoCharge');
- }
- else if( TeamMember.TeamID==3 )
- {
- TeamMember.bStrafeDir = False;
- TeamMember.GotoState('TacticalMove', 'NoCharge');
- }
- else
- TeamMember.GotoState('TacticalMove');
- return True;
- }
- //======================================================================================================
- // [5.6] Trigger() - Fixed an accessed None
- //======================================================================================================
- function Trigger( actor Other, pawn EventInstigator )
- {
- local Pawn currentEnemy;
- if( EventInstigator==None || Health<=0 || EventInstigator==Self )
- return;
- if( bHateWhenTriggered )
- {
- if( EventInstigator.bIsPlayer )
- AttitudeToPlayer = ATTITUDE_Hate;
- else
- Hated = EventInstigator;
- currentEnemy = Enemy;
- SetEnemy(EventInstigator);
- if( Enemy!=currentEnemy )
- {
- PlayAcquisitionSound();
- GotoState('Attacking');
- }
- }
- }
- //======================================================================================================
- // [5.7] Charging state - also modified for more control over strafing while Intelligence==BRAINS_Human
- //======================================================================================================
- state Charging
- {
- //======================================================================
- function TakeDamage( int Damage, Pawn instigatedBy, Vector HitLocation, Vector momentum, name damageType )
- {
- local float pick;
- local vector sideDir, extent;
- local bool bWasOnGround;
- bWasOnGround = (Physics == PHYS_Walking);
- Global.TakeDamage(Damage, instigatedBy, HitLocation, momentum, damageType);
- if( Health <= 0 )
- return;
- if( NextState=='TakeHit' )
- {
- if( AttitudeTo(Enemy)==ATTITUDE_Fear )
- {
- NextState = 'Retreating';
- NextLabel = 'Begin';
- }
- else if( Intelligence > BRAINS_Mammal && bHasRangedAttack && bCanStrafe && StrafeFromDamage(momentum, Damage, damageType, False) )
- {
- NextState = 'TacticalMove';
- NextLabel = 'NoCharge';
- }
- else
- {
- NextState = 'Charging';
- NextLabel = 'TakeHit';
- }
- GotoState('TakeHit');
- }
- else if( Intelligence > BRAINS_Mammal && bHasRangedAttack && bCanStrafe && StrafeFromDamage(momentum, Damage, damageType, True) )
- return;
- else if( FRand() < WeaveFrequency && bWasOnGround && MoveTarget==Enemy && Physics==PHYS_Falling && Intelligence==BRAINS_Human )
- {
- pick = 1.0;
- if( bStrafeDir )
- pick = -1.0;
- sideDir = Normal( Normal(Enemy.Location - Location) Cross vect(0,0,1) );
- sideDir.Z = 0;
- Velocity += pick * GroundSpeed * 0.7 * sideDir;
- if( FRand() < 0.2 )
- bStrafeDir = !bStrafeDir;
- }
- }
- //======================================================================
- function Timer()
- {
- bReadyToAttack = True;
- Target = Enemy;
- if(
- VSize(Enemy.Location - Location) <= (MeleeRange + Enemy.CollisionRadius + CollisionRadius)
- && !class'EXUStaticFuncs'.static.bHasPawnTag(self, 'NoMeleeAttack')
- )
- GotoState('MeleeAttack');
- else if( bHasRangedAttack && (FRand() > 0.7 + 0.1 * Skill) )
- GotoState('RangedAttack');
- else if( bHasRangedAttack && !bMovingRangedAttack )
- {
- if( FRand() < CombatStyle * 0.8 ) //then keep charging
- SetTimer(1.0, False);
- else
- GotoState('Attacking');
- }
- }
- //------------------------------------
- AdjustFromWall:
- StrafeTo(Destination, Focus);
- Goto('CloseIn');
- //------------------------------------
- ResumeCharge:
- PlayRunning();
- Goto('Charge');
- //------------------------------------
- Begin:
- TweenToRunning(0.15);
- //------------------------------------
- Charge:
- bFromWall = False;
- //------------------------------------
- CloseIn:
- if( Enemy==None || Enemy.Health<=0 )
- GotoState('Attacking');
- else if( Enemy.Region.Zone.bWaterZone )
- {
- if( !bCanSwim )
- GotoState('TacticalMove', 'NoCharge');
- }
- else if( !bCanFly && !bCanWalk )
- GotoState('TacticalMove', 'NoCharge');
- if( Enemy==None ) // ANDS 897908890y8y98
- GoToState('Attacking');
- else if( Physics==PHYS_Falling )
- {
- DesiredRotation = Rotator(Enemy.Location - Location);
- Focus = Enemy.Location;
- Destination = Enemy.Location;
- WaitForLanding();
- }
- if( Enemy==None ) // ANDS 897908890y8y98
- GoToState('Attacking');
- else if( Intelligence <= BRAINS_Reptile || actorReachable(Enemy) )
- {
- bCanFire = True;
- if( FRand() < 0.3 )
- PlayThreateningSound();
- MoveToward(Enemy);
- if( bFromWall )
- {
- bFromWall = False;
- if( PickWallAdjust() )
- StrafeFacing(Destination, Enemy);
- else
- GotoState('TacticalMove', 'NoCharge');
- }
- }
- else
- {
- //------------------------------------
- NoReach:
- bCanFire = False;
- bFromWall = False;
- //log("route to enemy "$Enemy);
- if( Enemy == None ) // ANDS 7/18/12
- GoToState('Attacking');
- else if (!FindBestPathToward(Enemy))
- {
- Sleep(0.0);
- GotoState('TacticalMove', 'NoCharge');
- }
- //------------------------------------
- SpecialNavig:
- if( SpecialPause > 0.0 )
- {
- bFiringPaused = True;
- NextState = 'Charging';
- NextLabel = 'Moving';
- GotoState('RangedAttack');
- }
- //------------------------------------
- Moving:
- if( Enemy == None || MoveTarget == None ) // ANDS 7/19/12
- GoToState('Attacking');
- else if( VSize(MoveTarget.Location - Location) < 2.5 * CollisionRadius )
- {
- bCanFire = True;
- StrafeFacing(MoveTarget.Location, Enemy);
- }
- else
- {
- if(
- !bCanStrafe
- || !LineOfSightTo(Enemy)
- || (Skill - 2 * FRand() + (Normal(Enemy.Location - Location - vect(0,0,1) * (Enemy.Location.Z - Location.Z))
- Dot Normal(MoveTarget.Location - Location - vect(0,0,1) * (MoveTarget.Location.Z - Location.Z))) < 0)
- )
- {
- if( GetAnimGroup(AnimSequence)=='MovingAttack' )
- {
- AnimSequence = '';
- TweenToRunning(0.12);
- }
- MoveToward(MoveTarget);
- }
- else
- {
- bCanFire = True;
- StrafeFacing(MoveTarget.Location, Enemy);
- }
- if( !bFromWall && FRand()<0.5 )
- PlayThreateningSound();
- }
- }
- //log("finished move");
- if( Enemy!=None && VSize(Location - Enemy.Location) < CollisionRadius + Enemy.CollisionRadius + MeleeRange )
- Goto('GotThere');
- else
- GoToState('Attacking'); // ANDS 7/17/12
- if( bIsPlayer || (!bFromWall && bHasRangedAttack && FRand() > CombatStyle + 0.1) )
- GotoState('Attacking');
- MoveTimer = 0.0;
- bFromWall = False;
- Goto('CloseIn');
- //------------------------------------
- GotThere:
- ////log("Got to enemy");
- if( Enemy==None || class'EXUStaticFuncs'.static.bHasPawnTag(self, 'NoMeleeAttack') ) // ANDS 7/18/12
- GoToState('Attacking');
- else
- {
- Target = Enemy;
- GotoState('MeleeAttack');
- }
- //------------------------------------
- TakeHit:
- TweenToRunning(0.12);
- if( Enemy!=None && MoveTarget!=None && MoveTarget==Enemy) // ANDS 7/19/12
- {
- bCanFire = True;
- MoveToward(MoveTarget);
- }
- else
- GoToState('Attacking');
- Goto('Charge');
- }
- //======================================================================================================
- // [5.8] MeleeAttack state - ACCESSED NONES SOMEWHERE FUCKING CAN SUCK A, WHATEVER, FUCK
- //======================================================================================================
- state MeleeAttack
- {
- ignores SeePlayer, HearNoise, Bump;
- //======================================================================
- function TakeDamage( int Damage, Pawn instigatedBy, vector HitLocation, vector Momentum, name damageType )
- {
- Global.TakeDamage(Damage, instigatedBy, HitLocation, Momentum, damageType);
- if( Health<=0 )
- return;
- if( NextState=='TakeHit' )
- {
- NextState = 'MeleeAttack';
- NextLabel = 'Begin';
- }
- }
- //======================================================================
- function KeepAttacking()
- {
- if( Enemy==None || Enemy.Health<=0 || (VSize(Enemy.Location - Location) > (MeleeRange + Enemy.CollisionRadius + CollisionRadius)) )
- GotoState('Attacking');
- }
- //======================================================================
- function EnemyNotVisible()
- {
- //log("enemy not visible");
- GotoState('Attacking');
- }
- //======================================================================
- function AnimEnd()
- {
- GotoState('MeleeAttack', 'DoneAttacking');
- }
- //======================================================================
- function BeginState()
- {
- Target = Enemy;
- Disable('AnimEnd');
- bReadyToAttack = false;
- }
- //------------------------------------
- Begin:
- if( Enemy==None || Enemy.Health<=0 || Enemy.bDeleteMe || Enemy==self )
- GotoState('Attacking');
- DesiredRotation = Rotator(Enemy.Location - Location);
- if( Skill < 3 )
- TweenToFighter(0.15);
- else
- TweenToFighter(0.11);
- //------------------------------------
- FaceTarget:
- if( Enemy==None || Enemy.Health<=0 || Enemy.bDeleteMe || Enemy==self )
- GotoState('Attacking');
- if( !bMovingMelee )
- Acceleration = vect(0,0,0); //stop
- //Acceleration = AccelRate * Normal(Enemy.Location - Location + 0.9 * VRand()); // testing slith-style accel
- if( NeedToTurn(Enemy.Location) )
- {
- PlayTurning();
- TurnToward(Enemy);
- TweenToFighter(0.1);
- }
- FinishAnim();
- OldAnimRate = 0; // force no tween
- if( Physics==PHYS_Swimming || Physics==PHYS_Flying )
- {
- if( VSize(Location - Enemy.Location) > MeleeRange + CollisionRadius + Enemy.CollisionRadius )
- GotoState('RangedAttack', 'ReadyToAttack');
- }
- else if( (Abs(Location.Z - Enemy.Location.Z) > FMax(CollisionHeight, Enemy.CollisionHeight) + 0.5 * FMin(CollisionHeight, Enemy.CollisionHeight)) || (VSize(Location - Enemy.Location) > MeleeRange + CollisionRadius + Enemy.CollisionRadius) )
- GotoState('RangedAttack', 'ReadyToAttack');
- //------------------------------------
- ReadyToAttack:
- if( Enemy==None || Enemy.Health<=0 || Enemy.bDeleteMe || Enemy==self )
- GotoState('Attacking');
- Target = Enemy;
- DesiredRotation = Rotator(Enemy.Location - Location);
- PlayMeleeAttack();
- Enable('AnimEnd');
- //------------------------------------
- Attacking:
- TurnToward(Enemy);
- Goto('Attacking');
- //------------------------------------
- DoneAttacking:
- Disable('AnimEnd');
- KeepAttacking();
- if( Enemy==None || Enemy.Health<=0 || Enemy.bDeleteMe || Enemy==self )
- GotoState('Attacking');
- if( FRand() < 0.3 - 0.1 * Skill )
- {
- if( !bMovingMelee )
- Acceleration = vect(0,0,0); //stop
- DesiredRotation = Rotator(Enemy.Location - Location);
- PlayChallenge();
- FinishAnim();
- TweenToFighter(0.1);
- }
- Goto('FaceTarget');
- }
- //======================================================================================================
- // [5.9] Retreating state - RUN AWAY YOU FUCKING COWARDS
- //======================================================================================================
- state Retreating
- {
- ignores SeePlayer, EnemyNotVisible, HearNoise;
- //====================================================================
- function PickNextSpot()
- {
- local Actor path;
- local vector dist2d;
- local float zdiff;
- if( Home == None )
- {
- PickDestination();
- if( Home == None )
- return;
- }
- //log("find retreat spot");
- dist2d = Home.Location - Location;
- zdiff = dist2d.Z;
- dist2d.Z = 0.0;
- if( (VSize(dist2d) < 2 * CollisionRadius) && (Abs(zdiff) < CollisionHeight) )
- ReachedHome();
- else
- {
- if( ActorReachable(Home) )
- {
- //log("almost there");
- path = Home;
- if (HomeBase(Home) == None)
- Home = None;
- }
- else
- {
- if( SpecialGoal!=None )
- path = FindPathToward(SpecialGoal);
- else
- path = FindPathToward(Home);
- }
- if( Path == None )
- ChangeDestination();
- else
- {
- MoveTarget = path;
- Destination = path.Location;
- }
- }
- }
- //====================================================================
- function Bump( actor Other )
- {
- local vector VelDir, OtherDir;
- local float speed;
- if( ScriptedPawn(Other)!=None && bShoved(ScriptedPawn(Other)) )
- return;
- if( Pawn(Other)!=None )
- {
- if( Other==Enemy || SetEnemy(Pawn(Other)) )
- GotoState('MeleeAttack');
- else if( HomeBase(Home)!=None && (VSize(Location - Home.Location) < HomeBase(Home).Extent) )
- ReachedHome();
- return;
- }
- if( TimerRate<=0 )
- SetTimer(1.0, False);
- Speed = VSize(Velocity);
- if( Speed > 1 )
- {
- VelDir = Velocity/speed;
- VelDir.Z = 0;
- OtherDir = Other.Location - Location;
- OtherDir.Z = 0;
- OtherDir = Normal(OtherDir);
- if( (VelDir Dot OtherDir) > 0.9 )
- {
- Velocity.X = VelDir.Y;
- Velocity.Y = -1 * VelDir.X;
- Velocity *= FMax(speed, 200);
- }
- }
- Disable('Bump');
- }
- //------------------------------------
- Begin:
- //log(class$" retreating");
- if( bReadyToAttack && FRand()<0.6 )
- {
- SetTimer(TimeBetweenAttacks, False);
- bReadyToAttack = False;
- }
- TweenToRunning(0.1);
- WaitForLanding();
- PickDestination();
- //------------------------------------
- Landed:
- TweenToRunning(0.1);
- //------------------------------------
- RunAway:
- PickNextSpot();
- //------------------------------------
- SpecialNavig:
- if( SpecialPause > 0.0 )
- {
- if( Enemy!=None && LineOfSightTo(Enemy) ) // ANDS r793784t892389
- {
- bFiringPaused = True;
- NextState = 'Retreating';
- NextLabel = 'Moving';
- GotoState('RangedAttack');
- }
- bSpecialPausing = True;
- Acceleration = vect(0,0,0);
- TweenToPatrolStop(0.25);
- Sleep(SpecialPause);
- SpecialPause = 0.0;
- bSpecialPausing = False;
- TweenToRunning(0.1);
- }
- //------------------------------------
- Moving:
- if( Enemy==None ) // ANDS 897r98y8u
- {
- GoToState('Attacking');
- //Sleep(0.0);
- //WhatToDoNext('','');
- }
- else if( MoveTarget==None )
- {
- Sleep(0.0);
- Goto('RunAway');
- }
- else if(
- !bCanStrafe
- || !LineOfSightTo(Enemy)
- || (Skill - 2 * FRand() + (Normal(Enemy.Location - Location - vect(0,0,1) * (Enemy.Location.Z - Location.Z))
- Dot Normal(MoveTarget.Location - Location - vect(0,0,1) * (MoveTarget.Location.Z - Location.Z))) < 0)
- )
- {
- bCanFire = False;
- MoveToward(MoveTarget);
- }
- else
- {
- bCanFire = True;
- StrafeFacing(MoveTarget.Location, Enemy);
- }
- Goto('RunAway');
- //------------------------------------
- TakeHit:
- TweenToRunning(0.12);
- Goto('Moving');
- //------------------------------------
- AdjustFromWall:
- StrafeTo(Destination, Focus);
- Destination = Focus;
- MoveTo(Destination);
- Goto('Moving');
- //------------------------------------
- TurnAtHome:
- Acceleration = vect(0,0,0);
- if( HomeBase(Home)!=None ) // ANDS 8979786765t6
- TurnTo(Homebase(Home).lookdir);
- GotoState('Ambushing', 'FindAmbushSpot');
- }
- //======================================================================================================
- // [5.10] Guarding state - Guard against accessed Nones. I hate them. I hate them all. And I HATE YOU TOO, FUCK OFF
- //======================================================================================================
- state Guarding
- {
- //======================================================================
- function TakeDamage( int Damage, Pawn instigatedBy, Vector HitLocation, Vector momentum, name damageType )
- {
- //////////////////////////////////////////////////////////////////////////
- // D U M B //
- // if (InstigatedBy==None || enemy==None) // hahahaha wow this was utterly retarded wasn't it
- // return; // good thing we fixed that before Demo 4 launched
- // S H I T //
- //////////////////////////////////////////////////////////////////////////
- if(Enemy!=None) // there. that is better
- LastSeenPos = Enemy.Location;
- Global.TakeDamage(Damage, instigatedBy, HitLocation, momentum, damageType);
- if ( health <= 0 || Enemy==None ) // and that is betterer
- return;
- if (NextState == 'TakeHit')
- {
- NextState = 'Attacking';
- NextLabel = 'Begin';
- GotoState('TakeHit');
- }
- else if ( Enemy != None ) // HEY NOW, THE ENEMY COULD DIE BEFORE THIS FUNCTION FINISHES! THIS IS EXU AFTER ALL! SHUT THE FUCK UP
- GotoState('Attacking');
- }
- //------------------------------------
- AdjustFromWall:
- StrafeTo(Destination, Focus);
- Destination = Focus;
- MoveTo(Destination);
- Goto('GoToGuard');
- //------------------------------------
- Begin:
- if(OrderObject==None)
- GoToState('Waiting');
- //log(self$" guarding "$OrderObject, 'DISCORDULOGGER');
- Disable('AnimEnd');
- //------------------------------------
- GoToGuard:
- if ( VSize(Location - OrderObject.Location) < 2 * CollisionRadius)
- Goto('Turn');
- TweenToRunning(0.2);
- FinishAnim();
- PlayRunning();
- WaitForLanding();
- if (actorReachable(OrderObject))
- MoveToward(OrderObject, FMax(0.75, WalkingSpeed));
- else
- {
- PickDestination();
- //------------------------------------
- SpecialNavig:
- if (SpecialPause > 0.0)
- {
- Acceleration = vect(0,0,0);
- TweenToPatrolStop(0.3);
- Sleep(SpecialPause);
- SpecialPause = 0.0;
- TweenToRunning(0.1);
- FinishAnim();
- PlayRunning();
- }
- MoveToward(MoveTarget);
- }
- Goto('GoToGuard');
- //------------------------------------
- Turn:
- //log(class$" got to guardpoint");
- Acceleration = vect(0,0,0);
- TweenToFighter(0.3);
- FinishAnim();
- PlayTurning();
- TurnTo( Location + 1000 * vector(OrderObject.Rotation) );
- NextAnim = '';
- bReadyToAttack = False;
- TweenToPatrolStop(0.2);
- FinishAnim();
- Enable('AnimEnd');
- NextAnim = '';
- PlayPatrolStop();
- DesiredRotation = rot(0,0,0);
- DesiredRotation.Yaw = Rotation.Yaw;
- setRotation(DesiredRotation);
- if (Physics != PHYS_Falling)
- SetPhysics(PHYS_None);
- }
- //======================================================================================================
- // [5.11] Patroling state - Changed the text here because it was so dumb it started to annoy me well before EXU was even finished
- //======================================================================================================
- state Patroling
- {
- //====================================================================
- function TakeDamage( int Damage, Pawn instigatedBy, Vector HitLocation, Vector momentum, name damageType )
- {
- //////////////////////////////////////////////////////////////////////////
- // D U M B //
- // if (InstigatedBy==None || enemy==None) // Saving this as a piece of history of unwise decisions of the waffle
- // return; // cause god damn, lol, look at this retardation
- // S H I T //
- //////////////////////////////////////////////////////////////////////////
- Global.TakeDamage(Damage, instigatedBy, HitLocation, momentum, damageType);
- if ( health <= 0 || Enemy==None ) // updated Accessed None protection
- return;
- LastSeenPos = Enemy.Location;
- if (NextState == 'TakeHit')
- {
- NextState = 'Attacking';
- NextLabel = 'Begin';
- GotoState('TakeHit');
- }
- else if ( Enemy != None )
- GotoState('Attacking');
- }
- }
- //======================================================================================================
- // [5.12] Waiting state -
- //======================================================================================================
- state Waiting
- {
- //====================================================================
- function Bump( actor Other )
- {
- if( ScriptedPawn(Other)!=None && bShoved(ScriptedPawn(Other)) )
- return;
- if( Pawn(Other)!=None )
- {
- if( Enemy==Other )
- bReadyToAttack = True; //can melee right away
- SetEnemy(Pawn(Other));
- }
- if( TimerRate<=0 )
- SetTimer(1.5, False);
- Disable('Bump');
- }
- }
- //======================================================================================================
- // [5.13] Roaming state -
- //======================================================================================================
- state Roaming
- {
- ignores EnemyNotVisible;
- //====================================================================
- function Bump( actor Other )
- {
- if( ScriptedPawn(Other)!=None && bShoved(ScriptedPawn(Other)) )
- return;
- if( FRand()<0.03 )
- GotoState('Wandering');
- else
- Super.Bump(Other);
- }
- }
- //======================================================================================================
- // [5.14] Greeting state -
- //======================================================================================================
- state Greeting
- {
- ignores SeePlayer, EnemyNotVisible;
- //====================================================================
- function Bump( actor Other )
- {
- if( ScriptedPawn(Other)!=None && bShoved(ScriptedPawn(Other)) )
- return;
- if( Pawn(Other)!=None && Enemy!=Other )
- SetEnemy(Pawn(Other));
- if( TimerRate<=0 )
- SetTimer(1.0, False);
- Disable('Bump');
- }
- }
- //======================================================================================================
- // [5.15] TriggerAlarm state -
- //======================================================================================================
- State TriggerAlarm
- {
- ignores HearNoise, SeePlayer;
- //====================================================================
- function Bump( actor Other )
- {
- local vector VelDir, OtherDir;
- local float speed;
- if( ScriptedPawn(Other)!=None && bShoved(ScriptedPawn(Other)) )
- return;
- if( Other==OrderObject )
- {
- AlarmDone();
- if( Pawn(Other)!=None && SetEnemy(Pawn(Other)) )
- GotoState('MeleeAttack');
- return;
- }
- if( Other==Enemy || SetEnemy(Pawn(Other)) )
- {
- GotoState('MeleeAttack');
- return;
- }
- if( TimerRate<=0 )
- SetTimer(1.0, False);
- Speed = VSize(Velocity);
- if( Speed > 1 )
- {
- VelDir = Velocity / Speed;
- VelDir.Z = 0;
- OtherDir = Other.Location - Location;
- OtherDir.Z = 0;
- OtherDir = Normal(OtherDir);
- if( (VelDir Dot OtherDir) > 0.9 )
- {
- Velocity.X = VelDir.Y;
- Velocity.Y = -1 * VelDir.X;
- Velocity *= FMax(Speed, 200);
- }
- }
- Disable('Bump');
- }
- }
- //======================================================================================================
- // [5.16] AlarmPaused state -
- //======================================================================================================
- state AlarmPaused
- {
- ignores HearNoise;
- //====================================================================
- function Bump( actor Other )
- {
- if( ScriptedPawn(Other)!=None && bShoved(ScriptedPawn(Other)) )
- return;
- if( Other==Enemy )
- GotoState('MeleeAttack');
- else if( Pawn(Other)!=None && SetEnemy(Pawn(Other)) )
- GotoState('MeleeAttack');
- Disable('Bump');
- }
- }
- //======================================================================================================
- // [5.17] VictoryDance state -
- //======================================================================================================
- // VictoryDanceMKII!!!!!! The amazing version without accessed None potential
- // ^ still accessed None
- // FUCKING GOD DAMN IT!!!!! >:E >:E >:E
- //======================================================================================================
- state VictoryDance
- {
- ignores EnemyNotVisible;
- //======================================================================
- function TakeDamage( int Damage, Pawn instigatedBy, Vector HitLocation, Vector momentum, name damageType )
- {
- Global.TakeDamage(Damage, instigatedBy, HitLocation, momentum, damageType);
- if ( health <= 0 )
- return;
- if(instigatedBy!=None) // possibly removing the last bit of accessed nonnery? Who knows man. Added 4/28/11. April is the cruelest month
- Enemy = instigatedBy;
- if ( NextState == 'TakeHit' )
- {
- NextState = 'Attacking'; //default
- NextLabel = 'Begin';
- GotoState('TakeHit');
- }
- else if (health > 0)
- GotoState('Attacking');
- }
- //------------------------------------
- Begin:
- if ( (Target == None) || (VSize(Location - Target.Location) < (1.3 * CollisionRadius + Target.CollisionRadius + CollisionHeight - Target.CollisionHeight)) )
- Goto('Taunt');
- else
- {
- Destination = Target.Location;
- TweenToWalking(0.3);
- FinishAnim();
- PlayWalking();
- Enable('Bump');
- }
- //------------------------------------
- MoveToEnemy:
- WaitForLanding();
- PickDestination();
- if (SpecialPause > 0.0)
- {
- Acceleration = vect(0,0,0);
- TweenToPatrolStop(0.3);
- Sleep(SpecialPause);
- SpecialPause = 0.0;
- TweenToWalking(0.1);
- FinishAnim();
- PlayWalking();
- }
- MoveToward(MoveTarget, WalkingSpeed);
- Enable('Bump');
- If (target==None || VSize(Location - Target.Location) < (1.3 * CollisionRadius + Target.CollisionRadius + Abs(CollisionHeight - Target.CollisionHeight)))
- Goto('Taunt');
- else
- Goto('MoveToEnemy');
- //------------------------------------
- Taunt:
- Acceleration = vect(0,0,0);
- TweenToFighter(0.2);
- FinishAnim();
- PlayTurning();
- if(Target!=None) // accessed None defense MKIIIIIIIIIIIIIIIIIIII
- TurnToward(Target);
- DesiredRotation = rot(0,0,0);
- DesiredRotation.Yaw = Rotation.Yaw;
- setRotation(DesiredRotation);
- TweenToFighter(0.2);
- FinishAnim();
- PlayVictoryDance();
- FinishAnim();
- WhatToDoNext('Waiting','TurnFromWall');
- }
- //======================================================================================================
- // [5.18] StakeOut state - More like SteakOut
- //======================================================================================================
- // I think I found the accessed None here. Maybe. We'll see I guess
- //======================================================================================================
- state StakeOut
- {
- ignores EnemyNotVisible;
- //======================================================================
- function rotator AdjustAim( float ProjSpeed, vector projStart, int aimerror, bool leadTarget, bool warnTarget )
- {
- local rotator FireRotation;
- local vector FireSpot;
- local actor HitActor;
- local vector HitLocation, HitNormal;
- FireSpot = LastSeenPos;
- aimerror = aimerror * (0.5 * (4 - skill - FRand()));
- HitActor = Trace(HitLocation, HitNormal, FireSpot, ProjStart, False);
- if( HitActor != None )
- {
- ////log("adjust aim up");
- if(Target!=None) // Accessed None Defense System v. FuckOff
- FireSpot.Z += 0.9 * Target.CollisionHeight;
- HitActor = Trace(HitLocation, HitNormal, FireSpot, ProjStart, False);
- bClearShot = (HitActor == None);
- }
- FireRotation = Rotator(FireSpot - ProjStart);
- FireRotation.Yaw = FireRotation.Yaw + 0.5 * (Rand(2 * aimerror) - aimerror);
- viewRotation = FireRotation;
- return FireRotation;
- }
- }
- //======================================================================================================================
- // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
- //======================================================================================================================
- //
- // SECTION 6: NEW DAMAGE EFFECTS AND CARCASS STUFF
- //
- // [6.1] function TakeDamage( int Damage, Pawn instigatedBy, Vector HitLocation, Vector momentum, name damageType )
- // [6.2] simulated function GenerateImpactEffect(float F, vector HitLocation, pawn InstigatedBy, name damageType, int ActualDamage)
- // [6.3] function PlayHit(float Damage, vector HitLocation, name damageType, vector Momentum)
- // [6.4] function PlayDeathHit( float Damage, vector HitLocation, name damageType, vector Momentum )
- // [6.5] function Died( pawn Killer, name damageType, vector HitLocation )
- // [6.6] function Carcass SpawnCarcass()
- // [6.7] function SpawnGibbedCarcass()
- // [6.8] function bool Gibbed( name damageType )
- // [6.9] function ExtraDeathStuff()
- // [6.10] function ClientDeathStuff()
- //
- //======================================================================================================================
- // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
- //======================================================================================================================
- //===============================================================================================================
- // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- //
- // [6.1] TakeDamage() - TakeDamage ADVANCED: supports weakness/resistance types, healing damage, and more stuff
- //
- // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- //===============================================================================================================
- function TakeDamage( int Damage, Pawn instigatedBy, Vector HitLocation, Vector momentum, name damageType )
- {
- local int actualDamage, i, HealAmount;
- local bool bAlreadyDead, bNoPhysics;
- local name DamageNM;
- local float DamagePct;
- if( Role < ROLE_Authority )
- {
- log(self$" client damage type "$damageType$" by "$instigatedBy,'GODFUCKINGDAMNITMANDONTDOTHIS');
- return;
- }
- if( bEnableDamageLoggers )
- log(self$" with "$Health$" health initially took "$damage$" "$damagetype$" damage",'DISCORDUDAMAGELOGGER');
- bAlreadyDead = Health <= 0;
- bNoPhysics = class'EXUStaticFuncs'.Static.bHasPawnTag(self, 'NoDamagePhysics');
- if( !bNoPhysics )
- {
- if( Physics==PHYS_None )
- SetMovementPhysics();
- if( Physics==PHYS_Walking )
- Momentum.Z = FMax(Momentum.Z, 0.4 * VSize(Momentum));
- if( instigatedBy==self )
- Momentum *= 0.6;
- Momentum = Momentum/Mass;
- }
- //===================================================================
- // // // // Damage calculation stuff \\ \\ \\
- //===================================================================
- actualDamage = Level.Game.ReduceDamage(Damage, DamageType, self, instigatedBy) * HellDamageScale;
- //===================================================================
- if( bIsPlayer )
- {
- if( ReducedDamageType=='All' ) //God mode
- actualDamage = 0;
- else if( Inventory!=None ) //then check if carrying armor
- actualDamage = Inventory.ReduceDamage(actualDamage, DamageType, HitLocation);
- else
- actualDamage = Damage;
- }
- //===================================================================
- for( i=-1; i < DamageTypesTracker; i++ )
- {
- if( i==-1 )
- DamageNM = ReducedDamageType;
- else
- DamageNM = DamageTypes[i];
- if( DamageNM!='' && DamageNM!='None' )
- {
- if( i==-1 )
- DamagePct = 1.0 - ReducedDamagePct;
- else
- DamagePct = DamageScales[i];
- if( DamageNM=='All' || DamageNM==damageType )
- {
- ActualDamage = float(ActualDamage) * DamagePct;
- GenerateImpactEffect(DamagePct, HitLocation, InstigatedBy, damageType, ActualDamage);
- break; //found a valid damage modifier, break loop
- }
- }
- else if( i>=0 )
- {
- // found an empty slot, break loop (wont break if reduceddamagetype is '', will just ignore it, this preserves original functionality of damagetypes, using reduceddamagetype is optional but will break loop if successfully processed) // I like how he wrapped this comment in brackets along with the break command // I'm such an asshole
- break;
- }
- }
- //===================================================================
- // Handle stun damage
- //===================================================================
- if( damageType=='Stunned' && ActualDamage > 0 )
- {
- StunLength += (ActualDamage * 0.01);
- StunnedRotation = Rotation;
- PlayHit(actualDamage, HitLocation, damageType, Momentum);
- ActualDamage = 0;
- GoToState('StunnedState');
- //log(self$" stunned for "$StunLength$" seconds - ActualDamage is "$ActualDamage);
- }
- //===================================================================
- // Hell Gun damage stacking support. Sorta hacky but it works
- //===================================================================
- else if(
- damageType=='Hell'
- && instigatedBy!=None
- && instigatedBy.bIsPawn
- && instigatedBy.Weapon!=None
- && (instigatedBy.Weapon.MyDamageType=='Hell' && instigatedBy.Weapon.AltDamageType=='Hell')
- )
- {
- HellDamageScale += ActualDamage * 0.0001;
- //log(self$" HellDamageScale is now "$HellDamageScale);
- }
- //================================================
- // Check self-damage and friendly damage here
- //================================================
- if( SelfDamageScale!=1.0 && instigatedBy==Self )
- ActualDamage = float(ActualDamage) * SelfDamageScale;
- else if(
- FriendlyDamageScale!=1.0
- && EXUScriptedPawn(instigatedBy)!=None
- && EXUScriptedPawn(instigatedBy).default.TeamTag == Self.default.TeamTag
- )
- ActualDamage = float(ActualDamage) * FriendlyDamageScale;
- if( Level.Game.DamageMutator!=None )
- Level.Game.DamageMutator.MutatorTakeDamage( ActualDamage, Self, InstigatedBy, HitLocation, Momentum, DamageType );
- if( !bNoPhysics && Mass < 1000000 )
- AddVelocity( Momentum );
- //===================================================================
- // If the pawn takes negative damage (heals), ensure that the healing
- // cap is nonzero and that it isn't exceeded.
- // Negative cap = no health cap
- //===================================================================
- if( ActualDamage < 0 )
- {
- if( MaxHealingScale!=0 ) // do some healin
- {
- HealAmount = -ActualDamage;
- if( Health < StartingHealth * MaxHealingScale || MaxHealingScale < 0 )
- {
- Health += HealAmount;
- if( MaxHealingScale > 0 && Health > StartingHealth * MaxHealingScale )
- Health = StartingHealth * MaxHealingScale;
- // Increase score for pawns that can superheal, but don't decrease it when health decreases later on
- if( Health > StartingHealth && (MaxHealingScale < 0 || InitialPointValue * MaxHealingScale > PointValue) )
- PointValue += 5 * (Health / StartingHealth);
- }
- }
- else
- ActualDamage = 0; // MaxHealingScale=0, no healing
- }
- else
- Health -= actualDamage; // *** Subtract actual damage from health (or add it if negative) ***
- //===================================================================
- if( CarriedDecoration!=None )
- DropDecoration();
- if( HitLocation==vect(0,0,0) )
- HitLocation = Location;
- // *** Figure out if dead or not based on new health, then decide what to do ***
- if( Health > 0 )
- {
- if( instigatedBy!=None && instigatedBy!=Self )
- damageAttitudeTo(instigatedBy);
- if( ActualDamage > 0 && !bNoPhysics )
- PlayHit(ActualDamage, HitLocation, DamageType, Momentum);
- }
- else if( !bAlreadyDead )
- {
- NextState = '';
- PlayDeathHit(ActualDamage, HitLocation, DamageType, Momentum);
- ///FIXME - my god this shit is dumb, ill find a better solution later that still permits easy gibbing
- if( ActualDamage > Mass )
- Health = -1 * ActualDamage;
- if( InstigatedBy!=None && InstigatedBy!=Self )
- DamageAttitudeTo(InstigatedBy);
- Died(InstigatedBy, DamageType, HitLocation);
- }
- else
- {
- //Warn(self$" took regular damage "$damagetype$" from "$instigator$" while already dead"); // lol
- // SpawnGibbedCarcass();
- if( bIsPlayer )
- {
- HidePlayer();
- GotoState('Dying');
- }
- else
- Destroy();
- }
- MakeNoise(1.0);
- if( bEnableDamageLoggers )
- log(self$" now has "$Health$" health: took "$ActualDamage$" "$damagetype$" damage",'DISCORDUDAMAGELOGGER');
- }
- //===============================================================================================================
- // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- //
- // [6.2] GenerateImpactEffect() - creates flashes for healing/weakness/resistance/immunity damage
- //
- // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- //===============================================================================================================
- simulated function GenerateImpactEffect( float F, vector HitLocation, pawn InstigatedBy, name damageType, int ActualDamage )
- {
- local bool bFlashReady;
- local float s;
- //log(self$" GenerateImpactEffect() called on "$getenum(enum'enetmode',Level.netmode)$" and Role="$ROLE,'DISCORDULOGGER');
- if( bDisableDamageEffects || damageType=='Stunned' )
- return;
- bFlashReady = OldFlash==None || OldFlash.bDeleteMe;
- if( bFlashReady )
- OldFlash = None;
- if( InstigatedBy==None )
- return;
- s = randrange(0.85, 1.1);
- if( F > 1.0 )
- {
- if( bUseDamageFlashes && bFlashReady )
- OldFlash = Spawn(Class'FlashWeakness', self);
- PlayOwnedSound(EXUHitWeakness, SLOT_None, 8,,, s);
- PlayOwnedSound(EXUHitWeakness, SLOT_Interact, 8,,, s);
- if( Level.bDropDetail && FRand()<0.5 )
- return;
- else
- Spawn(Class'ExtraDamageEffect', self,, HitLocation + (5 * vect(1,1,1) * VRand()), rotator(HitLocation - Location));
- }
- else if( F < 0 )
- {
- if( bUseDamageFlashes && bFlashReady )
- OldFlash = Spawn(Class'FlashHealing', self);
- PlayOwnedSound(EXUHitHealing, SLOT_None, 8,,, s);
- PlayOwnedSound(EXUHitHealing, SLOT_Interact, 8,,, s);
- if( Level.bDropDetail && FRand()<0.5 )
- return;
- else
- Spawn(Class'HealinEffect', self,, HitLocation + (5 * vect(1,1,1) * VRand()), rotator(HitLocation - Location));
- }
- else if( F == 0 )
- {
- if( InstigatedBy==self ) // Don't generate invincibility effects for point-blank self-damage, only for damage from other pawns
- return;
- if( bUseDamageFlashes && bFlashReady )
- OldFlash = Spawn(Class'FlashImmune', self);
- PlayOwnedSound(EXUHitImmunity, SLOT_None, 8,,, s);
- PlayOwnedSound(EXUHitImmunity, SLOT_Interact, 8,,, s);
- if( Level.bDropDetail && FRand()<0.5 )
- return;
- else
- Spawn(Class'InvincibilityEffect', self,, HitLocation + (5 * vect(1,1,1) * VRand()), rotator(HitLocation - Location));
- }
- else
- {
- if( bUseDamageFlashes && bFlashReady )
- OldFlash = Spawn(Class'FlashResist', self);
- PlayOwnedSound(EXUHitResistance, SLOT_None, 8,,, s);
- PlayOwnedSound(EXUHitResistance, SLOT_Interact, 8,,, s);
- if( Level.bDropDetail && FRand()<0.5 )
- return;
- else
- Spawn(Class'ResistanceEffect', self,, HitLocation + (5 * vect(1,1,1) * VRand()), rotator(HitLocation - Location));
- }
- }
- //===============================================================================================================
- // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- //
- // [6.3] PlayHit() - HEMOSPECTRUM CODE: Modified hit code to allow for different blood types and all sorts of other stuff
- //
- // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- //===============================================================================================================
- function PlayHit( float Damage, vector HitLocation, name damageType, vector Momentum )
- {
- local Actor EHF;
- local BloodEXU b;
- local Bubble1 bub;
- local bool bOptionalTakeHit;
- local vector BloodOffset;
- local EXUKetchupSpurt Blood;
- local rotator durr, BloodDirection;
- BloodDirection = rotator(HitLocation-location);
- if( Damage > 1 ) //spawn some blood
- {
- if( damageType=='Drowned')
- {
- bub = spawn(class'Bubble1',,, Location + 0.7 * CollisionRadius * vector(ViewRotation) + 0.3 * EyeHeight * vect(0,0,1));
- if( bub!=None )
- bub.DrawScale = FRand() * 0.06 + 0.04;
- }
- else if( damageType != 'Corroded' )
- {
- BloodOffset = 0.2 * CollisionRadius * Normal(HitLocation - Location);
- BloodOffset.Z *= 0.5;
- if( Level.bHighDetailMode && !Level.bDropDetail && EXUHitEffect!=None && EXUHitEffectScale>0 )
- {
- EHF = Spawn(EXUHitEffect, self,, HitLocation, BloodDirection);
- if( EHF!=None )
- EHF.DrawScale *= ( EXUHitEffectScale * randrange(0.9, 1.1) );
- }
- if( Hemospectrum!=BLOOD_None )
- {
- b = spawn(class'BloodBurstEXU', self,, HitLocation + (vect(1,1,1)*randrange(0,20)) );
- if( b!=None )
- {
- b.DrawScale = randrange(0.1, 0.15);
- b.HSBloodNumber = Hemospectrum;
- b.Initialize();
- }
- // "Static" blood
- Blood = spawn(class'EXUKetchupSpurt', self,, HitLocation + BloodOffset, BloodDirection);
- if( Blood!=None )
- {
- durr = rotator( class'exustaticfuncs'.static.randomspreadvector(0,20)>>BloodDirection );
- Blood.HSSpurtNumber = Hemospectrum;
- Blood.BaseScale = fclamp(CollisionRadius * 0.025, 1, 3); // Regular hit = small
- Blood.SetPhysics(PHYS_Projectile);
- Blood.settimer(0.2, False);
- Blood.Velocity = vector(durr) * randrange(30,60);
- Blood.Initialize();
- }
- if( Level.bHighDetailMode && !Level.bDropDetail )
- {
- // Directional blood
- Blood = spawn(class'EXUKetchupSpurt', self,, HitLocation + BloodOffset, BloodDirection);
- if( Blood!=None )
- {
- durr = rotator( class'exustaticfuncs'.static.randomspreadvector(0,25) >> BloodDirection );
- Blood.HSSpurtNumber = Hemospectrum;
- Blood.BaseScale = fclamp(CollisionRadius * 0.025, 1, 3); // Regular hit = small
- Blood.SetPhysics(PHYS_Projectile);
- Blood.settimer(0.2, False);
- Blood.Velocity = vector(durr) * randrange(100, 200);
- Blood.Initialize();
- }
- }
- }
- }
- }
- if( Weapon!=None && Weapon.bPointing && !bIsPlayer )
- {
- bFire = 0;
- bAltFire = 0;
- }
- bOptionalTakeHit = bIsWuss || ( (Level.TimeSeconds - LastPainTime > 0.3 + 0.25 * skill)
- && (Damage * FRand() > 0.08 * Health) && (Skill < 3)
- && (GetAnimGroup(AnimSequence) != 'MovingAttack')
- && (GetAnimGroup(AnimSequence) != 'Attack') );
- if( (!bIsPlayer || Weapon==None || !Weapon.bPointing)
- && (bOptionalTakeHit || (Momentum.Z > 140) || (bFirstShot && (Damage > 0.015 * (skill + 6) * Health))
- || (Damage * FRand() > (0.17 + 0.04 * skill) * Health)) )
- {
- PlayTakeHitSound(Damage, damageType, 3);
- PlayHitAnim(HitLocation, Damage);
- }
- else if( NextState=='TakeHit' )
- {
- PlayTakeHitSound(Damage, damageType, 2);
- NextState = '';
- }
- }
- //======================================================================================================
- // [6.4] PlayDeathHit() -
- //======================================================================================================
- function PlayDeathHit( float Damage, vector HitLocation, name damageType, vector Momentum )
- {
- local Actor EHF;
- local Bubble1 bub;
- local BloodEXU b;
- local EXUKetchupSpurt Blood;
- if( Region.Zone.bDestructive && Region.Zone.ExitActor!=None )
- Spawn(Region.Zone.ExitActor);
- if( HeadRegion.Zone.bWaterZone )
- {
- bub = spawn(class'Bubble1',,, Location + 0.3 * CollisionRadius * vector(Rotation) + 0.8 * EyeHeight * vect(0,0,1));
- if( bub!=None )
- bub.DrawScale = FRand() * 0.08 + 0.03;
- bub = spawn(class'Bubble1',,, Location + 0.2 * CollisionRadius * VRand() + 0.7 * EyeHeight * vect(0,0,1));
- if( bub!=None )
- bub.DrawScale = FRand() * 0.08 + 0.03;
- bub = spawn(class'Bubble1',,, Location + 0.3 * CollisionRadius * VRand() + 0.6 * EyeHeight * vect(0,0,1));
- if( bub!=None )
- bub.DrawScale = FRand() * 0.08 + 0.03;
- }
- if( damageType!='Burned' && damageType!='Corroded' && damageType!='Drowned' && damageType!='Fell' )
- {
- if( Level.bHighDetailMode && !Level.bDropDetail && EXUHitEffect!=None && EXUHitEffectScale>0 )
- {
- EHF = spawn(EXUHitEffect, self,, HitLocation);
- if( EHF!=None )
- EHF.DrawScale *= ( EXUHitEffectScale * randrange(0.9, 1.1) );
- }
- if( Hemospectrum!=BLOOD_None )
- {
- b = spawn(class'BloodBurstEXU', self,, HitLocation);
- if( b!=None )
- {
- b.HSBloodNumber = Hemospectrum;
- b.Initialize();
- }
- if( Level.bHighDetailMode && !Level.bDropDetail )
- {
- Blood = spawn(class'EXUKetchupSpurt', self,, HitLocation);
- if( Blood!=None )
- {
- Blood.HSSpurtNumber = Hemospectrum;
- Blood.BaseScale = fclamp(CollisionRadius * 0.0365, 1, 4); // DEATH = BIG (sorta)
- Blood.Initialize();
- }
- }
- }
- }
- }
- //===============================================================================================================
- // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- //
- // [6.5] Died() - Hook for pawns to use to do extra stuff when killed, stuff not handled in the carcass or in Destroy()
- //
- // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- //===============================================================================================================
- function Died( pawn Killer, name damageType, vector HitLocation )
- {
- ExtraDeathStuff();
- ClientDeathStuff();
- Super.Died(Killer, damageType, HitLocation);
- }
- //======================================================================================================
- // [6.6] SpawnCarcass() -
- //======================================================================================================
- function Carcass SpawnCarcass()
- {
- local Carcass Carc;
- Carc = Spawn(CarcassType, self);
- if( Carc!=None )
- Carc.Initfor(self);
- //else
- // warn(self$" Failed to spawn Carcass "$CarcassType$" at Location "$Location);
- return Carc;
- }
- //======================================================================================================
- // [6.7] SpawnGibbedCarcass() - Carcass Management System v0.8.243.f.3453.5.546g
- //======================================================================================================
- function SpawnGibbedCarcass()
- {
- local carcass carc;
- local EXUKetchupSpurt Blood;
- if( GibMode==GIB_Never )
- return;
- carc = Spawn(CarcassType, self); // set carcass's Owner to Self for use by EXUCreatureCarcass and the like
- if( carc!=None )
- {
- carc.Initfor(self);
- carc.ChunkUp(-1 * Health);
- }
- if( Level.bHighDetailMode && Hemospectrum!=BLOOD_None && !Level.bDropDetail ) // yeah this should be done in EXUCreatureCarcass but you know what, fuck you, fuck you
- {
- Blood = spawn(class'EXUKetchupSpurt', self);
- if( Blood!=None )
- {
- Blood.HSSpurtNumber = Hemospectrum;
- Blood.BaseScale = fmax(CollisionRadius*0.09, 1); // GIBDEATH = BIG_GIB
- Blood.Initialize();
- }
- }
- }
- //======================================================================================================
- // [6.8] Gibbed() -
- //======================================================================================================
- function bool Gibbed( name damageType )
- {
- if( GibMode==GIB_Never )
- return False;
- else if( GibMode==GIB_Always || damageType=='LRPC' )
- return True;
- else
- return Super.Gibbed(damageType);
- }
- //======================================================================================================
- // [6.9] ExtraDeathStuff()
- //======================================================================================================
- // NOTE: THIS FUNCTION IS ALWAYS CALLED SERVER-SIDE. If you need to spawn effects clientside, see below:
- //======================================================================================================
- function ExtraDeathStuff(); // Implement in subclasses
- //======================================================================================================
- // [6.10] ClientDeathStuff() -
- //======================================================================================================
- // This function is ALSO always called server-side, but is meant to be used with a simulation hook that will work clientside via a proxy class.
- // Implement ClientDeathStuff() in the pawn, and have it spawn a proxy actor set up to generate anything you need clientside.
- // See Effects >> EXUGenericEffects >> EXUClientEffectProxy for more info.
- // Thanks to PCube, []KAOS[]Casey, and Core for help with this stuff!
- //======================================================================================================
- function ClientDeathStuff(); // Subclasses yo
- //=====================================================================================================================
- // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
- //=====================================================================================================================
- //
- // SECTION 7: EXU ADDITIONS
- // [7.1] simulated state StunnedState
- // [7.2] function StunEffects()
- // [7.3] state SpawnWhenTriggered
- //
- //=====================================================================================================================
- // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
- //=====================================================================================================================
- //===============================================================================================================
- // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- //
- // [7.1] StunnedState - Take a quick break and spaz out for a bit
- //
- // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- //===============================================================================================================
- simulated state StunnedState
- {
- ignores SeePlayer, HearNoise, Bump;
- //======================================================================
- function Timer()
- {
- StunEffects();
- SetTimer(0.1, False);
- }
- //======================================================================
- simulated function Tick(float dt)
- {
- local rotator StunRot;
- if( StunLength > 0 )
- StunLength -= dt;
- if( StunShock!=None )
- {
- StunShock.ScaleGlow = StunLength / 2;
- StunShock.SoundVolume = fclamp( (StunLength / 2) * 255, 0, 255 );
- }
- StunRot = StunnedRotation;
- StunRot.Yaw += randrange(-2000, 2000);
- SetRotation( StunRot );
- }
- //======================================================================
- simulated function BeginState()
- {
- if( DrawType==DT_Mesh && StunShock==None )
- {
- if( Level.Netmode==NM_Standalone )
- {
- StunShock = Spawn(Class'StunOverlay', self);
- if( StunShock!=None )
- {
- StunShock.Mesh = Mesh;
- StunShock.DrawScale = DrawScale;
- StunShock.Fatness = fclamp( Fatness + 2, 0, 255 );
- }
- }
- else
- {
- StunShock = Spawn(Class'StunnerProxy', self);
- if( ROLE==ROLE_Authority && StunShock!=None )
- StunShock.RemoteRole = ROLE_None;
- }
- }
- }
- //======================================================================
- simulated function EndState()
- {
- local StunOverlay E;
- if( Level.Netmode==NM_Standalone )
- {
- if( StunShock!=None )
- StunShock.Destroy();
- }
- else
- {
- foreach ChildActors( class'StunOverlay', E )
- {
- if( !E.bDeleteMe )
- E.Destroy();
- }
- }
- }
- //------------------------------------
- Begin:
- Timer();
- SetTimer(0.1, False);
- Acceleration = vect(0,0,0);
- Sleep(StunLength);
- StunLength = 0;
- GoToState('Attacking');
- }
- //======================================================================================================
- // [7.2] StunEffects - Global for ease of overriding / enhancing
- //======================================================================================================
- function StunEffects()
- {
- local float Choice;
- Choice = FRand();
- if( Choice < 0.75 )
- PlayGutHit(0.08);
- else if( Choice < 0.5 )
- PlayHeadHit(0.08);
- else if( Choice < 0.25 )
- PlayLeftHit(0.08);
- else
- PlayRightHit(0.08);
- if( FRand() < 0.1 )
- PlayTakeHitSound(0, 'None', 2);
- }
- //===============================================================================================================
- // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- //
- // [7.3] SpawnWhenTriggered - Enemy isn't interactable until triggered. Can spawn effects when appearing
- //
- // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- //===============================================================================================================
- state SpawnWhenTriggered
- {
- ignores SeePlayer, HearNoise, Bump, TakeDamage, Killed;
- //=====================================================================================
- function Trigger( Actor Other, Pawn EventInstigator )
- {
- if( EventInstigator==None || EventInstigator==Self )
- return;
- Disable('Trigger');
- SWTEnemy = EventInstigator;
- bStasis = False; // Force bStasis to False so the actor will appear and generate its spawn effect whether it's visible (i.e. relevant) or not
- GoToState('SpawnWhenTriggered', 'SpawnStuff');
- }
- //=====================================================================================
- function DoinThangs()
- {
- local Pawn currentEnemy;
- local Actor TSE;
- bHidden = Default.bHidden;
- bProjTarget = Default.bProjTarget;
- bQuiet = Default.bQuiet;
- bIgnoreFriends = Default.bIgnoreFriends;
- SoundVolume = Default.SoundVolume;
- LightType = Default.LightType;
- SetCollision(True, True, True);
- AttitudeToPlayer = OriginalAttitudeToPlayer;
- SetPhysics(OriginalPhysics);
- BagOfJunk = True; // Gotta be the most hilarious variable name yet
- if( TriggeredSpawnEffect!=None )
- {
- TSE = Spawn(TriggeredSpawnEffect, self);
- if( TSE!=None )
- {
- if( TriggeredSpawnEffectScale < 0 )
- TSE.DrawScale *= CollisionHeight / 25;
- else
- TSE.DrawScale *= TriggeredSpawnEffectScale;
- }
- }
- bStasis = Default.bStasis; // Restore original bStasis condition
- Enable('Trigger');
- if( SWTEnemy!=None && bHateWhenTriggered ) ///FIXME: we need a check to be sure the player is *visible* if Relentless is False
- { // Otherwise, all SpawnWhenTriggered enemies will immediately seek the player
- if( SWTEnemy.bIsPlayer )
- AttitudeToPlayer = ATTITUDE_Hate;
- else
- Hated = SWTEnemy;
- currentEnemy = Enemy;
- SetEnemy(SWTEnemy);
- if( SWTEnemy!=currentEnemy )
- {
- PlayAcquisitionSound();
- if( AlternateStartupState!='' )
- {
- Orders = AlternateStartupState;
- GoToState(Orders);
- }
- else if( AlternateStartupState=='' )
- GoToState('Attacking');
- }
- SetFall();
- }
- else
- {
- if( AlternateStartupState!='' )
- {
- Orders = AlternateStartupState;
- GoToState(Orders);
- }
- else
- GoToState('Waiting');
- mtimer2(); // Enemy scan radar (using AutoHateRadius)
- }
- }
- //=====================================================================================
- function SetFall()
- {
- if( Enemy!=None )
- {
- NextState = 'Attacking'; //default
- NextLabel = 'Begin';
- NextAnim = 'Fighter';
- GotoState('FallingState', 'FastLanded');
- }
- }
- //=====================================================================================
- function BeginState()
- {
- local Actor a;
- OriginalPhysics = Physics;
- OriginalAttitudeToPlayer = AttitudeToPlayer;
- bHidden = True;
- bProjTarget = False;
- bQuiet = True;
- bIgnoreFriends = True;
- SoundVolume = 0;
- LightType = LT_None;
- AttitudeToPlayer = ATTITUDE_Ignore;
- SetPhysics(PHYS_None);
- SetCollision(False, False, False);
- }
- //------------------------------------
- SpawnStuff:
- if( TrigSpawnDelayMax > 0 )
- Sleep(randrange(TrigSpawnDelayMin, TrigSpawnDelayMax));
- DoinThangs();
- }
- defaultproperties
- {
- AutoHateRadius=600
- HellDamageScale=1.000000
- AttitudeToOwnClass=ATTITUDE_Friendly
- AttitudeToSubClass=ATTITUDE_Friendly
- DefaultAttitude=ATTITUDE_Friendly
- TriggeredSpawnEffectScale=-1.000000
- TrigSpawnDelayMax=0.000000
- TrigSpawnDelayMin=-1.000000
- DamageScales(0)=1.000000
- DamageScales(1)=1.000000
- DamageScales(2)=1.000000
- DamageScales(3)=1.000000
- DamageScales(4)=1.000000
- DamageScales(5)=1.000000
- DamageScales(6)=1.000000
- DamageScales(7)=1.000000
- DamageScales(8)=1.000000
- DamageScales(9)=1.000000
- MaxHealingScale=1.000000
- MeleeDamageType=hacked
- EXUHitEffectScale=1.000000
- EXUHitHealing=Sound'AmbModern.OneShot.teleprt3'
- EXUHitImmunity=Sound'EXU-Sounds.GunSounds.Invulnerability'
- EXUHitResistance=Sound'EXU-Sounds.PawnSounds.UT3Spark1'
- EXUHitWeakness=Sound'AmbAncient.OneShot.explo7'
- MuzzleEffectScale=1.0
- ProjectilesPerShot=1
- ShotsPerBurst=1
- TimeBetweenShots=0.05
- ShootVolume=2.0
- ShootMagnitude=1
- PawnTags(0)=Organic
- PawnTags(1)=Living
- DeathLightingMode=DLM_GibsLit
- bEnableDamageLoggers=False
- NameArticle="a "
- MaxWanderDist=1500
- PointValue=100
- SelfDamageScale=1.0
- FriendlyDamageScale=1.0
- PawnDescription="An EXU2 Monster"
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement