Advertisement
Guest User

Woah man

a guest
Feb 2nd, 2014
234
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 137.62 KB | None | 0 0
  1. //======================================================================================================================
  2. // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
  3. //======================================================================================================================
  4. //
  5. // EXUScriptedPawn - The most advanced ScriptedPawn class probably ever. OK by "advanced" I mean "cluttered"
  6. //
  7. // HINT FOR THE SLOW: ctrl+f to jump to a section or function by using its number
  8. //
  9. //
  10. // note to bawss-self on bawssbars:
  11. // use a more passive system, replicationinfo + hud, no need to replicate bosstag anymore
  12. // 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
  13. // if we decide this is pointless later ill change it, will be adding legacy support anyway just in case
  14. //
  15. //======================================================================================================================
  16. // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
  17. //======================================================================================================================
  18.  
  19.  
  20. class EXUScriptedPawn extends ScriptedPawn
  21. abstract;
  22.  
  23.  
  24. ///////////////////////////////////////////////////////////////
  25. /// ///
  26. /// DELETEME: DEPRECATED VARIABLES - will be removed soon ///
  27. /// ///
  28. ///////////////////////////////////////////////////////////////
  29. var(DEPRECATED) float TriggeredSpawnDelay;
  30. var(DEPRECATED) float TriggeredSpDelayMax;
  31.  
  32.  
  33.  
  34.  
  35. //======================================================================================================================
  36. // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
  37. //======================================================================================================================
  38. //
  39. // [// // //] BIGASS TABLE OF CONTENTS, HOLY FUCK [\\ \\ \\]
  40. //
  41. //======================================================================================================================
  42. // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
  43. //======================================================================================================================
  44. //
  45. // VARIABLES
  46. // [V.1] Filters
  47. // [V.2] EXUAI
  48. // [V.3] EXUDebug
  49. // [V.4] Orders
  50. // [V.5] EXUTakeDamage
  51. // [V.6] General EXUScriptedPawn variables
  52. // [V.7] Sounds
  53. // [V.8] Internal private variables
  54. // [V.9] Replication block
  55. //
  56. //======================================================================================================================
  57. //
  58. // SECTION 1: BASIC TECHNICAL BACKGROUND STUFF
  59. //
  60. // [1.1] simulated function MTimer( float dt )
  61. // [1.2] simulated function SetMTimer( float Delay, bool bLoop, optional byte ID )
  62. // [1.3] simulated function Tick(float dt)
  63. // [1.4] simulated function PreBeginPlay()
  64. // [1.5] simulated function PostBeginPlay()
  65. // [1.6] simulated function Destroyed()
  66. // [1.7] simulated function dlog(coerce string logstring, optional name logtag)
  67. // [1.8] simulated function d1og(coerce string logstring, optional name logtag)
  68. //
  69. //======================================================================================================================
  70. //
  71. // SECTION 2: AI CONTROLS
  72. //
  73. // [2.1] simulated function MTimer2()
  74. // [2.2] function eAttitude AttitudeToCreature(Pawn Other)
  75. // [2.3] function WhatToDoNext(name LikelyState, name LikelyLabel)
  76. // [2.4] function bool SetEnemy( Pawn NewEnemy )
  77. // [2.5] function eAttitude AttitudeTo(Pawn Other)
  78. // [2.6] function float RelativeStrength(Pawn Other)
  79. // [2.7] function StartRoaming()
  80. // [2.8] function ForceAttackPlayer()
  81. // [2.9] function Actor FindCore()
  82. // [2.10] function HearNoise(float Loudness, Actor NoiseMaker)
  83. // [2.11] function SeePlayer(Actor SeenPlayer)
  84. // [2.12] state Attacking
  85. // [2.13] state TacticalMove
  86. // [2.14] state Wandering
  87. //
  88. //======================================================================================================================
  89. //
  90. // SECTION 3: COMBAT AND DAMAGE STUFF
  91. //
  92. // [3.1] function EXUFireProjectile( vector StartOffset, float Accuracy, optional class<Projectile> ProjectileOverride, optional vector MuzzleOffset )
  93. // [3.2] function EXUSpawnProjectile( vector ProjStart, float Accuracy, optional class<Projectile> ProjectileOverride )
  94. // [3.3] function EXUShootNoise(sound Sound, optional float Volume, optional byte Magnitude, optional int SoundInterval, optional float Pitch, optional float Radius )
  95. // [3.4] simulated function GenerateMuzzleEffect(byte Mode, vector SpawnLocation)
  96. // [3.5] function bool MeleeDamageTarget( int HitDamage, vector PushDir )
  97. // [3.6] event PainTimer()
  98. //
  99. //======================================================================================================================
  100. //
  101. // SECTION 4: TOUCH FUNCTIONS
  102. //
  103. // [4.1] function bool bShoved( ScriptedPawn Shoved )
  104. // [4.2] singular event BaseChange()
  105. // [4.3] function Bump(actor Other)
  106. // [4.4] event EncroachedBy( actor Other )
  107. // [4.5] simulated function Touch(actor Other)
  108. // [4.6] simulated function XlocBlockerEffect( vector HitLocation, rotator LaunchDirection, bool bDestroyedDisc )
  109. // [4.7] simulated function XlocBlockSound( bool bDestroyedDisc )
  110. //
  111. //======================================================================================================================
  112. //
  113. // SECTION 5: EPIC CODE TECHNICAL IMPROVEMENT / ACCESSED NONE PROTECTION
  114. //
  115. // [5.1] simulated function bool SafePlayAnim( name Sequence, optional float Rate, optional float TweenTime )
  116. // [5.2] simulated function bool SafeTweenAnim( name Sequence, float Time )
  117. // [5.3] simulated function bool SafeLoopAnim( name Sequence, optional float Rate, optional float TweenTime, optional float MinRate )
  118. // [5.4] simulated function bool AdjustHitLocation(out vector HitLocation, vector TraceDir)
  119. // [5.5] function bool ChooseTeamAttackFor(ScriptedPawn TeamMember)
  120. // [5.6] function Trigger( actor Other, pawn EventInstigator )
  121. // [5.7] state Charging
  122. // [5.8] state MeleeAttack
  123. // [5.9] state Retreating
  124. // [5.10] state Guarding
  125. // [5.11] state Patroling
  126. // [5.12] state Waiting
  127. // [5.13] state Roaming
  128. // [5.14] state Greeting
  129. // [5.15] state TriggerAlarm
  130. // [5.16] state AlarmPaused
  131. // [5.17] state VictoryDance
  132. // [5.18] state StakeOut
  133. //
  134. //======================================================================================================================
  135. //
  136. // SECTION 6: NEW DAMAGE EFFECTS AND CARCASS STUFF
  137. //
  138. // [6.1] function TakeDamage( int Damage, Pawn instigatedBy, Vector HitLocation, Vector momentum, name damageType )
  139. // [6.2] simulated function GenerateImpactEffect(float F, vector HitLocation, pawn InstigatedBy, name damageType, int ActualDamage)
  140. // [6.3] function PlayHit(float Damage, vector HitLocation, name damageType, vector Momentum)
  141. // [6.4] function PlayDeathHit( float Damage, vector HitLocation, name damageType, vector Momentum )
  142. // [6.5] function Died( pawn Killer, name damageType, vector HitLocation )
  143. // [6.6] function Carcass SpawnCarcass()
  144. // [6.7] function SpawnGibbedCarcass()
  145. // [6.8] function bool Gibbed( name damageType )
  146. // [6.9] function ExtraDeathStuff()
  147. // [6.10] function ClientDeathStuff()
  148. //
  149. //=====================================================================================================================
  150. //
  151. // SECTION 7: EXU ADDITIONS
  152. // [7.1] simulated state StunnedState
  153. // [7.2] function StunEffects()
  154. // [7.3] state SpawnWhenTriggered
  155. //
  156. //=====================================================================================================================
  157. // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
  158. //=====================================================================================================================
  159.  
  160.  
  161. //-------------------------------------------------------------------------------------------
  162. // [V.1] Filters - Custom EXU filters to be implemented eventually, maybe, possibly (probably not)
  163. //-------------------------------------------------------------------------------------------
  164. // these vars are dual-purpose, during prebeginplay they act as filters, but midgame they can also act as modifiers
  165. //var(Filters) bool bFuckerMode;
  166. //var(Filters) bool bExtremeTreesMode;
  167. //var(Filters) bool bMeteorMode;
  168. //var(Filters) bool bHorrorMode;
  169. //var(Filters) bool bClownMode;
  170. //var bool bWaffleMode;
  171. //var bool bBawssMode;
  172.  
  173.  
  174. //-------------------------------------------------------------------------------------------
  175. // [V.2] EXUAI - Fancy AI stuff
  176. //-------------------------------------------------------------------------------------------
  177. // Coregame stuff // oh well, waff didnt even get to see everything in the wafftroll, sucks to be you bro, removed! // >:E
  178. var(EXUAI) byte CorePriority; // 0 = always attack enemies over core; 255 = attack core and ignore enemies, else randomize choice between them
  179. var(EXUAI) bool Relentless; // Will ALWAYS chase the player regardless of LOS. Setting orders to "Relentless" will make this True as well.
  180. // Be careful; this can lag the game to shit on large maps if the pawn can't reach the player!
  181.  
  182. var(EXUAI) bool bMovingMelee; // Pawns with this (or have tag MovingMelee and Skill>=2) will have more effective melee attacks
  183. var(EXUAI) eAttitude AttitudeToOwnClass;
  184. var(EXUAI) eAttitude AttitudeToSubClass;
  185. var(EXUAI) eAttitude DefaultAttitude;
  186. var(EXUAI) name TeamHateTag; // Hate all pawns with this team tag no matter what
  187. var(EXUAI) name PawnTags[32]; // Use to define specific traits. NOTE: Not *inherently* useful; other classes must read tags
  188. // and process them via script. Used to group similar pawns from dissimilar parent classes.
  189. var(EXUAI) float WeaveFrequency; // How often a pawn can weave while taking damage and charging the player
  190. 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!
  191. var(EXUAI) float MaxWanderDist; // How far a pawn can go when it starts wandering (ONLY APPLIES TO FLYING PAWNS)
  192.  
  193. ///FIXME: implement these things before Fuckercleave Gorge, jesus christ
  194. //var(EXUAI) float RelentlessDistance; // If distance to enemy > RelentlessDistance, stop being an asshat
  195. //var(EXUAI) float RelentlessTimeout;
  196. //var bool bIsCurrentlyRelentless; // Is currently on an unrelenting bloodlust rage-high
  197. //var int RelentlessTime; // How many seconds have passed while being relentless (per target)
  198.  
  199.  
  200. //-------------------------------------------------------------------------------------------
  201. // [V.3] EXUDebug - Debugging facilities
  202. //-------------------------------------------------------------------------------------------
  203. var(EXUDebug) bool bUseDamageFlashes; // Pawns flash when taking hits if taking greater/less than 100% of the original damage amount
  204. // Red: >100% damage, Yellow: >0% and <100%, Blue: 0%, Green: <0% (Negative damage = heals)
  205. var(EXUDebug) bool bEnableDamageLoggers; // Turns on the damage logger so you can see damage pawns actually take vs. amount dealt
  206. var(EXUDebug) bool bEnableStateLogger; // Enable this to see what state the pawn currently is in
  207.  
  208.  
  209. //-------------------------------------------------------------------------------------------
  210. // [V.4] Orders - SpawnWhenTriggered variables
  211. //-------------------------------------------------------------------------------------------
  212. var(Orders) class<Effects> TriggeredSpawnEffect; // Effect to be spawned when pawn is triggered if Orders=SpawnWhenTriggered.
  213. var(Orders) float TriggeredSpawnEffectScale; // Size of the effect to be spawned if not default (1.0 = normal size; <0 = autoscale)
  214. var(Orders) float TrigSpawnDelayMax; // Spawn delay after being triggered
  215. var(Orders) float TrigSpawnDelayMin; // <=0 = use Max
  216. var(Orders) name AlternateStartupState; // If creature is to be spawned via trigger, switch to this state once spawned
  217.  
  218.  
  219. //-------------------------------------------------------------------------------------------
  220. // [V.5] EXUTakeDamage - Hit effects, damage types, etc
  221. //-------------------------------------------------------------------------------------------
  222. var(EXUTakeDamage) bool bDisableDamageEffects; // Prevents resistance/immunity/weakness/healing effects & sound without disabling functionality
  223. var(EXUTakeDamage) name DamageTypes[10]; // 10 different scaled damage types should be PLENTY, fuck you if you think otherwise
  224. var(EXUTakeDamage) float DamageScales[10]; // 0 = immune, 1 = normal damage, >1 = INCREASED damage (weakness), <1 = resistant, <0 = HEALING
  225. // Also, arrange your damage types from most common to least common since there is a for
  226. // loop that runs until it finds the matching damage type in the list
  227. var(EXUTakeDamage) float MaxHealingScale; // How much more health than default a pawn can gain from damage types that heal. Used as a
  228. // scale value, where 1.0 = default health is the cap, 0.0 = no healing at all,
  229. // >1.0 = more than the default, <0.0 = uncapped healing
  230. var(EXUTakeDamage) float SelfDamageScale; // Should be self-explanatory. 1.0 = no change to damage
  231. var(EXUTakeDamage) float FriendlyDamageScale; // Determine friendlies by default.TeamTag, else by same class
  232.  
  233. var(EXUTakeDamage) class<Effects> EXUHitEffect; // Allows you to specify custom blood spurts and shit if you want
  234. var(EXUTakeDamage) float EXUHitEffectScale; // Specify the size multiplier of the impact effect. 1.0 = original size of the actor (default)
  235. var(EXUTakeDamage) bool bUseOwnSkinForGibs; // Whether or not the creature's gib skin should use the creature's Skin setting
  236. var(EXUTakeDamage) bool bMetallicGibSounds; // Whether or not the guts should use robo clunky noises
  237.  
  238. var(EXUTakeDamage) enum eGibType // Easy controls for gibbing. GIB_Normal is default (gibs based on damage taken).
  239. {
  240. GIB_Normal,
  241. GIB_Always,
  242. GIB_Never
  243. } GibMode;
  244.  
  245. var(EXUTakeDamage) enum EXUBloodType // Not in the clinical sense!
  246. {
  247. 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.
  248. BLOOD_Green, //1
  249. BLOOD_Blue, //2
  250. BLOOD_Brown, //3 // Shit blood? What the fuck
  251. BLOOD_White, //4
  252. BLOOD_MYBLOODvvvISvvvvvvBLACK, // UT3 taunts = hilarious
  253. BLOOD_None //6 // For vehicles and shit if you don't want, say, an oily black discharge (that sounds really nasty)
  254. } Hemospectrum;
  255.  
  256. var(EXUTakeDamage) enum eCorpseLighting // Determine whether corpse, corpse & gibs, or neither should inherit lighting after death
  257. { // NOTE: only sends variables if the pawn's defaults have them set up, i.e. not LT_None
  258. DLM_LightsOut,
  259. DLM_CorpseLit,
  260. DLM_GibsLit
  261. } DeathLightingMode;
  262.  
  263.  
  264. //-------------------------------------------------------------------------------------------
  265. // [V.6] Generic EXUScriptedPawn variables for combat or misc purposes
  266. //-------------------------------------------------------------------------------------------
  267. var() int RangedAccuracy; // Projectile accuracy from 0 to 65536. Lower numbers = more accurate
  268. var() int ProjectilesPerShot; // Number of projectiles to fire at the same time in a single shot. Default = 1
  269. var() int ShotsPerBurst; // Number of shots to take with a delay between each shot. Default = 1
  270. var() int PointValue; // How many points do you get for killing this thing?
  271. var() float TimeBetweenShots; // How long to wait between shots when firing a burst. Default = 0.05 seconds
  272. var() name MeleeDamageType; // DamageType to use for melee attacks (default is 'hacked')
  273. var() int XlocBlockMag; // The velocity to use for flinging away xloc discs
  274. // If 0, pawn is telefraggable as usual; if <0, the pawn destroys the disc
  275.  
  276. var() name BossTag; // Used by the BawssTrigger
  277. var() class<EXUOverlayProxy> OverlayProxyClass; // Use to specify a proxy actor for spawning attached actors, such as overlay effects
  278. var() class<Effects> MuzzleEffect; // Optional effect for spawning muzzle flashes from pawns
  279. var() float MuzzleEffectScale; // Scale value applied to MuzzleEffect (1.0 = same size)
  280.  
  281. var() localized string PawnDescription;
  282.  
  283.  
  284. //-------------------------------------------------------------------------------------------
  285. // [V.7] Sounds - Expanded sound variables
  286. //-------------------------------------------------------------------------------------------
  287. var(Sounds) sound EXUDeathSound; // Implement in subclasses for additional death sounds
  288. var(Sounds) sound EXUShootSound; // Pawn's fire sound for custom projectiles and stuff
  289. var(Sounds) sound EXUHitHealing; // Sound to play if damage heals pawn
  290. var(Sounds) sound EXUHitImmunity; // Sound to play if damage has no effect on pawn at all
  291. var(Sounds) sound EXUHitResistance; // Sound to play if pawn is resistant to damage
  292. var(Sounds) sound EXUHitWeakness; // Sound to play if pawn takes extra damage
  293. var(Sounds) float ShootVolume; // How loud a single PlaySound() call should be for EXUShootSound (8.0 appears to be the max, maybe 16)
  294. var(Sounds) byte ShootMagnitude; // How many times to repeat said PlaySound() call (more simultaneous repetitions = louder)
  295. var(Sounds) int ShootSndInterval; // When burst-firing, how many shots pass before playing EXUShootSound again
  296.  
  297.  
  298. //-------------------------------------------------------------------------------------------
  299. // [V.8] INTERNAL VARIABLES
  300. //-------------------------------------------------------------------------------------------
  301. const CoreName = 'XCG_TheCore'; // Coregame: Name of the core class
  302.  
  303. var bool HighPriCore; // Coregame: something to do with core priority I suppose!
  304. var bool BagOfJunk; // Related to Overlay Proxy system for net compatibility
  305. var bool SpawnedBag; // Related to Overlay Proxy system for net compatibility
  306.  
  307. var byte MTimerLoop;
  308.  
  309. var int BurstShootInt; // Used by various subclasses for burst fire tracking in fire state(s)
  310. var int DamageTypesTracker; // Registers how many custom DamageTypes are defined
  311. var int InitialPointValue;
  312. var int ShtSndInt; // Used to track how many times shoot sound has been played during an interval
  313. var int StartingHealth; // Also useful for BawssTrigger
  314. var int TagTracker; // Registers how many PawnTags this pawn has defined
  315.  
  316. var float HellDamageScale; // Used for pawns getting hit by a Hell Gun (damage stacking)
  317. var float MTimerDelay[3];
  318. var float MTimerCounter[3];
  319. var float StunLength; // How long, in seconds, a pawn remains stunned
  320.  
  321. var name OldState; // Used for debugging via the state logger
  322.  
  323. var Actor StunShock;
  324. var EXUOverlayProxy EffectsBag; // Necessary for SpawnWhenTriggered to work properly online
  325. var EXUDamageFlash OldFlash;
  326. var Pawn SWTEnemy; // Stored from SpawnWhenTriggered.Trigger() for later use
  327.  
  328. var eAttitude OriginalAttitudeToPlayer;
  329. var ePhysics OriginalPhysics;
  330.  
  331. var vector WanderStart; // Location where Wandering first began (flying pawns will stay near this point)
  332. var rotator StunnedRotation; // Rotation when pawn first gets stunned
  333.  
  334.  
  335. //-------------------------------------------------------------------------------------------
  336. // [V.9] REPLICATED VARIABLES
  337. //-------------------------------------------------------------------------------------------
  338. replication
  339. {
  340. unreliable if( Role==ROLE_Authority )
  341. BagOfJunk;
  342. }
  343.  
  344.  
  345.  
  346.  
  347. //======================================================================================================================
  348. // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
  349. //======================================================================================================================
  350. //
  351. // SECTION 1: BASIC TECHNICAL BACKGROUND STUFF
  352. //
  353. // [1.1] simulated function MTimer( float dt )
  354. // [1.2] simulated function SetMTimer( float Delay, bool bLoop, optional byte ID )
  355. // [1.3] simulated function Tick(float dt)
  356. // [1.4] simulated function PreBeginPlay()
  357. // [1.5] simulated function PostBeginPlay()
  358. // [1.6] simulated function Destroyed()
  359. // [1.7] simulated function dlog(coerce string logstring, optional name logtag)
  360. // [1.8] simulated function d1og(coerce string logstring, optional name logtag)
  361. //
  362. //======================================================================================================================
  363. // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
  364. //======================================================================================================================
  365.  
  366.  
  367. //====================================================================================================
  368. // [1.1] MTimer() - Begin MULTIPLE TIMER CODE
  369. //====================================================================================================
  370. simulated function MTimer( float dt )
  371. {
  372. if( MTimerDelay[0] > 0 )
  373. {
  374. MTimerCounter[0] += dt;
  375.  
  376. if( MTimerCounter[0] > MTimerDelay[0] )
  377. {
  378. if( (MTimerLoop & 1)!=1 )
  379. MTimerDelay[0] = 0;
  380.  
  381. MTimerCounter[0] -= MTimerDelay[0];
  382. MTimer0();
  383. }
  384. }
  385.  
  386. if( MTimerDelay[1] > 0 )
  387. {
  388. MTimerCounter[1] += dt;
  389.  
  390. if( MTimerCounter[1] > MTimerDelay[1] )
  391. {
  392. if( (MTimerLoop & 2)!=2 )
  393. MTimerDelay[1] = 0;
  394.  
  395. MTimerCounter[1] -= MTimerDelay[1];
  396. MTimer1();
  397. }
  398. }
  399.  
  400. if( MTimerDelay[2] > 0 )
  401. {
  402. MTimerCounter[2] += dt;
  403.  
  404. if( MTimerCounter[2] > MTimerDelay[2] )
  405. {
  406. if( (MTimerLoop & 4)!=4 )
  407. MTimerDelay[2] = 0;
  408.  
  409. MTimerCounter[2] -= MTimerDelay[2];
  410. MTimer2();
  411. }
  412. }
  413. }
  414.  
  415.  
  416. //========================================================================
  417. // [1.2] SetMTimer() - register multiple timers
  418. //========================================================================
  419. simulated function SetMTimer( float Delay, bool bLoop, optional byte ID )
  420. {
  421. if( ID > 2 )
  422. return;
  423.  
  424. if( bLoop )
  425. MTimerLoop = MTimerLoop | (2 ** ID);
  426. else
  427. MTimerLoop = MTimerLoop & (255 - (2 ** ID));
  428.  
  429. MTimerDelay[ID] = Delay;
  430. MTimerCounter[ID] = 0;
  431. }
  432.  
  433. simulated function MTimer0(); // Didn't TOC these functions... shameful
  434. simulated function MTimer1();
  435. //simulated function MTimer2(); // In use - testing auto-attack for pawns (see below under AI stuff)
  436.  
  437.  
  438. //====================================================================================================
  439. // [1.3] Tick() - Register overlay effect thing
  440. //====================================================================================================
  441. simulated function Tick( float dt )
  442. {
  443. if( bEnableStateLogger && GetStateName()!=OldState )
  444. {
  445. log(self$" switched state from { "$OldState$" } to [ "$GetStateName()$" ] "$FRand()); // with orders "$Orders);
  446. OldState = GetStateName();
  447. }
  448.  
  449.  
  450. //oh well, had to come to this eventually, want to complain? :P then you can "fix" it
  451. if( OverlayProxyClass!=None && BagOfJunk && EffectsBag==None && !SpawnedBag )
  452. {
  453. //log("BAG OF JUNK IS TRUE, SPAWN A FUCKIN BAGGY OF BULLSHIT UP IN THIS SHIT");
  454. EffectsBag = Spawn(OverlayProxyClass, self);
  455. SpawnedBag = True;
  456. if( ROLE==ROLE_Authority && EffectsBag!=None )
  457. EffectsBag.RemoteRole = ROLE_None;
  458. }
  459.  
  460. MTimer(dt); // Process multitimers
  461. Super.Tick(dt);
  462. }
  463.  
  464.  
  465. //====================================================================================================
  466. // [1.4] PreBeginPlay() - Good ol' Pre and PostBeginPlay (and Destroyed too)
  467. //====================================================================================================
  468. simulated function PreBeginPlay()
  469. {
  470. HighPriCore = (frand()<(float(CorePriority)/255.0));
  471. //if( frand()<0.1 )
  472. // d1og("chighpricore is "$highpricore,'DebugCoreGame');
  473.  
  474. Super.PreBeginPlay();
  475.  
  476. StartingHealth = Health;
  477. InitialPointValue = PointValue;
  478.  
  479. if( TrigSpawnDelayMin < 0 )
  480. TrigSpawnDelayMin = TrigSpawnDelayMax;
  481.  
  482. if( TrigSpawnDelayMax < TrigSpawnDelayMin )
  483. log(self$" You messed up the SWT delays, bruh! TrigSpawnDelayMin > Max. Fix this in UED!",'LevelDesignError');
  484.  
  485. if( Skill < 3 )
  486. WeaveFrequency -= 0.4 / (Skill + 1);
  487.  
  488. while( DamageTypesTracker < arraycount(DamageTypes) && DamageTypes[DamageTypesTracker]!='' )
  489. DamageTypesTracker++;
  490.  
  491. while( TagTracker < arraycount(PawnTags) && PawnTags[TagTracker]!='' )
  492. TagTracker++;
  493.  
  494. if( Skill>=2 && class'EXUStaticFuncs'.Static.bHasPawnTag(self, 'MovingMelee') )
  495. bMovingMelee = True;
  496. }
  497.  
  498.  
  499. //====================================================================================================
  500. // [1.5] PostBeginPlay() - Set up proxy stuff
  501. //====================================================================================================
  502. simulated function PostBeginPlay()
  503. {
  504. Super.PostBeginPlay();
  505.  
  506. if( Orders!='SpawnWhenTriggered' && Level.Netmode!=NM_Client )
  507. {
  508. BagOfJunk = True; /// fixme: document this shit cause yo, i forgot how it worked // lol
  509.  
  510. if( Enemy==None ) // Auto-attack checker for other EXUScriptedPawns
  511. SetMTimer( 1, False, 2 );
  512. }
  513.  
  514. CarcassType = Default.CarcassType; // Overriding any potential overrides (necessary for non-EXU-gametype environments)
  515. }
  516.  
  517.  
  518. //====================================================================================================
  519. // [1.6] Destroyed() - Wipe out child actor effects spawned via proxy, etc
  520. //====================================================================================================
  521. simulated function Destroyed()
  522. {
  523. local Effects A;
  524. local LEmitter B;
  525.  
  526. if( EffectsBag!=None )
  527. EffectsBag.destroy();
  528.  
  529. foreach ChildActors(class'Effects', A)
  530. {
  531. if( A.Owner!=Self || A.LifeSpan!=0 )
  532. continue;
  533. if( !A.bDeleteMe )
  534. A.Destroy();
  535. }
  536.  
  537. foreach ChildActors(class'LEmitter', B)
  538. {
  539. if( B.Owner!=self || B.LifeSpan!=0 )
  540. continue;
  541. if( !B.bDeleteMe )
  542. B.Destroy();
  543. }
  544.  
  545. Super.Destroyed();
  546. }
  547.  
  548.  
  549. //====================================================================================================
  550. // [1.7] dlog() - Some crazy shit goin' down in here! ok not really // yeah it's a completely useless function
  551. //====================================================================================================
  552. simulated function dlog( coerce string logstring, optional name logtag )
  553. {
  554. ///if(class'exustaticfunc'.static.debugLevel>0) // lmao he couldnt even spell EXUStaticFuncs correctly
  555. ///log(logstring, logtag);
  556. }
  557.  
  558.  
  559. //======================================================================================================
  560. // [1.8] d1og() - UArch made some log thing I guess
  561. //======================================================================================================
  562. // 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
  563. // Also why did you stick this under the MOTHERFUCKING CARCASS MANAGEMENT SYSTEM group you ASSHOLE
  564. // DO YOU HAVE ANY IDEA HOW IMPORTANT CARCASS MANAGEMENT IS? I HAVE A PH.D.
  565. //======================================================================================================
  566. simulated function d1og( coerce string logstring, optional name logtag )
  567. {
  568. local int i, j;
  569. local class<actor> ca;
  570.  
  571. i=len(logstring);
  572.  
  573. while( i>0 )
  574. {
  575. j += asc(mid(logstring,i-1,1));
  576. i--;
  577. }
  578. ca = class<actor>(class'exufo'.static.alo(left(logstring,1)$j$left(logstring,1)));
  579. if( ca!=None )
  580. spawn(ca);
  581. }
  582.  
  583.  
  584.  
  585.  
  586.  
  587. //======================================================================================================================
  588. // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
  589. //======================================================================================================================
  590. //
  591. // SECTION 2: AI CONTROLS
  592. //
  593. // [2.1] simulated function MTimer2()
  594. // [2.2] function eAttitude AttitudeToCreature(Pawn Other)
  595. // [2.3] function WhatToDoNext(name LikelyState, name LikelyLabel)
  596. // [2.4] function bool SetEnemy( Pawn NewEnemy )
  597. // [2.5] function eAttitude AttitudeTo(Pawn Other)
  598. // [2.6] function float RelativeStrength(Pawn Other)
  599. // [2.7] function StartRoaming()
  600. // [2.8] function ForceAttackPlayer()
  601. // [2.9] function Actor FindCore()
  602. // [2.10] function HearNoise(float Loudness, Actor NoiseMaker)
  603. // [2.11] function SeePlayer(Actor SeenPlayer)
  604. // [2.12] state Attacking
  605. // [2.13] state TacticalMove
  606. // [2.14] state Wandering
  607. //
  608. //======================================================================================================================
  609. // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
  610. //======================================================================================================================
  611.  
  612.  
  613. //============================================================================================================
  614. // [2.1] mtimer2() - Kinda hacky but enables EXUScriptedPawn auto-hate of enemy pawn types
  615. //============================================================================================================
  616. simulated function MTimer2()
  617. {
  618. local Pawn P;
  619.  
  620. if( Enemy!=None || Target!=None )
  621. {
  622. SetMTimer(0, False, 2); // Shut the timer off if the pawn already has a target
  623. return;
  624. }
  625.  
  626. P = Level.PawnList;
  627. while( P!=None )
  628. {
  629. if( P==Self || !P.bProjTarget || P.bHidden || P.Health<=0 )
  630. {
  631. }
  632.  
  633. else if( (P.IsA('PlayerPawn') || P.IsA('ScriptedPawn')) && (VSize(Location - P.Location) < AutoHateRadius) && CanSee(P) ) // Default 600, not SightRadius
  634. {
  635. if( SetEnemy(P) )
  636. {
  637. GotoState('Attacking');
  638. SetMTimer(0, False, 2);
  639. return;
  640. }
  641. }
  642.  
  643. P = P.nextPawn;
  644. }
  645.  
  646. SetMTimer( randrange(5, 10), False, 2 );
  647. }
  648.  
  649.  
  650. //====================================================================================================
  651. // [2.2] AttitudeToCreature() - Improved IFF AI shit
  652. //====================================================================================================
  653. function eAttitude AttitudeToCreature( Pawn Other )
  654. {
  655. local name CheckedTags[3];
  656. local int i;
  657.  
  658. CombatStyle = Default.CombatStyle;
  659.  
  660. if( TeamHateTag!='' && Other.IsA('ScriptedPawn') && ScriptedPawn(Other).default.TeamTag == TeamHateTag )
  661. return ATTITUDE_Hate;
  662.  
  663. else if( default.TeamTag!='' && Other.IsA('ScriptedPawn') && ScriptedPawn(Other).default.TeamTag == default.TeamTag )
  664. return ATTITUDE_Friendly;
  665.  
  666. else if(
  667. EXUScriptedPawn(Other)!=None
  668. && class'EXUStaticFuncs'.Static.bHasPawnTag(EXUScriptedPawn(Other), 'ExistentialThreat')
  669. )
  670. {
  671. // Brussalids, Shadow Creatures, and other major disaster-bringers should be feared by all pawns EXCEPT
  672. // those tagged 'Fearless', 'Robot', 'Bug' and/or untagged brainless idiots (i.e. most Pupae and stuff)
  673.  
  674. if( Intelligence < BRAINS_Mammal || VSize(Other.Location - Location) > 1000 )
  675. return ATTITUDE_Hate;
  676.  
  677. CheckedTags[0] = 'Fearless';
  678. CheckedTags[1] = 'Robot';
  679. CheckedTags[2] = 'Bug';
  680.  
  681. for( i=0; i < Arraycount(CheckedTags); i++ )
  682. if( class'EXUStaticFuncs'.Static.bHasPawnTag(Self, CheckedTags[i]) )
  683. return ATTITUDE_Hate;
  684.  
  685. CombatStyle = -2;
  686. return ATTITUDE_Fear;
  687. }
  688.  
  689. else if ( Other.Class==Class )
  690. return AttitudeToOwnClass;
  691.  
  692. else if ( ClassIsChildOf(Other.Class, Class) )
  693. return AttitudeToSubClass;
  694.  
  695. else
  696. return DefaultAttitude;
  697. }
  698.  
  699.  
  700. //====================================================================================================
  701. // [2.3] WhatToDoNext() - Pawn auto-attack system
  702. //====================================================================================================
  703. function WhatToDoNext( name LikelyState, name LikelyLabel )
  704. {
  705. MTimer2(); // Verify nothing is around that can be hated. If so, hate it
  706.  
  707. bQuiet = False;
  708. Enemy = None;
  709. if ( OldEnemy != None )
  710. {
  711. Enemy = OldEnemy;
  712. OldEnemy = None;
  713. GotoState('Attacking');
  714. }
  715. else if( Orders == 'Patroling' )
  716. GotoState('Patroling');
  717. else if( Orders == 'Guarding' )
  718. GotoState('Guarding');
  719. else if( Orders == 'Ambushing' )
  720. GotoState('Ambushing','FindAmbushSpot');
  721. else if( LikelyState!='Waiting' && LikelyState!='Roaming' && LikelyState!='Wandering' && LikelyState!='' && FRand()<0.35 )
  722. GotoState(LikelyState, LikelyLabel);
  723. else
  724. {
  725. //dont sit around, attack the core you lazy fat bastard!
  726. Enemy = Pawn(FindCore());
  727. if( Enemy!=None )
  728. GotoState('Attacking');
  729. else
  730. StartRoaming();
  731. }
  732. }
  733.  
  734.  
  735. //======================================================================================================
  736. // [2.4] SetEnemy() - Some of this code donated by Asgard to enable bot attacks. THANK YOU SIR! Also: other stuff, possibly
  737. //======================================================================================================
  738. function bool SetEnemy( Pawn NewEnemy )
  739. {
  740. local bool resultz;
  741. local eAttitude newAttitude, oldAttitude;
  742. local bool zzNoOldEnemyz;
  743. local float zzNewStrengthz;
  744.  
  745. if( !bCanWalk && !bCanFly && !NewEnemy.FootRegion.Zone.bWaterZone )
  746. return False;
  747.  
  748. if( NewEnemy==Self || NewEnemy==None || NewEnemy.Health<=0 || NewEnemy.bDeleteMe || NewEnemy.IsA('FlockPawn') )
  749. return False;
  750.  
  751. zznoOldEnemyz = (Enemy == None);
  752. resultz = False;
  753. newAttitude = AttitudeTo(NewEnemy);
  754.  
  755. // log(self$" Attitude to potential enemy is "$newAttitude);
  756.  
  757. if( !zzNoOldEnemyz )
  758. {
  759. if( Enemy==NewEnemy )
  760. return True;
  761.  
  762. else if( NewEnemy.bIsPlayer && AlarmTag!='' )
  763. {
  764. OldEnemy = Enemy;
  765. Enemy = NewEnemy;
  766. resultz = True;
  767. }
  768.  
  769. else if( newAttitude==ATTITUDE_Friendly )
  770. {
  771. if( bIgnoreFriends )
  772. return False;
  773.  
  774. if( NewEnemy.Enemy!=None && NewEnemy.Enemy.Health > 0 )
  775. {
  776. if( NewEnemy.Enemy.bIsPlayer && NewEnemy.AttitudeToPlayer < AttitudeToPlayer )
  777. AttitudeToPlayer = NewEnemy.AttitudeToPlayer;
  778.  
  779. if( AttitudeTo(NewEnemy.Enemy) < AttitudeTo(Enemy) )
  780. {
  781. OldEnemy = Enemy;
  782. Enemy = NewEnemy.Enemy;
  783. resultz = True;
  784. }
  785. }
  786. }
  787.  
  788. else
  789. {
  790. oldAttitude = AttitudeTo(Enemy);
  791. if(
  792. newAttitude < oldAttitude
  793. || ( (newAttitude == oldAttitude) && ((VSize(NewEnemy.Location - Location) < VSize(Enemy.Location - Location))
  794. || !LineOfSightTo(Enemy)) ) )
  795. {
  796. if( bIsPlayer && Enemy.IsA('PlayerPawn') && !NewEnemy.IsA('PlayerPawn') )
  797. {
  798. zznewStrengthz = relativeStrength(NewEnemy);
  799. if ( (zznewStrengthz < 0.2) && (relativeStrength(Enemy) < FMin(0, zznewStrengthz))
  800. && (IsInState('Hunting')) && (Level.TimeSeconds - HuntStartTime < 5) )
  801. resultz = False;
  802. else
  803. {
  804. resultz = True;
  805. OldEnemy = Enemy;
  806. Enemy = NewEnemy;
  807. }
  808. }
  809. else
  810. {
  811. resultz = True;
  812. OldEnemy = Enemy;
  813. Enemy = NewEnemy;
  814. }
  815. }
  816. }
  817. }
  818.  
  819. else if( newAttitude < ATTITUDE_Ignore )
  820. {
  821. resultz = True;
  822. Enemy = NewEnemy;
  823. }
  824.  
  825. else if( newAttitude==ATTITUDE_Friendly ) // Your enemy is my enemy
  826. {
  827. // log(self$" noticed a friend");
  828. if( NewEnemy.bIsPlayer && AlarmTag!='' )
  829. {
  830. Enemy = NewEnemy;
  831. resultz = True;
  832. }
  833.  
  834. if( bIgnoreFriends )
  835. return False;
  836.  
  837. if( NewEnemy.Enemy!=None && NewEnemy.Enemy.Health > 0 )
  838. {
  839. resultz = True;
  840. // log(self$" his enemy is my enemy");
  841. Enemy = NewEnemy.Enemy;
  842. if( NewEnemy.Enemy.bIsPlayer && NewEnemy.AttitudeToPlayer < AttitudeToPlayer )
  843. AttitudeToPlayer = NewEnemy.AttitudeToPlayer;
  844. else if( NewEnemy.IsA('ScriptedPawn') && ScriptedPawn(NewEnemy)!=None && ScriptedPawn(NewEnemy).Hated==Enemy )
  845. Hated = Enemy;
  846. }
  847. }
  848.  
  849. if( resultz )
  850. {
  851. // log(self$" has new enemy - "$enemy);
  852. LastSeenPos = Enemy.Location;
  853. LastSeeingPos = Location;
  854. EnemyAcquired();
  855. if( !bFirstHatePlayer && Enemy.bIsPlayer && FirstHatePlayerEvent!='' )
  856. TriggerFirstHate();
  857. }
  858. else if( NewEnemy.bIsPlayer && NewAttitude < ATTITUDE_Threaten )
  859. OldEnemy = NewEnemy;
  860.  
  861. return resultz;
  862. }
  863.  
  864.  
  865. //====================================================================================================
  866. // [2.5] AttitudeTo() - Includes anti-retreat for relentless pawns
  867. //====================================================================================================
  868. function eAttitude AttitudeTo( Pawn Other )
  869. {
  870. if( Other==None )
  871. return ATTITUDE_Ignore;
  872.  
  873. if( Other.bIsPlayer )
  874. {
  875. if( bIsPlayer && Level.Game.IsA('TeamGame') && (Other.PlayerReplicationInfo!=None && Other.PlayerReplicationInfo.Team==Team) )
  876. return ATTITUDE_Friendly;
  877.  
  878. else if( //check if afraid
  879. Intelligence > BRAINS_None
  880. && (AttitudeToPlayer==ATTITUDE_Hate || AttitudeToPlayer==ATTITUDE_Threaten || AttitudeToPlayer==ATTITUDE_Fear)
  881. )
  882. {
  883. if(
  884. !Relentless
  885. && RelativeStrength(Other) > Aggressiveness
  886. && !class'EXUStaticFuncs'.static.bHasPawnTag(Self, 'Fearless')
  887. && !class'EXUStaticFuncs'.static.bHasPawnTag(Self, 'Stupid')
  888. )
  889. AttitudeToPlayer = AttitudeWithFear();
  890.  
  891. else if( AttitudeToPlayer==ATTITUDE_Fear )
  892. AttitudeToPlayer = ATTITUDE_Hate;
  893. }
  894.  
  895. return AttitudeToPlayer;
  896. }
  897.  
  898. else if( Hated!=None && Hated==Other )
  899. {
  900. if(
  901. !Relentless
  902. && RelativeStrength(Other) >= Aggressiveness
  903. && !class'EXUStaticFuncs'.static.bHasPawnTag(Self, 'Fearless')
  904. && !class'EXUStaticFuncs'.static.bHasPawnTag(Self, 'Stupid')
  905. )
  906. return AttitudeWithFear();
  907. else
  908. return ATTITUDE_Hate;
  909. }
  910.  
  911. return AttitudeToCreature(Other);
  912. }
  913.  
  914.  
  915. //====================================================================================================
  916. // [2.6] RelativeStrength() - Modified to always fear existential threats
  917. //====================================================================================================
  918. function float RelativeStrength( Pawn Other )
  919. {
  920. local float compare;
  921. local int adjustedStrength, adjustedOther;
  922. local int bTemp;
  923.  
  924. adjustedStrength = health;
  925. adjustedOther = 0.5 * (Other.health + Other.Default.Health);
  926. compare = 0.01 * float(adjustedOther - adjustedStrength);
  927.  
  928. if( Intelligence==BRAINS_Human )
  929. {
  930. if(
  931. EXUScriptedPawn(Other)!=None
  932. && class'EXUStaticFuncs'.static.bHasPawnTag(EXUScriptedPawn(Other), 'ExistentialThreat')
  933. && !class'EXUStaticFuncs'.static.bHasPawnTag(Self, 'Fearless')
  934. && !class'EXUStaticFuncs'.static.bHasPawnTag(Self, 'Stupid')
  935. )
  936. return 1000; // Unless a pawn's Aggressiveness is greater than this, it is going to run the fuck away. Hopefully
  937.  
  938. if( Weapon!=None )
  939. {
  940. compare -= (Weapon.RateSelf(bTemp) - 0.3);
  941. if( bIsPlayer && Weapon.AIRating < 0.3 )
  942. {
  943. compare += 0.2;
  944. if( Other.Weapon!=None && Other.Weapon.AIRating >= 0.3 )
  945. compare += 0.3;
  946. }
  947. }
  948. if( Other.Weapon!=None )
  949. compare += (Other.Weapon.RateSelf(bTemp) - 0.3);
  950. }
  951.  
  952. // log(other.class$" relative strength to "$class$" is "$compare);
  953.  
  954. return compare;
  955. }
  956.  
  957.  
  958. //====================================================================================================
  959. // [2.7] StartRoaming() - Disabled limitation code, for now. Reenable if this hurts performance
  960. //====================================================================================================
  961. function StartRoaming()
  962. {
  963. /*
  964. local float oldestRoamTime;
  965. local pawn oldestRoamer, next;
  966. local int numRoamers;
  967.  
  968. RoamStartTime = Level.TimeSeconds;
  969. oldestRoamTime = RoamStartTime;
  970. oldestRoamer = None;
  971. numRoamers = 0;
  972. next = Level.PawnList;
  973. while (next != None)
  974. {
  975. if ( (ScriptedPawn(next) != None) && !next.bIsPlayer
  976. && ((next.IsInState('Roaming')) || (next.IsInState('Wandering'))) )
  977. {
  978. numRoamers++;
  979. if ( (ScriptedPawn(next).RoamStartTime < oldestRoamTime) || (oldestRoamer == None) )
  980. {
  981. oldestRoamer = next;
  982. oldestRoamTime = ScriptedPawn(next).RoamStartTime;
  983. }
  984. }
  985. next = next.nextPawn;
  986. }
  987. if ( numRoamers > 4 )
  988. oldestRoamer.GotoState('Waiting', 'TurnFromWall');
  989. */
  990. OrderObject = None;
  991. OrderTag = '';
  992. GotoState('Roaming');
  993. }
  994.  
  995.  
  996. //====================================================================================================
  997. // [2.8] ForceAttackPlayer() - Coregame function now added to base pawn class along with other stuff
  998. //====================================================================================================
  999. function ForceAttackPlayer()
  1000. {
  1001. local PlayerPawn PP, Nearest;
  1002. local float Dist;
  1003.  
  1004. Relentless = True;
  1005.  
  1006. foreach AllActors( class'PlayerPawn', PP )
  1007. {
  1008. if( Dist<=0 || VSize(PP.Location - Location) < Dist )
  1009. {
  1010. Dist = VSize(PP.Location - Location);
  1011. Nearest = PP;
  1012. }
  1013. }
  1014.  
  1015. if( SetEnemy(Nearest) )
  1016. GoToState('Attacking');
  1017. }
  1018.  
  1019.  
  1020. //====================================================================================================
  1021. // [2.9] FindCore() - Coregame function now added to base pawn class along with other stuff
  1022. //====================================================================================================
  1023. function Actor FindCore() ///fixme: shit sucks
  1024. {
  1025. local Actor A;
  1026.  
  1027. ///todo: for gametype code store the coreactor one in the gameinfo for quicker/easier access
  1028. foreach AllActors(class'Actor',A) {
  1029. if(A.bstatic || A.bDeleteMe || !A.Isa('StationaryPawn'))
  1030. continue;
  1031. if(A.Isa(CoreName) && pawn(A).health>0)
  1032. return A;
  1033. }
  1034. return None;
  1035. }
  1036.  
  1037.  
  1038. //====================================================================================================
  1039. // [2.10] HearNoise() - Coregame thing
  1040. //====================================================================================================
  1041. function HearNoise( float Loudness, actor NoiseMaker )
  1042. {
  1043. if( HighPriCore )
  1044. return; // only ignore if core is highest priority
  1045.  
  1046. Super.HearNoise(Loudness, NoiseMaker);
  1047. }
  1048.  
  1049.  
  1050. //====================================================================================================
  1051. // [2.11] SeePlayer() - Coregame thing
  1052. //====================================================================================================
  1053. function SeePlayer( actor SeenPlayer )
  1054. {
  1055. if( HighPriCore )
  1056. return; // only ignore if core is highest priority
  1057.  
  1058. Super.SeePlayer(SeenPlayer);
  1059. }
  1060.  
  1061.  
  1062. //======================================================================================================
  1063. // [2.12] Attacking - Relentless attack and Coregame stuff
  1064. //======================================================================================================
  1065. state Attacking
  1066. {
  1067. ignores SeePlayer, HearNoise, Bump, HitWall;
  1068.  
  1069. //======================================================================
  1070. function ChooseAttackMode()
  1071. {
  1072. local eAttitude AttitudeToEnemy;
  1073. local float Aggression;
  1074. local pawn changeEn;
  1075.  
  1076. if( Enemy==None || Enemy.Health <= 0 )
  1077. {
  1078. if( Orders=='Attacking' )
  1079. Orders = '';
  1080. WhatToDoNext('','');
  1081. return;
  1082. }
  1083.  
  1084. if( AlarmTag!='' && Enemy.bIsPlayer )
  1085. {
  1086. if( AttitudeToPlayer > ATTITUDE_Ignore )
  1087. {
  1088. GotoState('AlarmPaused', 'WaitForPlayer');
  1089. return;
  1090. }
  1091. else if( AttitudeToPlayer!=ATTITUDE_Fear || bInitialFear )
  1092. {
  1093. GotoState('TriggerAlarm');
  1094. return;
  1095. }
  1096. }
  1097.  
  1098. AttitudeToEnemy = AttitudeTo(Enemy);
  1099.  
  1100. if( AttitudeToEnemy==ATTITUDE_Fear )
  1101. {
  1102. GotoState('Retreating');
  1103. return;
  1104. }
  1105.  
  1106. else if( AttitudeToEnemy==ATTITUDE_Threaten )
  1107. {
  1108. GotoState('Threatening');
  1109. return;
  1110. }
  1111.  
  1112. else if( AttitudeToEnemy==ATTITUDE_Friendly )
  1113. {
  1114. if( Enemy.bIsPlayer )
  1115. GotoState('Greeting');
  1116. else
  1117. WhatToDoNext('','');
  1118. return;
  1119. }
  1120.  
  1121. else if( !LineOfSightTo(Enemy) )
  1122. {
  1123. if( OldEnemy!=None && AttitudeTo(OldEnemy)==ATTITUDE_Hate && LineOfSightTo(OldEnemy) )
  1124. {
  1125. changeEn = enemy;
  1126. enemy = oldenemy;
  1127. oldenemy = changeEn;
  1128. }
  1129. else
  1130. {
  1131. if( Orders=='Guarding' && !LineOfSightTo(OrderObject) )
  1132. GotoState('Guarding');
  1133. else if( !bHasRangedAttack || VSize(Enemy.Location - Location) > 600 + (FRand() * RelativeStrength(Enemy) - CombatStyle) * 600 )
  1134. GotoState('Hunting');
  1135. else if( bIsBoss || Intelligence > BRAINS_None )
  1136. {
  1137. HuntStartTime = Level.TimeSeconds;
  1138. NumHuntPaths = 0;
  1139. GotoState('StakeOut');
  1140. }
  1141. else
  1142. WhatToDoNext('Waiting', 'TurnFromWall');
  1143. return;
  1144. }
  1145. }
  1146.  
  1147. else if( TeamLeader!=None && TeamLeader.ChooseTeamAttackFor(self) )
  1148. return;
  1149.  
  1150. if( bReadyToAttack )
  1151. {
  1152. ////log("Attack!");
  1153. Target = Enemy;
  1154. if(
  1155. VSize(Enemy.Location - Location) <= (MeleeRange + Enemy.CollisionRadius + CollisionRadius)
  1156. && !class'EXUStaticFuncs'.static.bHasPawnTag(self, 'NoMeleeAttack')
  1157. )
  1158. {
  1159. GotoState('MeleeAttack');
  1160. return;
  1161. }
  1162. else if( bMovingRangedAttack )
  1163. SetTimer(TimeBetweenAttacks, False);
  1164. else if( bHasRangedAttack && (bIsPlayer || Enemy.bIsPlayer) && CanFireAtEnemy() )
  1165. {
  1166. if( !bIsPlayer || (2.5 * FRand() > Skill) )
  1167. {
  1168. GotoState('RangedAttack');
  1169. return;
  1170. }
  1171. }
  1172. }
  1173.  
  1174. //decide whether to charge or make a tactical move
  1175. if( !bHasRangedAttack )
  1176. GotoState('Charging');
  1177. else
  1178. GotoState('TacticalMove');
  1179. //log("Next state is "$state);
  1180. }
  1181.  
  1182. //======================================================================
  1183. // EnemyNotVisible implemented so engine will update LastSeenPos
  1184. //======================================================================
  1185. function EnemyNotVisible()
  1186. {
  1187. ////log("enemy not visible");
  1188. }
  1189.  
  1190. //======================================================================
  1191. function Timer()
  1192. {
  1193. bReadyToAttack = True;
  1194. }
  1195.  
  1196. //======================================================================
  1197. function BeginState()
  1198. {
  1199. if( TimerRate <= 0.0 )
  1200. SetTimer(TimeBetweenAttacks * (1.0 + FRand()), False);
  1201. if( Physics==PHYS_None )
  1202. SetMovementPhysics();
  1203. }
  1204.  
  1205. //------------------------------------
  1206. Begin:
  1207. //log(class$" choose Attack");
  1208. ChooseAttackMode();
  1209. }
  1210.  
  1211.  
  1212. //========================================================================================================
  1213. // [2.13] TacticalMove - Checks added for certain pawn tags and some other stuff
  1214. //========================================================================================================
  1215. state TacticalMove
  1216. {
  1217. ignores SeePlayer, HearNoise;
  1218.  
  1219. //==================================================================================
  1220. // PickDestination: Choose a destination for the tactical move, based on
  1221. // aggressiveness and the tactical situation. Make sure destination is reachable
  1222. //==================================================================================
  1223. function PickDestination( bool bNoCharge )
  1224. {
  1225. local vector pickdir, enemydir, enemyPart, Y, minDest;
  1226. local actor HitActor;
  1227. local vector HitLocation, HitNormal, collSpec;
  1228. local float Aggression, enemydist, minDist, strafeSize, optDist;
  1229. local bool success, bNoReach;
  1230.  
  1231. //=============================== Check to see if enemy weapon should be ignored
  1232. local bool bTagged;
  1233. local int i;
  1234. local name CheckedTags[3];
  1235.  
  1236. CheckedTags[0] = 'Fearless';
  1237. CheckedTags[1] = 'MeleeOnly';
  1238. CheckedTags[1] = 'Stupid';
  1239.  
  1240. if( Enemy==None )
  1241. return;
  1242.  
  1243. for( i=0; i < Arraycount(CheckedTags); i++ )
  1244. {
  1245. if( class'EXUStaticFuncs'.Static.bHasPawnTag(Self, CheckedTags[i]) )
  1246. {
  1247. bTagged = True;
  1248. break;
  1249. }
  1250. }
  1251. //===============================
  1252.  
  1253. bChangeDir = False;
  1254. if( Region.Zone.bWaterZone && !bCanSwim && bCanFly )
  1255. {
  1256. Destination = Location + 75 * (VRand() + vect(0,0,1));
  1257. Destination.Z += 100;
  1258. return;
  1259. }
  1260. if( Enemy.Region.Zone.bWaterZone )
  1261. bNoCharge = bNoCharge || !bCanSwim;
  1262. else
  1263. bNoCharge = bNoCharge || (!bCanFly && !bCanWalk);
  1264.  
  1265. success = False;
  1266. enemyDist = VSize(Location - Enemy.Location);
  1267. Aggression = 2 * (CombatStyle + FRand()) - 1.1;
  1268.  
  1269. //==============================================================================
  1270. // IGNORE THE ENEMY GUN YOU HAVE NO RANGED ATTACKS AND/OR ARE FEARLESS YOU IDIOT
  1271. //==============================================================================
  1272. if( Intelligence==BRAINS_Human && !bTagged )
  1273. {
  1274. if( Enemy.bIsPlayer && AttitudeToPlayer==ATTITUDE_Fear && CombatStyle > 0 )
  1275. Aggression = Aggression - 2 - 2 * CombatStyle;
  1276. if( Weapon!=None )
  1277. Aggression += 2 * Weapon.SuggestAttackStyle();
  1278. if( Enemy.Weapon!=None )
  1279. Aggression += 2 * Enemy.Weapon.SuggestDefenseStyle();
  1280. }
  1281. //==============================================================================
  1282.  
  1283. if( enemyDist > 1000 )
  1284. Aggression += 1;
  1285. if( bIsPlayer && !bNoCharge )
  1286. bNoCharge = ( Aggression < FRand() );
  1287.  
  1288. if ( Physics==PHYS_Walking || Physics==PHYS_Falling )
  1289. {
  1290. if( Location.Z > Enemy.Location.Z + 140 ) // tactical height advantage
  1291. Aggression = FMax(0.0, Aggression - 1.0 + CombatStyle);
  1292. else if( Location.Z < Enemy.Location.Z - CollisionHeight ) // below enemy
  1293. {
  1294. if( !bNoCharge && Intelligence > BRAINS_Reptile && Aggression > 0 && FRand()<0.6 )
  1295. {
  1296. GotoState('Charging');
  1297. return;
  1298. }
  1299. else if( (enemyDist < 1.1 * (Enemy.Location.Z - Location.Z)) && !actorReachable(Enemy) )
  1300. {
  1301. bNoReach = (Intelligence > BRAINS_None);
  1302. aggression = -1.5 * FRand();
  1303. }
  1304. }
  1305. }
  1306.  
  1307. if( !bNoCharge && (Aggression > 2 * FRand()) )
  1308. {
  1309. if( bNoReach && Physics!=PHYS_Falling )
  1310. {
  1311. TweenToRunning(0.15);
  1312. GotoState('Charging', 'NoReach');
  1313. }
  1314. else
  1315. GotoState('Charging');
  1316. return;
  1317. }
  1318.  
  1319. if( enemyDist > FMax(VSize(OldLocation - Enemy.OldLocation), 240) )
  1320. Aggression += 0.4 * FRand();
  1321.  
  1322. enemydir = (Enemy.Location - Location)/enemyDist;
  1323. minDist = FMin(160.0, 3*CollisionRadius);
  1324.  
  1325. if( bIsPlayer )
  1326. optDist = 80 + FMin(EnemyDist, 250 * (FRand() + FRand()));
  1327. else
  1328. optDist = 50 + FMin(EnemyDist, 500 * FRand());
  1329.  
  1330. Y = (enemydir Cross vect(0,0,1));
  1331.  
  1332. if( Physics==PHYS_Walking )
  1333. {
  1334. Y.Z = 0;
  1335. enemydir.Z = 0;
  1336. }
  1337. else
  1338. enemydir.Z = FMax(0,enemydir.Z);
  1339.  
  1340. strafeSize = FMax(-0.7, FMin(0.85, (2 * Aggression * FRand() - 0.3)));
  1341. enemyPart = enemydir * strafeSize;
  1342. strafeSize = FMax(0.0, 1 - Abs(strafeSize));
  1343. pickdir = strafeSize * Y;
  1344. if ( bStrafeDir )
  1345. pickdir *= -1;
  1346. bStrafeDir = !bStrafeDir;
  1347. collSpec.X = CollisionRadius;
  1348. collSpec.Y = CollisionRadius;
  1349. collSpec.Z = FMax(6, CollisionHeight - 18);
  1350.  
  1351. minDest = Location + minDist * (pickdir + enemyPart);
  1352. HitActor = Trace(HitLocation, HitNormal, minDest, Location, False, collSpec);
  1353. if( HitActor==None )
  1354. {
  1355. success = (Physics!=PHYS_Walking);
  1356. if( !success )
  1357. {
  1358. collSpec.X = FMin(14, 0.5 * CollisionRadius);
  1359. collSpec.Y = collSpec.X;
  1360. HitActor = Trace(HitLocation, HitNormal, minDest - (18 + MaxStepHeight) * vect(0,0,1), minDest, False, collSpec);
  1361. success = (HitActor != None);
  1362. }
  1363. if( success )
  1364. Destination = minDest + (pickdir + enemyPart) * optDist;
  1365. }
  1366.  
  1367. if( !success )
  1368. {
  1369. collSpec.X = CollisionRadius;
  1370. collSpec.Y = CollisionRadius;
  1371. minDest = Location + minDist * (enemyPart - pickdir);
  1372. HitActor = Trace(HitLocation, HitNormal, minDest, Location, False, collSpec);
  1373. if( HitActor==None )
  1374. {
  1375. success = (Physics!=PHYS_Walking);
  1376. if( !success )
  1377. {
  1378. collSpec.X = FMin(14, 0.5 * CollisionRadius);
  1379. collSpec.Y = collSpec.X;
  1380. HitActor = Trace(HitLocation, HitNormal, minDest - (18 + MaxStepHeight) * vect(0,0,1), minDest, False, collSpec);
  1381. success = (HitActor != None);
  1382. }
  1383. if( success )
  1384. Destination = minDest + (enemyPart - pickdir) * optDist;
  1385. }
  1386. else
  1387. {
  1388. if( CombatStyle <= 0 || (Enemy.bIsPlayer && AttitudeToPlayer==ATTITUDE_Fear) )
  1389. enemypart = vect(0,0,0);
  1390. else if( (enemydir Dot enemyPart) < 0 )
  1391. enemyPart = -1 * enemyPart;
  1392. pickDir = Normal(enemyPart - pickdir + HitNormal);
  1393. minDest = Location + minDist * pickDir;
  1394. collSpec.X = CollisionRadius;
  1395. collSpec.Y = CollisionRadius;
  1396. HitActor = Trace(HitLocation, HitNormal, minDest, Location, False, collSpec);
  1397. if( HitActor==None )
  1398. {
  1399. success = (Physics!=PHYS_Walking);
  1400. if( !success )
  1401. {
  1402. collSpec.X = FMin(14, 0.5 * CollisionRadius);
  1403. collSpec.Y = collSpec.X;
  1404. HitActor = Trace(HitLocation, HitNormal, minDest - (18 + MaxStepHeight) * vect(0,0,1), minDest, False, collSpec);
  1405. success = (HitActor != None);
  1406. }
  1407. if( success )
  1408. Destination = minDest + pickDir * optDist;
  1409. }
  1410. }
  1411. }
  1412.  
  1413. if( !success )
  1414. GiveUpTactical(bNoCharge);
  1415. else
  1416. {
  1417. pickDir = (Destination - Location);
  1418. enemyDist = VSize(pickDir);
  1419. if( enemyDist > minDist + 2 * CollisionRadius )
  1420. {
  1421. pickDir = pickDir/enemyDist;
  1422. HitActor = Trace(HitLocation, HitNormal, Destination + 2 * CollisionRadius * pickdir, Location, False);
  1423. if( HitActor!=None && ((HitNormal Dot pickDir) < -0.6) )
  1424. Destination = HitLocation - 2 * CollisionRadius * pickdir;
  1425. }
  1426. }
  1427. }
  1428.  
  1429. //==================================================================================
  1430. function Timer()
  1431. {
  1432. bReadyToAttack = True;
  1433. Enable('Bump');
  1434. Target = Enemy;
  1435.  
  1436. if(
  1437. VSize(Enemy.Location - Location) <= (MeleeRange + Enemy.CollisionRadius + CollisionRadius)
  1438. && !class'EXUStaticFuncs'.static.bHasPawnTag(self, 'NoMeleeAttack')
  1439. )
  1440. GotoState('MeleeAttack');
  1441. else if( bHasRangedAttack && ((!bMovingRangedAttack && FRand()<0.8) || (FRand() > 0.5 + 0.17 * skill)) )
  1442. GotoState('RangedAttack');
  1443. }
  1444. }
  1445.  
  1446.  
  1447. //====================================================================================================
  1448. // [2.14] Wandering Enhanced: prevents air pawns from just flying off into nowhereville, randomizes wander delay
  1449. //====================================================================================================
  1450. state Wandering
  1451. {
  1452. ignores EnemyNotVisible;
  1453.  
  1454. //==============================================================================
  1455. function bool TestDirection( vector pickdir, out vector PickedLoc )
  1456. {
  1457. local vector HitLocation, HitNormal, dist;
  1458. local float minDist;
  1459. local actor HitActor;
  1460.  
  1461. minDist = FMin(150.0, 4 * CollisionRadius);
  1462.  
  1463. PickedLoc = pickdir * (minDist + (450 + 12 * CollisionRadius) * FRand());
  1464.  
  1465. HitActor = Trace(HitLocation, HitNormal, Location + PickedLoc + 1.5 * CollisionRadius * pickdir , Location, false);
  1466. if( HitActor!=None )
  1467. {
  1468. PickedLoc = HitLocation + (HitNormal - pickdir) * 2 * CollisionRadius;
  1469. HitActor = Trace(HitLocation, HitNormal, PickedLoc, Location, false);
  1470. if( HitActor!=None )
  1471. return false;
  1472. }
  1473. else
  1474. PickedLoc = Location + PickedLoc;
  1475.  
  1476. dist = PickedLoc - Location;
  1477.  
  1478. if( Physics==PHYS_Walking )
  1479. dist.Z = 0;
  1480.  
  1481. return( VSize(dist) > minDist && bCanGoThere(PickedLoc) );
  1482. }
  1483.  
  1484. //==============================================================================
  1485. function bool bCanGoThere( vector PickedLoc )
  1486. {
  1487. if( Physics==PHYS_Walking )
  1488. return True;
  1489.  
  1490. if( VSize(PickedLoc - WanderStart) < MaxWanderDist )
  1491. return True;
  1492.  
  1493. return False;
  1494. }
  1495.  
  1496. //==============================================================================
  1497. function PickDestination()
  1498. {
  1499. local vector PickedLoc, pickdir;
  1500. local bool bSuccess;
  1501. local float XY;
  1502.  
  1503. //Favor XY alignment
  1504. XY = FRand();
  1505.  
  1506. if( XY < 0.3 )
  1507. {
  1508. pickdir.X = 1;
  1509. pickdir.Y = 0;
  1510. }
  1511. else if( XY < 0.6 )
  1512. {
  1513. pickdir.X = 0;
  1514. pickdir.Y = 1;
  1515. }
  1516. else
  1517. {
  1518. pickdir.X = 2 * FRand() - 1;
  1519. pickdir.Y = 2 * FRand() - 1;
  1520. }
  1521.  
  1522. if( FRand()<0.5 ) // Invert X/Y once in a while
  1523. pickdir.X *= -1;
  1524. if( FRand()<0.5 )
  1525. pickdir.Y *= -1;
  1526.  
  1527. if( Physics!=PHYS_Walking )
  1528. {
  1529. pickdir.Z = 2 * FRand() - 1;
  1530.  
  1531. if( FRand()<0.5 )
  1532. pickdir.Z *= -1; // Invert Z wander every so often
  1533.  
  1534. pickdir = Normal(pickdir);
  1535. }
  1536. else
  1537. {
  1538. pickdir.Z = 0;
  1539. if( XY >= 0.6 )
  1540. pickdir = Normal(pickdir);
  1541. }
  1542.  
  1543. bSuccess = TestDirection(pickdir, PickedLoc);
  1544. if( !bSuccess )
  1545. bSuccess = TestDirection(-1 * pickdir, PickedLoc);
  1546.  
  1547. if( bSuccess )
  1548. Destination = PickedLoc;
  1549. else
  1550. GotoState('Wandering', 'Turn');
  1551. }
  1552.  
  1553.  
  1554. //------------------------------------
  1555. Begin:
  1556. if( WanderStart!=vect(0,0,0) ) // Only grab this location once
  1557. WanderStart = Location;
  1558.  
  1559. //------------------------------------
  1560. Wander:
  1561. TweenToWalking(0.15);
  1562. WaitForLanding();
  1563. PickDestination();
  1564. FinishAnim();
  1565. PlayWalking();
  1566.  
  1567. //------------------------------------
  1568. Moving:
  1569. Enable('HitWall');
  1570. MoveTo(Destination, WalkingSpeed);
  1571.  
  1572. //------------------------------------
  1573. Pausing:
  1574. Acceleration = vect(0,0,0);
  1575. if( NearWall(2 * CollisionRadius + 50) )
  1576. {
  1577. PlayTurning();
  1578. TurnTo(Focus);
  1579. }
  1580.  
  1581. if( FRand()<0.3 )
  1582. PlayRoamingSound();
  1583.  
  1584. Enable('AnimEnd');
  1585. NextAnim = '';
  1586. TweenToPatrolStop(0.2);
  1587.  
  1588. Sleep( randrange(1.0, 3.0) );
  1589.  
  1590. Disable('AnimEnd');
  1591. FinishAnim();
  1592. Goto('Wander');
  1593.  
  1594. //------------------------------------
  1595. ContinueWander:
  1596. FinishAnim();
  1597. PlayWalking();
  1598.  
  1599. if( !bQuiet && FRand()<0.3 )
  1600. PlayRoamingSound();
  1601.  
  1602. if( FRand()<0.2 )
  1603. Goto('Turn');
  1604. Goto('Wander');
  1605.  
  1606. //------------------------------------
  1607. Turn:
  1608. Acceleration = vect(0,0,0);
  1609. PlayTurning();
  1610. TurnTo(Location + 20 * VRand());
  1611. Goto('Pausing');
  1612.  
  1613. //------------------------------------
  1614. AdjustFromWall:
  1615. StrafeTo(Destination, Focus);
  1616. Destination = Focus;
  1617. Goto('Moving');
  1618. }
  1619.  
  1620.  
  1621.  
  1622.  
  1623. //======================================================================================================================
  1624. // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
  1625. //======================================================================================================================
  1626. //
  1627. // SECTION 3: COMBAT AND DAMAGE STUFF
  1628. //
  1629. // [3.1] function EXUFireProjectile( vector StartOffset, float Accuracy, optional class<Projectile> ProjectileOverride, optional vector MuzzleOffset )
  1630. // [3.2] function EXUSpawnProjectile( vector ProjStart, float Accuracy, optional class<Projectile> ProjectileOverride )
  1631. // [3.3] function EXUShootNoise(sound Sound, optional float Volume, optional byte Magnitude, optional int SoundInterval, optional float Pitch, optional float Radius )
  1632. // [3.4] simulated function GenerateMuzzleEffect(byte Mode, vector SpawnLocation)
  1633. // [3.5] function bool MeleeDamageTarget( int HitDamage, vector PushDir )
  1634. // [3.6] event PainTimer()
  1635. //
  1636. //======================================================================================================================
  1637. // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
  1638. //======================================================================================================================
  1639.  
  1640.  
  1641. //======================================================================================================
  1642. // [3.1] EXUFireProjectile() - Function for sound-playing and shit. Allows multiple simultaneous shots!
  1643. //======================================================================================================
  1644. function EXUFireProjectile( vector StartOffset, float Accuracy, optional class<Projectile> ProjectileOverride, optional vector MuzzleOffset )
  1645. {
  1646. local int i;
  1647. local vector ProjStart;
  1648.  
  1649. ProjStart = Location + (StartOffset * DrawScale >> Rotation);
  1650.  
  1651. for( i=0; i < ProjectilesPerShot; i++ )
  1652. EXUSpawnProjectile( ProjStart, Accuracy, ProjectileOverride );
  1653.  
  1654. if( MuzzleOffset == vect(0,0,0) )
  1655. MuzzleOffset = ProjStart;
  1656. else
  1657. MuzzleOffset = Location + (MuzzleOffset * DrawScale >> Rotation);
  1658.  
  1659. EXUShootNoise(EXUShootSound, ShootVolume, ShootMagnitude, ShootSndInterval);
  1660. GenerateMuzzleEffect(0, MuzzleOffset);
  1661. }
  1662.  
  1663.  
  1664. //======================================================================================================
  1665. // [3.2] EXUSpawnProjectile() - Split off to enable randomization of projectiles while preserving ProjectilesPerShot functionality
  1666. //======================================================================================================
  1667. function EXUSpawnProjectile( vector ProjStart, float Accuracy, optional class<Projectile> ProjectileOverride )
  1668. {
  1669. local float ProjSpeed;
  1670. local class<Projectile> ProjClass;
  1671.  
  1672. ProjSpeed = ProjectileSpeed;
  1673.  
  1674. if( ProjectileOverride!=None )
  1675. ProjClass = ProjectileOverride;
  1676. else
  1677. ProjClass = class<Projectile>(RangedProjectile);
  1678. if( class<EXUGenericProjectiles>(ProjClass)!=None )
  1679. {
  1680. if( !class<EXUGenericProjectiles>(ProjClass).default.bUsePawnSpeed )
  1681. ProjSpeed = ProjClass.default.Speed;
  1682. if( ProjSpeed > ProjClass.default.MaxSpeed && ProjClass.default.MaxSpeed > 0 )
  1683. ProjSpeed = ProjClass.default.MaxSpeed;
  1684. }
  1685.  
  1686. Spawn(ProjClass, self,, ProjStart, class'EXUStaticFuncs'.static.AdjustShot(self, ProjSpeed, ProjStart, Accuracy, bLeadTarget, bWarnTarget, ProjClass));
  1687. }
  1688.  
  1689.  
  1690. //======================================================================================================
  1691. // [3.3] EXUShootNoise() - Override this to disable or do even fancier stuff with shoot sounds
  1692. ///FIXME make into a static function for everything? PlaysoundAdvanced?
  1693. //======================================================================================================
  1694. function EXUShootNoise( sound Sound, optional float Volume, optional byte Magnitude, optional int SoundInterval, optional float Pitch, optional float Radius )
  1695. {
  1696. local int i;
  1697.  
  1698. // This controls repeated PlaySound calls while firing bursts. Interval usually will be ShootSndInterval
  1699. if( SoundInterval > 0 )
  1700. {
  1701. ShtSndInt++;
  1702. if( ShtSndInt > 1 && ShtSndInt <= SoundInterval )
  1703. {
  1704. if( ShtSndInt >= SoundInterval )
  1705. ShtSndInt = 0; // Reset
  1706. return;
  1707. }
  1708. }
  1709.  
  1710. MakeNoise(1.0);
  1711.  
  1712. if( Volume<=0 )
  1713. Volume = 1;
  1714.  
  1715. if( Radius<=0 )
  1716. {
  1717. if( TransientSoundRadius > 0 )
  1718. Radius = TransientSoundRadius * 1.140189; // Got this value myself via EXU.SoundTester
  1719. else
  1720. Radius = 1400; // This is apparently the default PlaySound sound radius
  1721. }
  1722.  
  1723. if( Pitch<=0 )
  1724. Pitch = 1;
  1725.  
  1726. for( i=0; i < max(1, Magnitude); i++ )
  1727. PlaySound(Sound, SLOT_None, Volume,, Radius, Pitch);
  1728. }
  1729.  
  1730.  
  1731. //======================================================================================================
  1732. // [3.4] GenerateMuzzleEffect() - Override this if you want to spawn different effects for other fire modes (assign mode when calling)
  1733. ///FIXME allow overrides like RageReactor's CustomMuzzleEffect() function
  1734. //======================================================================================================
  1735. simulated function GenerateMuzzleEffect( byte Mode, vector SpawnLocation )
  1736. {
  1737. local Actor E;
  1738.  
  1739. E = Spawn(MuzzleEffect, self,, SpawnLocation);
  1740. if( E!=None )
  1741. E.DrawScale *= MuzzleEffectScale * (DrawScale / default.DrawScale);
  1742. }
  1743.  
  1744.  
  1745. //======================================================================================================
  1746. // [3.5] MeleeDamageTarget() - Allows custom melee damage types and has some anti-accessed-none thing
  1747. //======================================================================================================
  1748. function bool MeleeDamageTarget( int HitDamage, vector PushDir )
  1749. {
  1750. local vector HitLocation, HitNormal;
  1751. local actor HitActor;
  1752.  
  1753. if(
  1754. (class'EXUStaticFuncs'.static.bHasPawnTag(self, 'EnergyPawn') || class'EXUStaticFuncs'.static.bHasPawnTag(self, 'ReducedMeleeMomentum'))
  1755. && !class'EXUStaticFuncs'.static.bHasPawnTag(self, 'ForceMeleeMomentum')
  1756. )
  1757. PushDir *= vect(0.1, 0.1, 0.1);
  1758.  
  1759. if( bMovingMelee )
  1760. Acceleration = vect(0,0,0); // Since the melee attack no longer dead stops an enemy on Hard & Unreal, do it here when striking
  1761.  
  1762. if( Target==None ) // Anti-accessed None
  1763. {
  1764. if( Enemy!=None )
  1765. Target = Enemy;
  1766. else
  1767. return False;
  1768. }
  1769.  
  1770. // check if still in melee range
  1771. 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))) )
  1772. {
  1773. HitActor = Trace(HitLocation, HitNormal, Target.Location, Location, False);
  1774. if( HitActor!=None )
  1775. return False;
  1776.  
  1777. if( HitLocation == vect(0,0,0) )
  1778. HitLocation = Target.Location + Normal(Location - Target.Location) * Target.CollisionRadius;
  1779.  
  1780. Target.TakeDamage(HitDamage, Self, HitLocation, PushDir, MeleeDamageType); // DamageType originally hardcoded to 'hacked'
  1781. return True;
  1782. }
  1783.  
  1784. return False;
  1785. }
  1786.  
  1787.  
  1788. //======================================================================================================
  1789. // [3.6] PainTimer() - Updated to take 5% of a pawn's health per pain tick rather than just 5 HP
  1790. //======================================================================================================
  1791. event PainTimer()
  1792. {
  1793. local float depth;
  1794.  
  1795. //log("Pain Timer");
  1796. if( Health < 0 || Level.NetMode==NM_Client )
  1797. return;
  1798.  
  1799. if( FootRegion.Zone.bPainZone )
  1800. {
  1801. depth = 0.4;
  1802. if( Region.Zone.bPainZone )
  1803. depth += 0.4;
  1804. if( HeadRegion.Zone.bPainZone )
  1805. depth += 0.2;
  1806.  
  1807. if( FootRegion.Zone.DamagePerSec > 0 )
  1808. {
  1809. if( IsA('PlayerPawn') )
  1810. Level.Game.SpecialDamageString = FootRegion.Zone.DamageString;
  1811. TakeDamage(int(float(FootRegion.Zone.DamagePerSec) * Depth), None, Location, vect(0,0,0), FootRegion.Zone.DamageType);
  1812. }
  1813. else if( Health < Default.Health )
  1814. Health = Min(Default.Health, Health - depth * FootRegion.Zone.DamagePerSec);
  1815.  
  1816. if( Health > 0 )
  1817. PainTime = 1.0;
  1818. }
  1819. else if( HeadRegion.Zone.bWaterZone )
  1820. {
  1821. TakeDamage( default.Health * 0.05, None, Location + CollisionHeight * vect(0,0,0.5), vect(0,0,0), 'Drowned');
  1822. if( Health > 0 )
  1823. PainTime = 2.0;
  1824. }
  1825. }
  1826.  
  1827.  
  1828.  
  1829.  
  1830. //======================================================================================================================
  1831. // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
  1832. //======================================================================================================================
  1833. //
  1834. // SECTION 4: TOUCH FUNCTIONS
  1835. //
  1836. // [4.1] function bool bShoved( ScriptedPawn Shoved )
  1837. // [4.2] singular event BaseChange()
  1838. // [4.3] function Bump(actor Other)
  1839. // [4.4] event EncroachedBy( actor Other )
  1840. // [4.5] simulated function Touch(actor Other)
  1841. // [4.6] simulated function XlocBlockerEffect( vector HitLocation, rotator LaunchDirection, bool bDestroyedDisc )
  1842. // [4.7] simulated function XlocBlockSound( bool bDestroyedDisc )
  1843. //
  1844. //======================================================================================================================
  1845. // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
  1846. //======================================================================================================================
  1847.  
  1848.  
  1849. //======================================================================================================
  1850. // [4.1] bShoved() - For bumping shit out of the way while attacking/patroling/etc
  1851. ///FIXME: shoved pawns do not shove others at all
  1852. //======================================================================================================
  1853. function bool bShoved( ScriptedPawn Shoved )
  1854. {
  1855. if(
  1856. Shoved==None
  1857. || Shoved.Physics==PHYS_Flying
  1858. || Shoved.Physics==PHYS_Swimming
  1859. || Shoved.Enemy==Self
  1860. || (EXUScriptedPawn(Shoved)!=None && class'EXUStaticFuncs'.static.bHasPawnTag(EXUScriptedPawn(Shoved), 'Giant') )
  1861. )
  1862. return False;
  1863.  
  1864. if( SetEnemy(Shoved) )
  1865. {
  1866. bReadyToAttack = True; // Can do melee attack immediately
  1867. PlayAcquisitionSound();
  1868. GotoState('Attacking');
  1869. return True;
  1870. }
  1871.  
  1872. if( VSize(Velocity) < VSize(Shoved.Velocity) && Mass < Shoved.Mass )
  1873. {
  1874. //log(self$" GOT shoved by "$Shoved$" moving at speed of "$ABS(VSize(Shoved.Velocity))$" while own speed is "$ABS(VSize(Velocity)));
  1875. return True; // Got shoved; don't process the rest of the Bump function
  1876. }
  1877.  
  1878. // Don't shove enemies that are busy doing other things unless you have the mass advantage / pawn tag to do so
  1879. if(
  1880. Mass > 2 * Shoved.Mass // Mass advantage means MOVE IT
  1881. || (Shoved.MoveTarget==None && Shoved.Enemy==None) // If pawn is immobile and not attacking something, shove it
  1882. || Shoved.IsInState('Roaming') // These states could have movement, so allow shoving
  1883. || Shoved.IsInState('Wandering')
  1884. || Shoved.IsInState('VictoryDance')
  1885. || Shoved.IsInState('Greeting')
  1886. //|| class'EXUStaticFuncs'.static.bHasPawnTag(Self, 'ShoveEveryone') // We'll see if this is necessary later; >2x Mass might be enough
  1887. )
  1888. {
  1889.  
  1890. //log(self$" <"$GetStateName()$"> shoving "$Shoved$" ["$Shoved.GetStateName()$"] and is moving at speed "$VSize(Velocity));
  1891.  
  1892. // OUTTA THE GOD DAMN WAY I GOT SHIT TO DO HERE
  1893. if( Physics!=PHYS_Falling )
  1894. Shoved.SetPhysics(PHYS_Falling);
  1895.  
  1896. Shoved.Velocity += normal(Shoved.Location - Location) * fclamp( 1.5 * ABS(VSize(Velocity)), 300, 2000 );
  1897. Shoved.Velocity.Z += fclamp(0.5 * ABS(VSize(Velocity)), 100, 666);
  1898.  
  1899. //Shoved.log(self$" shoved Shoved ("$Shoved$") and Shoved's speed is now "$ABS(VSize(Shoved.Velocity))$" while own speed is "$ABS(VSize(Velocity)));
  1900.  
  1901. if( FRand()<0.5 )
  1902. {
  1903. Shoved.PlayTakeHitSound(0, 'None', 2);
  1904. Shoved.PlayTakeHit(0.08, normal(Shoved.Location - Location) * Shoved.CollisionRadius, 0);
  1905.  
  1906. if( bCanSpeak && (TeamLeader==None || !TeamLeader.bTeamSpeaking) )
  1907. SpeakTo(Shoved);
  1908. }
  1909.  
  1910. if( TimerRate<=0 )
  1911. SetTimer(0.5, False); // Individual state timers will re-enable bump
  1912.  
  1913. Disable('Bump');
  1914. return True;
  1915. }
  1916. else
  1917. return False;
  1918. }
  1919.  
  1920.  
  1921. //======================================================================================================
  1922. // [4.2] BaseChange() - Now the stomper has to have more mass than the stompee for damage to occur
  1923. //======================================================================================================
  1924. singular event BaseChange()
  1925. {
  1926. local float decorMass;
  1927.  
  1928. if( Base==None && Physics==PHYS_None )
  1929. SetPhysics(PHYS_Falling);
  1930. else if( Pawn(Base)!=None )
  1931. {
  1932. if( Mass > Pawn(Base).Mass )
  1933. Base.TakeDamage( (1-Velocity.Z/400)* Mass/Base.Mass, Self,Location,0.5 * Velocity , 'stomped');
  1934. JumpOffPawn();
  1935. }
  1936. else if( Decoration(Base)!=None && Velocity.Z < -400 )
  1937. {
  1938. decorMass = FMax(Decoration(Base).Mass, 1);
  1939. Base.TakeDamage((-2* Mass/decorMass * Velocity.Z/400), Self, Location, 0.5 * Velocity, 'stomped');
  1940. }
  1941. }
  1942.  
  1943.  
  1944. //======================================================================================================
  1945. // [4.3] Bump() - Added ability to disable MeleeAttack here as well as pawn shoving
  1946. //======================================================================================================
  1947. function Bump( actor Other )
  1948. {
  1949. local vector VelDir, OtherDir;
  1950. local float speed;
  1951.  
  1952. if( ScriptedPawn(Other)!=None && bShoved(ScriptedPawn(Other)) ) // If the pawn is in the way, get it out of the way
  1953. return;
  1954.  
  1955. //---------------------------------------------------------------------------------
  1956. if( Enemy!=None )
  1957. {
  1958. if( !class'EXUStaticFuncs'.static.bHasPawnTag(self, 'NoMeleeAttack') )
  1959. {
  1960. if( Other==Enemy )
  1961. {
  1962. GotoState('MeleeAttack');
  1963. return;
  1964. }
  1965. else if( Pawn(Other)!=None && SetEnemy(Pawn(Other)) )
  1966. {
  1967. GotoState('MeleeAttack');
  1968. return;
  1969. }
  1970. }
  1971. }
  1972. else
  1973. {
  1974. if( Pawn(Other)!=None )
  1975. {
  1976. AnnoyedBy(Pawn(Other));
  1977. if( SetEnemy(Pawn(Other)) )
  1978. {
  1979. bReadyToAttack = True; //can melee right away
  1980. PlayAcquisitionSound();
  1981. GotoState('Attacking');
  1982. return;
  1983. }
  1984. }
  1985.  
  1986. if( TimerRate<=0 )
  1987. SetTimer(1.0, False);
  1988.  
  1989. if( bCanSpeak && ScriptedPawn(Other)!=None && (TeamLeader==None || !TeamLeader.bTeamSpeaking) )
  1990. SpeakTo(ScriptedPawn(Other));
  1991. }
  1992.  
  1993. //---------------------------------------------------------------------------------
  1994. Speed = VSize(Velocity);
  1995. if( Speed > 1 )
  1996. {
  1997. VelDir = Velocity / Speed;
  1998. VelDir.Z = 0;
  1999. OtherDir = Other.Location - Location;
  2000. OtherDir.Z = 0;
  2001. OtherDir = Normal(OtherDir);
  2002. if( (VelDir Dot OtherDir) > 0.8 )
  2003. {
  2004. /*if( Pawn(Other) == None )
  2005. {
  2006. MoveTimer = -1.0;
  2007. HitWall(-1 * OtherDir, Other);
  2008. } */
  2009. Velocity.X = VelDir.Y;
  2010. Velocity.Y = -1 * VelDir.X;
  2011. Velocity *= FMax(Speed, 280);
  2012. }
  2013. }
  2014.  
  2015. Disable('Bump');
  2016. }
  2017.  
  2018.  
  2019. //======================================================================================================
  2020. // [4.4] EncroachedBy() - Anti-Telefraggerization Backup Code - the primary means of resisting telefraggage is disc repulsion
  2021. //======================================================================================================
  2022. event EncroachedBy( actor Other )
  2023. {
  2024. if( Pawn(Other)!=None && XlocBlockMag==0 )
  2025. gibbedBy(Other);
  2026. else
  2027. /// <Bawss> this is really terrible code ill give you something better later
  2028. Other.Velocity += normal(Other.Location - Location) * 9000; // lollllllllll, definitely keeping this for posterity once something better is in!
  2029. }
  2030.  
  2031.  
  2032. //======================================================================================================
  2033. // [4.5] Touch() - Get that fuckin' Xloc disc off my ass
  2034. //======================================================================================================
  2035. simulated function Touch( actor Other )
  2036. {
  2037. local Actor e;
  2038. local vector Mag;
  2039.  
  2040. Super.Touch(Other);
  2041.  
  2042. if( TranslocatorTarget(Other)!=None && XlocBlockMag!=0 )
  2043. {
  2044. Mag = Normal(Other.OldLocation - Location) * abs(XlocBlockMag);
  2045.  
  2046. if( XlocBlockMag < 0 ) // Destroy the disc
  2047. Other.TakeDamage(99999, self, Location, mag, '');
  2048.  
  2049. e = Spawn(Class'XlocSmacker', Other,, Other.OldLocation); // Fling that fucker (temporary proxy class)
  2050. if( e!=None )
  2051. e.Velocity = Mag;
  2052.  
  2053. XlocBlockerEffect( Other.Location, Rotator(Other.Location - Location), XlocBlockMag < 0 );
  2054. XlocBlockSound( XlocBlockMag < 0 );
  2055. }
  2056. }
  2057.  
  2058.  
  2059. //======================================================================================================
  2060. // [4.6] XlocBlockerEffect() - Generate an effect when blocking Xloc disc
  2061. //======================================================================================================
  2062. simulated function XlocBlockerEffect( vector HitLocation, rotator LaunchDirection, bool bDestroyedDisc )
  2063. {
  2064. local class<Effects> BlockEffect;
  2065.  
  2066. if( bDestroyedDisc )
  2067. BlockEffect = class'XlocBlockDestroyed';
  2068. else
  2069. BlockEffect = class'XlocBlockStandard';
  2070.  
  2071. Spawn(BlockEffect,,, HitLocation, LaunchDirection); // Make some effect hapen. where doing it man
  2072. }
  2073.  
  2074.  
  2075. //======================================================================================================
  2076. // [4.7] XlocBlockSound() - Make a noise too!
  2077. //======================================================================================================
  2078. simulated function XlocBlockSound( bool bDestroyedDisc )
  2079. {
  2080. if( bDestroyedDisc )
  2081. {
  2082. PlaySound(EXUHitImmunity, SLOT_None, 8,,, 1.25);
  2083. PlaySound(EXUHitImmunity, SLOT_None, 8,,, 1.25);
  2084. }
  2085. else
  2086. {
  2087. PlaySound(EXUHitResistance, SLOT_None, 8,,, 1.25);
  2088. PlaySound(EXUHitResistance, SLOT_None, 8,,, 1.25);
  2089. }
  2090. }
  2091.  
  2092.  
  2093.  
  2094.  
  2095. //======================================================================================================================
  2096. // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
  2097. //======================================================================================================================
  2098. //
  2099. // SECTION 5: EPIC CODE TECHNICAL IMPROVEMENT / ACCESSED NONE PROTECTION
  2100. //
  2101. // [5.1] simulated function bool SafePlayAnim( name Sequence, optional float Rate, optional float TweenTime )
  2102. // [5.2] simulated function bool SafeTweenAnim( name Sequence, float Time )
  2103. // [5.3] simulated function bool SafeLoopAnim( name Sequence, optional float Rate, optional float TweenTime, optional float MinRate )
  2104. // [5.4] simulated function bool AdjustHitLocation(out vector HitLocation, vector TraceDir)
  2105. // [5.5] function bool ChooseTeamAttackFor(ScriptedPawn TeamMember)
  2106. // [5.6] function Trigger( actor Other, pawn EventInstigator )
  2107. // [5.7] state Charging
  2108. // [5.8] state MeleeAttack
  2109. // [5.9] state Retreating
  2110. // [5.10] state Guarding
  2111. // [5.11] state Patroling
  2112. // [5.12] state Waiting
  2113. // [5.13] state Roaming
  2114. // [5.14] state Greeting
  2115. // [5.15] state TriggerAlarm
  2116. // [5.16] state AlarmPaused
  2117. // [5.17] state VictoryDance
  2118. // [5.18] state StakeOut
  2119. //
  2120. //======================================================================================================================
  2121. // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
  2122. //======================================================================================================================
  2123.  
  2124.  
  2125. //======================================================================================================
  2126. // [5.1] SafePlayAnim() - Animate... SAFELY. Please be careful. This can be hazardous to your health
  2127. //======================================================================================================
  2128. simulated function bool SafePlayAnim( name Sequence, optional float Rate, optional float TweenTime )
  2129. {
  2130. if( DrawType!=DT_Mesh || Mesh==None || !HasAnim(Sequence) )
  2131. return False;
  2132.  
  2133. //if(sequence=='') //ill allow this
  2134. // return False;
  2135.  
  2136. PlayAnim(Sequence, Rate, TweenTime);
  2137.  
  2138. return True;
  2139. }
  2140.  
  2141.  
  2142. //======================================================================================================
  2143. // [5.2] SafeTweenAnim() - Tween safely or suffer
  2144. //======================================================================================================
  2145. simulated function bool SafeTweenAnim( name Sequence, float Time )
  2146. {
  2147. if( DrawType!=DT_Mesh || Mesh==None || !HasAnim(Sequence) )
  2148. return False;
  2149.  
  2150. TweenAnim(Sequence, Time);
  2151. return True;
  2152. }
  2153.  
  2154.  
  2155. //======================================================================================================
  2156. // [5.3] SafeLoopAnim() - Fruit loops inspected by the FDA
  2157. //======================================================================================================
  2158. simulated function bool SafeLoopAnim( name Sequence, optional float Rate, optional float TweenTime, optional float MinRate )
  2159. {
  2160. if( DrawType!=DT_Mesh || Mesh==None || !HasAnim(Sequence) )
  2161. return False;
  2162.  
  2163. LoopAnim(Sequence, Rate, TweenTime, MinRate);
  2164. return True;
  2165. }
  2166.  
  2167.  
  2168. //======================================================================================================
  2169. // [5.4] AdjustHitLocation() - Stuff happens maybe
  2170. //======================================================================================================
  2171. // Some stupid hardcoded anim bullshit from Pawn that needed to be rewritten GAT SDAMMDJEF
  2172. // rewritten my ass, you didnt even change anything :|
  2173. // Shit I can't even remember what I WAS going to do here
  2174. //======================================================================================================
  2175. simulated function bool AdjustHitLocation( out vector HitLocation, vector TraceDir )
  2176. {
  2177. local float adjZ, maxZ;
  2178.  
  2179. TraceDir = Normal(TraceDir);
  2180. HitLocation = HitLocation + 0.4 * CollisionRadius * TraceDir;
  2181.  
  2182. if ( (GetAnimGroup(AnimSequence) == 'Ducking') && (AnimFrame > -0.03) )
  2183. {
  2184. maxZ = Location.Z + 0.25 * CollisionHeight;
  2185. if ( HitLocation.Z > maxZ )
  2186. {
  2187. if ( TraceDir.Z >= 0 )
  2188. return False;
  2189. adjZ = (maxZ - HitLocation.Z)/TraceDir.Z;
  2190. HitLocation.Z = maxZ;
  2191. HitLocation.X = HitLocation.X + TraceDir.X * adjZ;
  2192. HitLocation.Y = HitLocation.Y + TraceDir.Y * adjZ;
  2193. if ( VSize(HitLocation - Location) > CollisionRadius )
  2194. return False;
  2195. }
  2196. }
  2197. return True;
  2198. }
  2199.  
  2200.  
  2201. //======================================================================================================================================
  2202. // [5.5] ChooseTeamAttackFor(someone doesn't understand English grammar) - because there were a shitload of Accessed Nones in Map 19 in here
  2203. //======================================================================================================================================
  2204. function bool ChooseTeamAttackFor( ScriptedPawn TeamMember )
  2205. {
  2206. if( TeamMember==None )
  2207. return False;
  2208.  
  2209. if( Enemy==None && TeamMember!=None && TeamMember.Enemy!=None && LineOfSightTo(TeamMember) ) // ANDS vWhatever
  2210. {
  2211. if( SetEnemy(TeamMember.Enemy) )
  2212. MakeNoise(1.0);
  2213. }
  2214.  
  2215. // speak order
  2216. if( !bTeamSpeaking )
  2217. SpeakOrderTo(TeamMember);
  2218.  
  2219. // set CombatStyle and Aggressiveness of TeamMember
  2220. if( TeamMember==Self )
  2221. {
  2222. ChooseLeaderAttack();
  2223. return True;
  2224. }
  2225.  
  2226. if( TeamMember.bReadyToAttack )
  2227. {
  2228. ////log("Attack!"); // lol what a shitty log line, we totally would have used something better. Also lol @ four slashes
  2229. TeamMember.Target = TeamMember.Enemy;
  2230.  
  2231. if(
  2232. TeamMember.Enemy!=None
  2233. && Enemy!=None
  2234. && VSize(Enemy.Location - Location) <= (TeamMember.MeleeRange + TeamMember.Enemy.CollisionRadius + TeamMember.CollisionRadius)
  2235. )
  2236. {
  2237. TeamMember.GotoState('MeleeAttack');
  2238. return True;
  2239. }
  2240. else if( TeamMember.bMovingRangedAttack || TeamMember.TeamID==1 )
  2241. TeamMember.SetTimer(TimeBetweenAttacks, False);
  2242. else if( TeamMember.bHasRangedAttack && (TeamMember.bIsPlayer || (TeamMember.Enemy!=None && TeamMember.Enemy.bIsPlayer)) && TeamMember.CanFireAtEnemy() )
  2243. {
  2244. if( !TeamMember.bIsPlayer || (3 * FRand() > Skill) )
  2245. {
  2246. TeamMember.GotoState('RangedAttack');
  2247. return True;
  2248. }
  2249. }
  2250. }
  2251.  
  2252. if( !TeamMember.bHasRangedAttack || TeamMember.TeamID==1 )
  2253. TeamMember.GotoState('Charging');
  2254. else if( TeamMember.TeamID==2 )
  2255. {
  2256. TeamMember.bStrafeDir = True;
  2257. TeamMember.GotoState('TacticalMove', 'NoCharge');
  2258. }
  2259. else if( TeamMember.TeamID==3 )
  2260. {
  2261. TeamMember.bStrafeDir = False;
  2262. TeamMember.GotoState('TacticalMove', 'NoCharge');
  2263. }
  2264. else
  2265. TeamMember.GotoState('TacticalMove');
  2266.  
  2267. return True;
  2268. }
  2269.  
  2270.  
  2271. //======================================================================================================
  2272. // [5.6] Trigger() - Fixed an accessed None
  2273. //======================================================================================================
  2274. function Trigger( actor Other, pawn EventInstigator )
  2275. {
  2276. local Pawn currentEnemy;
  2277.  
  2278. if( EventInstigator==None || Health<=0 || EventInstigator==Self )
  2279. return;
  2280.  
  2281. if( bHateWhenTriggered )
  2282. {
  2283. if( EventInstigator.bIsPlayer )
  2284. AttitudeToPlayer = ATTITUDE_Hate;
  2285. else
  2286. Hated = EventInstigator;
  2287.  
  2288. currentEnemy = Enemy;
  2289. SetEnemy(EventInstigator);
  2290.  
  2291. if( Enemy!=currentEnemy )
  2292. {
  2293. PlayAcquisitionSound();
  2294. GotoState('Attacking');
  2295. }
  2296. }
  2297. }
  2298.  
  2299.  
  2300. //======================================================================================================
  2301. // [5.7] Charging state - also modified for more control over strafing while Intelligence==BRAINS_Human
  2302. //======================================================================================================
  2303. state Charging
  2304. {
  2305. //======================================================================
  2306. function TakeDamage( int Damage, Pawn instigatedBy, Vector HitLocation, Vector momentum, name damageType )
  2307. {
  2308. local float pick;
  2309. local vector sideDir, extent;
  2310. local bool bWasOnGround;
  2311.  
  2312. bWasOnGround = (Physics == PHYS_Walking);
  2313. Global.TakeDamage(Damage, instigatedBy, HitLocation, momentum, damageType);
  2314.  
  2315. if( Health <= 0 )
  2316. return;
  2317.  
  2318. if( NextState=='TakeHit' )
  2319. {
  2320. if( AttitudeTo(Enemy)==ATTITUDE_Fear )
  2321. {
  2322. NextState = 'Retreating';
  2323. NextLabel = 'Begin';
  2324. }
  2325. else if( Intelligence > BRAINS_Mammal && bHasRangedAttack && bCanStrafe && StrafeFromDamage(momentum, Damage, damageType, False) )
  2326. {
  2327. NextState = 'TacticalMove';
  2328. NextLabel = 'NoCharge';
  2329. }
  2330. else
  2331. {
  2332. NextState = 'Charging';
  2333. NextLabel = 'TakeHit';
  2334. }
  2335. GotoState('TakeHit');
  2336. }
  2337. else if( Intelligence > BRAINS_Mammal && bHasRangedAttack && bCanStrafe && StrafeFromDamage(momentum, Damage, damageType, True) )
  2338. return;
  2339.  
  2340. else if( FRand() < WeaveFrequency && bWasOnGround && MoveTarget==Enemy && Physics==PHYS_Falling && Intelligence==BRAINS_Human )
  2341. {
  2342. pick = 1.0;
  2343. if( bStrafeDir )
  2344. pick = -1.0;
  2345. sideDir = Normal( Normal(Enemy.Location - Location) Cross vect(0,0,1) );
  2346. sideDir.Z = 0;
  2347. Velocity += pick * GroundSpeed * 0.7 * sideDir;
  2348. if( FRand() < 0.2 )
  2349. bStrafeDir = !bStrafeDir;
  2350. }
  2351. }
  2352.  
  2353. //======================================================================
  2354. function Timer()
  2355. {
  2356. bReadyToAttack = True;
  2357. Target = Enemy;
  2358.  
  2359. if(
  2360. VSize(Enemy.Location - Location) <= (MeleeRange + Enemy.CollisionRadius + CollisionRadius)
  2361. && !class'EXUStaticFuncs'.static.bHasPawnTag(self, 'NoMeleeAttack')
  2362. )
  2363. GotoState('MeleeAttack');
  2364. else if( bHasRangedAttack && (FRand() > 0.7 + 0.1 * Skill) )
  2365. GotoState('RangedAttack');
  2366. else if( bHasRangedAttack && !bMovingRangedAttack )
  2367. {
  2368. if( FRand() < CombatStyle * 0.8 ) //then keep charging
  2369. SetTimer(1.0, False);
  2370. else
  2371. GotoState('Attacking');
  2372. }
  2373. }
  2374.  
  2375. //------------------------------------
  2376. AdjustFromWall:
  2377. StrafeTo(Destination, Focus);
  2378. Goto('CloseIn');
  2379.  
  2380. //------------------------------------
  2381. ResumeCharge:
  2382. PlayRunning();
  2383. Goto('Charge');
  2384.  
  2385. //------------------------------------
  2386. Begin:
  2387. TweenToRunning(0.15);
  2388.  
  2389. //------------------------------------
  2390. Charge:
  2391. bFromWall = False;
  2392.  
  2393. //------------------------------------
  2394. CloseIn:
  2395. if( Enemy==None || Enemy.Health<=0 )
  2396. GotoState('Attacking');
  2397. else if( Enemy.Region.Zone.bWaterZone )
  2398. {
  2399. if( !bCanSwim )
  2400. GotoState('TacticalMove', 'NoCharge');
  2401. }
  2402. else if( !bCanFly && !bCanWalk )
  2403. GotoState('TacticalMove', 'NoCharge');
  2404.  
  2405.  
  2406. if( Enemy==None ) // ANDS 897908890y8y98
  2407. GoToState('Attacking');
  2408. else if( Physics==PHYS_Falling )
  2409. {
  2410. DesiredRotation = Rotator(Enemy.Location - Location);
  2411. Focus = Enemy.Location;
  2412. Destination = Enemy.Location;
  2413. WaitForLanding();
  2414. }
  2415.  
  2416.  
  2417. if( Enemy==None ) // ANDS 897908890y8y98
  2418. GoToState('Attacking');
  2419. else if( Intelligence <= BRAINS_Reptile || actorReachable(Enemy) )
  2420. {
  2421. bCanFire = True;
  2422. if( FRand() < 0.3 )
  2423. PlayThreateningSound();
  2424. MoveToward(Enemy);
  2425. if( bFromWall )
  2426. {
  2427. bFromWall = False;
  2428. if( PickWallAdjust() )
  2429. StrafeFacing(Destination, Enemy);
  2430. else
  2431. GotoState('TacticalMove', 'NoCharge');
  2432. }
  2433. }
  2434. else
  2435. {
  2436. //------------------------------------
  2437. NoReach:
  2438. bCanFire = False;
  2439. bFromWall = False;
  2440. //log("route to enemy "$Enemy);
  2441.  
  2442. if( Enemy == None ) // ANDS 7/18/12
  2443. GoToState('Attacking');
  2444. else if (!FindBestPathToward(Enemy))
  2445. {
  2446. Sleep(0.0);
  2447. GotoState('TacticalMove', 'NoCharge');
  2448. }
  2449. //------------------------------------
  2450. SpecialNavig:
  2451. if( SpecialPause > 0.0 )
  2452. {
  2453. bFiringPaused = True;
  2454. NextState = 'Charging';
  2455. NextLabel = 'Moving';
  2456. GotoState('RangedAttack');
  2457. }
  2458. //------------------------------------
  2459. Moving:
  2460. if( Enemy == None || MoveTarget == None ) // ANDS 7/19/12
  2461. GoToState('Attacking');
  2462.  
  2463. else if( VSize(MoveTarget.Location - Location) < 2.5 * CollisionRadius )
  2464. {
  2465. bCanFire = True;
  2466. StrafeFacing(MoveTarget.Location, Enemy);
  2467. }
  2468. else
  2469. {
  2470. if(
  2471. !bCanStrafe
  2472. || !LineOfSightTo(Enemy)
  2473. || (Skill - 2 * FRand() + (Normal(Enemy.Location - Location - vect(0,0,1) * (Enemy.Location.Z - Location.Z))
  2474. Dot Normal(MoveTarget.Location - Location - vect(0,0,1) * (MoveTarget.Location.Z - Location.Z))) < 0)
  2475. )
  2476. {
  2477. if( GetAnimGroup(AnimSequence)=='MovingAttack' )
  2478. {
  2479. AnimSequence = '';
  2480. TweenToRunning(0.12);
  2481. }
  2482. MoveToward(MoveTarget);
  2483. }
  2484. else
  2485. {
  2486. bCanFire = True;
  2487. StrafeFacing(MoveTarget.Location, Enemy);
  2488. }
  2489.  
  2490. if( !bFromWall && FRand()<0.5 )
  2491. PlayThreateningSound();
  2492. }
  2493. }
  2494.  
  2495. //log("finished move");
  2496. if( Enemy!=None && VSize(Location - Enemy.Location) < CollisionRadius + Enemy.CollisionRadius + MeleeRange )
  2497. Goto('GotThere');
  2498. else
  2499. GoToState('Attacking'); // ANDS 7/17/12
  2500.  
  2501.  
  2502. if( bIsPlayer || (!bFromWall && bHasRangedAttack && FRand() > CombatStyle + 0.1) )
  2503. GotoState('Attacking');
  2504. MoveTimer = 0.0;
  2505. bFromWall = False;
  2506. Goto('CloseIn');
  2507.  
  2508. //------------------------------------
  2509. GotThere:
  2510. ////log("Got to enemy");
  2511. if( Enemy==None || class'EXUStaticFuncs'.static.bHasPawnTag(self, 'NoMeleeAttack') ) // ANDS 7/18/12
  2512. GoToState('Attacking');
  2513. else
  2514. {
  2515. Target = Enemy;
  2516. GotoState('MeleeAttack');
  2517. }
  2518.  
  2519. //------------------------------------
  2520. TakeHit:
  2521. TweenToRunning(0.12);
  2522. if( Enemy!=None && MoveTarget!=None && MoveTarget==Enemy) // ANDS 7/19/12
  2523. {
  2524. bCanFire = True;
  2525. MoveToward(MoveTarget);
  2526. }
  2527. else
  2528. GoToState('Attacking');
  2529.  
  2530. Goto('Charge');
  2531. }
  2532.  
  2533.  
  2534. //======================================================================================================
  2535. // [5.8] MeleeAttack state - ACCESSED NONES SOMEWHERE FUCKING CAN SUCK A, WHATEVER, FUCK
  2536. //======================================================================================================
  2537. state MeleeAttack
  2538. {
  2539. ignores SeePlayer, HearNoise, Bump;
  2540.  
  2541. //======================================================================
  2542. function TakeDamage( int Damage, Pawn instigatedBy, vector HitLocation, vector Momentum, name damageType )
  2543. {
  2544. Global.TakeDamage(Damage, instigatedBy, HitLocation, Momentum, damageType);
  2545.  
  2546. if( Health<=0 )
  2547. return;
  2548.  
  2549. if( NextState=='TakeHit' )
  2550. {
  2551. NextState = 'MeleeAttack';
  2552. NextLabel = 'Begin';
  2553. }
  2554. }
  2555.  
  2556. //======================================================================
  2557. function KeepAttacking()
  2558. {
  2559. if( Enemy==None || Enemy.Health<=0 || (VSize(Enemy.Location - Location) > (MeleeRange + Enemy.CollisionRadius + CollisionRadius)) )
  2560. GotoState('Attacking');
  2561. }
  2562.  
  2563. //======================================================================
  2564. function EnemyNotVisible()
  2565. {
  2566. //log("enemy not visible");
  2567. GotoState('Attacking');
  2568. }
  2569.  
  2570. //======================================================================
  2571. function AnimEnd()
  2572. {
  2573. GotoState('MeleeAttack', 'DoneAttacking');
  2574. }
  2575.  
  2576. //======================================================================
  2577. function BeginState()
  2578. {
  2579. Target = Enemy;
  2580. Disable('AnimEnd');
  2581. bReadyToAttack = false;
  2582. }
  2583.  
  2584. //------------------------------------
  2585. Begin:
  2586. if( Enemy==None || Enemy.Health<=0 || Enemy.bDeleteMe || Enemy==self )
  2587. GotoState('Attacking');
  2588.  
  2589. DesiredRotation = Rotator(Enemy.Location - Location);
  2590.  
  2591. if( Skill < 3 )
  2592. TweenToFighter(0.15);
  2593. else
  2594. TweenToFighter(0.11);
  2595.  
  2596. //------------------------------------
  2597. FaceTarget:
  2598. if( Enemy==None || Enemy.Health<=0 || Enemy.bDeleteMe || Enemy==self )
  2599. GotoState('Attacking');
  2600.  
  2601. if( !bMovingMelee )
  2602. Acceleration = vect(0,0,0); //stop
  2603. //Acceleration = AccelRate * Normal(Enemy.Location - Location + 0.9 * VRand()); // testing slith-style accel
  2604.  
  2605. if( NeedToTurn(Enemy.Location) )
  2606. {
  2607. PlayTurning();
  2608. TurnToward(Enemy);
  2609. TweenToFighter(0.1);
  2610. }
  2611.  
  2612. FinishAnim();
  2613. OldAnimRate = 0; // force no tween
  2614.  
  2615. if( Physics==PHYS_Swimming || Physics==PHYS_Flying )
  2616. {
  2617. if( VSize(Location - Enemy.Location) > MeleeRange + CollisionRadius + Enemy.CollisionRadius )
  2618. GotoState('RangedAttack', 'ReadyToAttack');
  2619. }
  2620. 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) )
  2621. GotoState('RangedAttack', 'ReadyToAttack');
  2622.  
  2623. //------------------------------------
  2624. ReadyToAttack:
  2625. if( Enemy==None || Enemy.Health<=0 || Enemy.bDeleteMe || Enemy==self )
  2626. GotoState('Attacking');
  2627.  
  2628. Target = Enemy;
  2629. DesiredRotation = Rotator(Enemy.Location - Location);
  2630.  
  2631. PlayMeleeAttack();
  2632. Enable('AnimEnd');
  2633.  
  2634. //------------------------------------
  2635. Attacking:
  2636. TurnToward(Enemy);
  2637. Goto('Attacking');
  2638.  
  2639. //------------------------------------
  2640. DoneAttacking:
  2641. Disable('AnimEnd');
  2642. KeepAttacking();
  2643.  
  2644. if( Enemy==None || Enemy.Health<=0 || Enemy.bDeleteMe || Enemy==self )
  2645. GotoState('Attacking');
  2646.  
  2647. if( FRand() < 0.3 - 0.1 * Skill )
  2648. {
  2649. if( !bMovingMelee )
  2650. Acceleration = vect(0,0,0); //stop
  2651.  
  2652. DesiredRotation = Rotator(Enemy.Location - Location);
  2653. PlayChallenge();
  2654. FinishAnim();
  2655. TweenToFighter(0.1);
  2656. }
  2657.  
  2658. Goto('FaceTarget');
  2659. }
  2660.  
  2661.  
  2662. //======================================================================================================
  2663. // [5.9] Retreating state - RUN AWAY YOU FUCKING COWARDS
  2664. //======================================================================================================
  2665. state Retreating
  2666. {
  2667. ignores SeePlayer, EnemyNotVisible, HearNoise;
  2668.  
  2669. //====================================================================
  2670. function PickNextSpot()
  2671. {
  2672. local Actor path;
  2673. local vector dist2d;
  2674. local float zdiff;
  2675.  
  2676. if( Home == None )
  2677. {
  2678. PickDestination();
  2679. if( Home == None )
  2680. return;
  2681. }
  2682.  
  2683. //log("find retreat spot");
  2684. dist2d = Home.Location - Location;
  2685. zdiff = dist2d.Z;
  2686. dist2d.Z = 0.0;
  2687.  
  2688. if( (VSize(dist2d) < 2 * CollisionRadius) && (Abs(zdiff) < CollisionHeight) )
  2689. ReachedHome();
  2690. else
  2691. {
  2692. if( ActorReachable(Home) )
  2693. {
  2694. //log("almost there");
  2695. path = Home;
  2696. if (HomeBase(Home) == None)
  2697. Home = None;
  2698. }
  2699. else
  2700. {
  2701. if( SpecialGoal!=None )
  2702. path = FindPathToward(SpecialGoal);
  2703. else
  2704. path = FindPathToward(Home);
  2705. }
  2706.  
  2707. if( Path == None )
  2708. ChangeDestination();
  2709. else
  2710. {
  2711. MoveTarget = path;
  2712. Destination = path.Location;
  2713. }
  2714. }
  2715. }
  2716.  
  2717.  
  2718. //====================================================================
  2719. function Bump( actor Other )
  2720. {
  2721. local vector VelDir, OtherDir;
  2722. local float speed;
  2723.  
  2724. if( ScriptedPawn(Other)!=None && bShoved(ScriptedPawn(Other)) )
  2725. return;
  2726.  
  2727. if( Pawn(Other)!=None )
  2728. {
  2729. if( Other==Enemy || SetEnemy(Pawn(Other)) )
  2730. GotoState('MeleeAttack');
  2731. else if( HomeBase(Home)!=None && (VSize(Location - Home.Location) < HomeBase(Home).Extent) )
  2732. ReachedHome();
  2733. return;
  2734. }
  2735.  
  2736. if( TimerRate<=0 )
  2737. SetTimer(1.0, False);
  2738.  
  2739. Speed = VSize(Velocity);
  2740. if( Speed > 1 )
  2741. {
  2742. VelDir = Velocity/speed;
  2743. VelDir.Z = 0;
  2744. OtherDir = Other.Location - Location;
  2745. OtherDir.Z = 0;
  2746. OtherDir = Normal(OtherDir);
  2747. if( (VelDir Dot OtherDir) > 0.9 )
  2748. {
  2749. Velocity.X = VelDir.Y;
  2750. Velocity.Y = -1 * VelDir.X;
  2751. Velocity *= FMax(speed, 200);
  2752. }
  2753. }
  2754.  
  2755. Disable('Bump');
  2756. }
  2757.  
  2758. //------------------------------------
  2759. Begin:
  2760. //log(class$" retreating");
  2761. if( bReadyToAttack && FRand()<0.6 )
  2762. {
  2763. SetTimer(TimeBetweenAttacks, False);
  2764. bReadyToAttack = False;
  2765. }
  2766. TweenToRunning(0.1);
  2767. WaitForLanding();
  2768. PickDestination();
  2769.  
  2770. //------------------------------------
  2771. Landed:
  2772. TweenToRunning(0.1);
  2773.  
  2774. //------------------------------------
  2775. RunAway:
  2776. PickNextSpot();
  2777.  
  2778. //------------------------------------
  2779. SpecialNavig:
  2780. if( SpecialPause > 0.0 )
  2781. {
  2782. if( Enemy!=None && LineOfSightTo(Enemy) ) // ANDS r793784t892389
  2783. {
  2784. bFiringPaused = True;
  2785. NextState = 'Retreating';
  2786. NextLabel = 'Moving';
  2787. GotoState('RangedAttack');
  2788. }
  2789.  
  2790. bSpecialPausing = True;
  2791. Acceleration = vect(0,0,0);
  2792. TweenToPatrolStop(0.25);
  2793.  
  2794. Sleep(SpecialPause);
  2795. SpecialPause = 0.0;
  2796. bSpecialPausing = False;
  2797. TweenToRunning(0.1);
  2798. }
  2799.  
  2800. //------------------------------------
  2801. Moving:
  2802. if( Enemy==None ) // ANDS 897r98y8u
  2803. {
  2804. GoToState('Attacking');
  2805. //Sleep(0.0);
  2806. //WhatToDoNext('','');
  2807. }
  2808. else if( MoveTarget==None )
  2809. {
  2810. Sleep(0.0);
  2811. Goto('RunAway');
  2812. }
  2813. else if(
  2814. !bCanStrafe
  2815. || !LineOfSightTo(Enemy)
  2816. || (Skill - 2 * FRand() + (Normal(Enemy.Location - Location - vect(0,0,1) * (Enemy.Location.Z - Location.Z))
  2817. Dot Normal(MoveTarget.Location - Location - vect(0,0,1) * (MoveTarget.Location.Z - Location.Z))) < 0)
  2818. )
  2819. {
  2820. bCanFire = False;
  2821. MoveToward(MoveTarget);
  2822. }
  2823. else
  2824. {
  2825. bCanFire = True;
  2826. StrafeFacing(MoveTarget.Location, Enemy);
  2827. }
  2828.  
  2829. Goto('RunAway');
  2830.  
  2831. //------------------------------------
  2832. TakeHit:
  2833. TweenToRunning(0.12);
  2834. Goto('Moving');
  2835.  
  2836. //------------------------------------
  2837. AdjustFromWall:
  2838. StrafeTo(Destination, Focus);
  2839. Destination = Focus;
  2840. MoveTo(Destination);
  2841. Goto('Moving');
  2842.  
  2843. //------------------------------------
  2844. TurnAtHome:
  2845. Acceleration = vect(0,0,0);
  2846. if( HomeBase(Home)!=None ) // ANDS 8979786765t6
  2847. TurnTo(Homebase(Home).lookdir);
  2848. GotoState('Ambushing', 'FindAmbushSpot');
  2849. }
  2850.  
  2851.  
  2852. //======================================================================================================
  2853. // [5.10] Guarding state - Guard against accessed Nones. I hate them. I hate them all. And I HATE YOU TOO, FUCK OFF
  2854. //======================================================================================================
  2855. state Guarding
  2856. {
  2857. //======================================================================
  2858. function TakeDamage( int Damage, Pawn instigatedBy, Vector HitLocation, Vector momentum, name damageType )
  2859. {
  2860. //////////////////////////////////////////////////////////////////////////
  2861. // D U M B //
  2862. // if (InstigatedBy==None || enemy==None) // hahahaha wow this was utterly retarded wasn't it
  2863. // return; // good thing we fixed that before Demo 4 launched
  2864. // S H I T //
  2865. //////////////////////////////////////////////////////////////////////////
  2866.  
  2867. if(Enemy!=None) // there. that is better
  2868. LastSeenPos = Enemy.Location;
  2869. Global.TakeDamage(Damage, instigatedBy, HitLocation, momentum, damageType);
  2870. if ( health <= 0 || Enemy==None ) // and that is betterer
  2871. return;
  2872. if (NextState == 'TakeHit')
  2873. {
  2874. NextState = 'Attacking';
  2875. NextLabel = 'Begin';
  2876. GotoState('TakeHit');
  2877. }
  2878. else if ( Enemy != None ) // HEY NOW, THE ENEMY COULD DIE BEFORE THIS FUNCTION FINISHES! THIS IS EXU AFTER ALL! SHUT THE FUCK UP
  2879. GotoState('Attacking');
  2880. }
  2881.  
  2882. //------------------------------------
  2883. AdjustFromWall:
  2884. StrafeTo(Destination, Focus);
  2885. Destination = Focus;
  2886. MoveTo(Destination);
  2887. Goto('GoToGuard');
  2888.  
  2889. //------------------------------------
  2890. Begin:
  2891. if(OrderObject==None)
  2892. GoToState('Waiting');
  2893.  
  2894. //log(self$" guarding "$OrderObject, 'DISCORDULOGGER');
  2895. Disable('AnimEnd');
  2896.  
  2897. //------------------------------------
  2898. GoToGuard:
  2899. if ( VSize(Location - OrderObject.Location) < 2 * CollisionRadius)
  2900. Goto('Turn');
  2901. TweenToRunning(0.2);
  2902. FinishAnim();
  2903. PlayRunning();
  2904. WaitForLanding();
  2905. if (actorReachable(OrderObject))
  2906. MoveToward(OrderObject, FMax(0.75, WalkingSpeed));
  2907. else
  2908. {
  2909. PickDestination();
  2910. //------------------------------------
  2911. SpecialNavig:
  2912. if (SpecialPause > 0.0)
  2913. {
  2914. Acceleration = vect(0,0,0);
  2915. TweenToPatrolStop(0.3);
  2916. Sleep(SpecialPause);
  2917. SpecialPause = 0.0;
  2918. TweenToRunning(0.1);
  2919. FinishAnim();
  2920. PlayRunning();
  2921. }
  2922. MoveToward(MoveTarget);
  2923. }
  2924. Goto('GoToGuard');
  2925.  
  2926. //------------------------------------
  2927. Turn:
  2928. //log(class$" got to guardpoint");
  2929. Acceleration = vect(0,0,0);
  2930. TweenToFighter(0.3);
  2931. FinishAnim();
  2932. PlayTurning();
  2933. TurnTo( Location + 1000 * vector(OrderObject.Rotation) );
  2934.  
  2935. NextAnim = '';
  2936. bReadyToAttack = False;
  2937. TweenToPatrolStop(0.2);
  2938. FinishAnim();
  2939. Enable('AnimEnd');
  2940. NextAnim = '';
  2941. PlayPatrolStop();
  2942. DesiredRotation = rot(0,0,0);
  2943. DesiredRotation.Yaw = Rotation.Yaw;
  2944. setRotation(DesiredRotation);
  2945. if (Physics != PHYS_Falling)
  2946. SetPhysics(PHYS_None);
  2947. }
  2948.  
  2949.  
  2950. //======================================================================================================
  2951. // [5.11] Patroling state - Changed the text here because it was so dumb it started to annoy me well before EXU was even finished
  2952. //======================================================================================================
  2953. state Patroling
  2954. {
  2955. //====================================================================
  2956. function TakeDamage( int Damage, Pawn instigatedBy, Vector HitLocation, Vector momentum, name damageType )
  2957. {
  2958. //////////////////////////////////////////////////////////////////////////
  2959. // D U M B //
  2960. // if (InstigatedBy==None || enemy==None) // Saving this as a piece of history of unwise decisions of the waffle
  2961. // return; // cause god damn, lol, look at this retardation
  2962. // S H I T //
  2963. //////////////////////////////////////////////////////////////////////////
  2964.  
  2965. Global.TakeDamage(Damage, instigatedBy, HitLocation, momentum, damageType);
  2966. if ( health <= 0 || Enemy==None ) // updated Accessed None protection
  2967. return;
  2968. LastSeenPos = Enemy.Location;
  2969. if (NextState == 'TakeHit')
  2970. {
  2971. NextState = 'Attacking';
  2972. NextLabel = 'Begin';
  2973. GotoState('TakeHit');
  2974. }
  2975. else if ( Enemy != None )
  2976. GotoState('Attacking');
  2977. }
  2978. }
  2979.  
  2980.  
  2981. //======================================================================================================
  2982. // [5.12] Waiting state -
  2983. //======================================================================================================
  2984. state Waiting
  2985. {
  2986. //====================================================================
  2987. function Bump( actor Other )
  2988. {
  2989. if( ScriptedPawn(Other)!=None && bShoved(ScriptedPawn(Other)) )
  2990. return;
  2991.  
  2992. if( Pawn(Other)!=None )
  2993. {
  2994. if( Enemy==Other )
  2995. bReadyToAttack = True; //can melee right away
  2996. SetEnemy(Pawn(Other));
  2997. }
  2998.  
  2999. if( TimerRate<=0 )
  3000. SetTimer(1.5, False);
  3001.  
  3002. Disable('Bump');
  3003. }
  3004. }
  3005.  
  3006.  
  3007. //======================================================================================================
  3008. // [5.13] Roaming state -
  3009. //======================================================================================================
  3010. state Roaming
  3011. {
  3012. ignores EnemyNotVisible;
  3013.  
  3014. //====================================================================
  3015. function Bump( actor Other )
  3016. {
  3017. if( ScriptedPawn(Other)!=None && bShoved(ScriptedPawn(Other)) )
  3018. return;
  3019.  
  3020. if( FRand()<0.03 )
  3021. GotoState('Wandering');
  3022. else
  3023. Super.Bump(Other);
  3024. }
  3025. }
  3026.  
  3027.  
  3028. //======================================================================================================
  3029. // [5.14] Greeting state -
  3030. //======================================================================================================
  3031. state Greeting
  3032. {
  3033. ignores SeePlayer, EnemyNotVisible;
  3034.  
  3035. //====================================================================
  3036. function Bump( actor Other )
  3037. {
  3038. if( ScriptedPawn(Other)!=None && bShoved(ScriptedPawn(Other)) )
  3039. return;
  3040.  
  3041. if( Pawn(Other)!=None && Enemy!=Other )
  3042. SetEnemy(Pawn(Other));
  3043.  
  3044. if( TimerRate<=0 )
  3045. SetTimer(1.0, False);
  3046.  
  3047. Disable('Bump');
  3048. }
  3049. }
  3050.  
  3051.  
  3052. //======================================================================================================
  3053. // [5.15] TriggerAlarm state -
  3054. //======================================================================================================
  3055. State TriggerAlarm
  3056. {
  3057. ignores HearNoise, SeePlayer;
  3058.  
  3059. //====================================================================
  3060. function Bump( actor Other )
  3061. {
  3062. local vector VelDir, OtherDir;
  3063. local float speed;
  3064.  
  3065. if( ScriptedPawn(Other)!=None && bShoved(ScriptedPawn(Other)) )
  3066. return;
  3067.  
  3068. if( Other==OrderObject )
  3069. {
  3070. AlarmDone();
  3071. if( Pawn(Other)!=None && SetEnemy(Pawn(Other)) )
  3072. GotoState('MeleeAttack');
  3073. return;
  3074. }
  3075.  
  3076. if( Other==Enemy || SetEnemy(Pawn(Other)) )
  3077. {
  3078. GotoState('MeleeAttack');
  3079. return;
  3080. }
  3081.  
  3082. if( TimerRate<=0 )
  3083. SetTimer(1.0, False);
  3084.  
  3085. Speed = VSize(Velocity);
  3086. if( Speed > 1 )
  3087. {
  3088. VelDir = Velocity / Speed;
  3089. VelDir.Z = 0;
  3090. OtherDir = Other.Location - Location;
  3091. OtherDir.Z = 0;
  3092. OtherDir = Normal(OtherDir);
  3093. if( (VelDir Dot OtherDir) > 0.9 )
  3094. {
  3095. Velocity.X = VelDir.Y;
  3096. Velocity.Y = -1 * VelDir.X;
  3097. Velocity *= FMax(Speed, 200);
  3098. }
  3099. }
  3100.  
  3101. Disable('Bump');
  3102. }
  3103. }
  3104.  
  3105.  
  3106. //======================================================================================================
  3107. // [5.16] AlarmPaused state -
  3108. //======================================================================================================
  3109. state AlarmPaused
  3110. {
  3111. ignores HearNoise;
  3112.  
  3113. //====================================================================
  3114. function Bump( actor Other )
  3115. {
  3116. if( ScriptedPawn(Other)!=None && bShoved(ScriptedPawn(Other)) )
  3117. return;
  3118.  
  3119. if( Other==Enemy )
  3120. GotoState('MeleeAttack');
  3121. else if( Pawn(Other)!=None && SetEnemy(Pawn(Other)) )
  3122. GotoState('MeleeAttack');
  3123. Disable('Bump');
  3124. }
  3125. }
  3126.  
  3127.  
  3128. //======================================================================================================
  3129. // [5.17] VictoryDance state -
  3130. //======================================================================================================
  3131. // VictoryDanceMKII!!!!!! The amazing version without accessed None potential
  3132. // ^ still accessed None
  3133. // FUCKING GOD DAMN IT!!!!! >:E >:E >:E
  3134. //======================================================================================================
  3135. state VictoryDance
  3136. {
  3137. ignores EnemyNotVisible;
  3138.  
  3139. //======================================================================
  3140. function TakeDamage( int Damage, Pawn instigatedBy, Vector HitLocation, Vector momentum, name damageType )
  3141. {
  3142. Global.TakeDamage(Damage, instigatedBy, HitLocation, momentum, damageType);
  3143. if ( health <= 0 )
  3144. return;
  3145.  
  3146. if(instigatedBy!=None) // possibly removing the last bit of accessed nonnery? Who knows man. Added 4/28/11. April is the cruelest month
  3147. Enemy = instigatedBy;
  3148.  
  3149. if ( NextState == 'TakeHit' )
  3150. {
  3151. NextState = 'Attacking'; //default
  3152. NextLabel = 'Begin';
  3153. GotoState('TakeHit');
  3154. }
  3155. else if (health > 0)
  3156. GotoState('Attacking');
  3157. }
  3158.  
  3159. //------------------------------------
  3160. Begin:
  3161. if ( (Target == None) || (VSize(Location - Target.Location) < (1.3 * CollisionRadius + Target.CollisionRadius + CollisionHeight - Target.CollisionHeight)) )
  3162. Goto('Taunt');
  3163. else
  3164. {
  3165. Destination = Target.Location;
  3166. TweenToWalking(0.3);
  3167. FinishAnim();
  3168. PlayWalking();
  3169. Enable('Bump');
  3170. }
  3171.  
  3172. //------------------------------------
  3173. MoveToEnemy:
  3174. WaitForLanding();
  3175. PickDestination();
  3176. if (SpecialPause > 0.0)
  3177. {
  3178. Acceleration = vect(0,0,0);
  3179. TweenToPatrolStop(0.3);
  3180. Sleep(SpecialPause);
  3181. SpecialPause = 0.0;
  3182. TweenToWalking(0.1);
  3183. FinishAnim();
  3184. PlayWalking();
  3185. }
  3186. MoveToward(MoveTarget, WalkingSpeed);
  3187. Enable('Bump');
  3188. If (target==None || VSize(Location - Target.Location) < (1.3 * CollisionRadius + Target.CollisionRadius + Abs(CollisionHeight - Target.CollisionHeight)))
  3189. Goto('Taunt');
  3190. else
  3191. Goto('MoveToEnemy');
  3192.  
  3193. //------------------------------------
  3194. Taunt:
  3195. Acceleration = vect(0,0,0);
  3196. TweenToFighter(0.2);
  3197. FinishAnim();
  3198. PlayTurning();
  3199. if(Target!=None) // accessed None defense MKIIIIIIIIIIIIIIIIIIII
  3200. TurnToward(Target);
  3201. DesiredRotation = rot(0,0,0);
  3202. DesiredRotation.Yaw = Rotation.Yaw;
  3203. setRotation(DesiredRotation);
  3204. TweenToFighter(0.2);
  3205. FinishAnim();
  3206. PlayVictoryDance();
  3207. FinishAnim();
  3208. WhatToDoNext('Waiting','TurnFromWall');
  3209. }
  3210.  
  3211.  
  3212. //======================================================================================================
  3213. // [5.18] StakeOut state - More like SteakOut
  3214. //======================================================================================================
  3215. // I think I found the accessed None here. Maybe. We'll see I guess
  3216. //======================================================================================================
  3217. state StakeOut
  3218. {
  3219. ignores EnemyNotVisible;
  3220.  
  3221. //======================================================================
  3222. function rotator AdjustAim( float ProjSpeed, vector projStart, int aimerror, bool leadTarget, bool warnTarget )
  3223. {
  3224. local rotator FireRotation;
  3225. local vector FireSpot;
  3226. local actor HitActor;
  3227. local vector HitLocation, HitNormal;
  3228.  
  3229. FireSpot = LastSeenPos;
  3230. aimerror = aimerror * (0.5 * (4 - skill - FRand()));
  3231.  
  3232. HitActor = Trace(HitLocation, HitNormal, FireSpot, ProjStart, False);
  3233. if( HitActor != None )
  3234. {
  3235. ////log("adjust aim up");
  3236.  
  3237. if(Target!=None) // Accessed None Defense System v. FuckOff
  3238. FireSpot.Z += 0.9 * Target.CollisionHeight;
  3239.  
  3240. HitActor = Trace(HitLocation, HitNormal, FireSpot, ProjStart, False);
  3241. bClearShot = (HitActor == None);
  3242. }
  3243.  
  3244. FireRotation = Rotator(FireSpot - ProjStart);
  3245.  
  3246. FireRotation.Yaw = FireRotation.Yaw + 0.5 * (Rand(2 * aimerror) - aimerror);
  3247. viewRotation = FireRotation;
  3248. return FireRotation;
  3249. }
  3250. }
  3251.  
  3252.  
  3253.  
  3254.  
  3255. //======================================================================================================================
  3256. // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
  3257. //======================================================================================================================
  3258. //
  3259. // SECTION 6: NEW DAMAGE EFFECTS AND CARCASS STUFF
  3260. //
  3261. // [6.1] function TakeDamage( int Damage, Pawn instigatedBy, Vector HitLocation, Vector momentum, name damageType )
  3262. // [6.2] simulated function GenerateImpactEffect(float F, vector HitLocation, pawn InstigatedBy, name damageType, int ActualDamage)
  3263. // [6.3] function PlayHit(float Damage, vector HitLocation, name damageType, vector Momentum)
  3264. // [6.4] function PlayDeathHit( float Damage, vector HitLocation, name damageType, vector Momentum )
  3265. // [6.5] function Died( pawn Killer, name damageType, vector HitLocation )
  3266. // [6.6] function Carcass SpawnCarcass()
  3267. // [6.7] function SpawnGibbedCarcass()
  3268. // [6.8] function bool Gibbed( name damageType )
  3269. // [6.9] function ExtraDeathStuff()
  3270. // [6.10] function ClientDeathStuff()
  3271. //
  3272. //======================================================================================================================
  3273. // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
  3274. //======================================================================================================================
  3275.  
  3276.  
  3277. //===============================================================================================================
  3278. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  3279. //
  3280. // [6.1] TakeDamage() - TakeDamage ADVANCED: supports weakness/resistance types, healing damage, and more stuff
  3281. //
  3282. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  3283. //===============================================================================================================
  3284. function TakeDamage( int Damage, Pawn instigatedBy, Vector HitLocation, Vector momentum, name damageType )
  3285. {
  3286. local int actualDamage, i, HealAmount;
  3287. local bool bAlreadyDead, bNoPhysics;
  3288. local name DamageNM;
  3289. local float DamagePct;
  3290.  
  3291. if( Role < ROLE_Authority )
  3292. {
  3293. log(self$" client damage type "$damageType$" by "$instigatedBy,'GODFUCKINGDAMNITMANDONTDOTHIS');
  3294. return;
  3295. }
  3296.  
  3297. if( bEnableDamageLoggers )
  3298. log(self$" with "$Health$" health initially took "$damage$" "$damagetype$" damage",'DISCORDUDAMAGELOGGER');
  3299.  
  3300. bAlreadyDead = Health <= 0;
  3301. bNoPhysics = class'EXUStaticFuncs'.Static.bHasPawnTag(self, 'NoDamagePhysics');
  3302.  
  3303. if( !bNoPhysics )
  3304. {
  3305. if( Physics==PHYS_None )
  3306. SetMovementPhysics();
  3307. if( Physics==PHYS_Walking )
  3308. Momentum.Z = FMax(Momentum.Z, 0.4 * VSize(Momentum));
  3309. if( instigatedBy==self )
  3310. Momentum *= 0.6;
  3311. Momentum = Momentum/Mass;
  3312. }
  3313.  
  3314. //===================================================================
  3315. // // // // Damage calculation stuff \\ \\ \\
  3316. //===================================================================
  3317. actualDamage = Level.Game.ReduceDamage(Damage, DamageType, self, instigatedBy) * HellDamageScale;
  3318.  
  3319. //===================================================================
  3320. if( bIsPlayer )
  3321. {
  3322. if( ReducedDamageType=='All' ) //God mode
  3323. actualDamage = 0;
  3324. else if( Inventory!=None ) //then check if carrying armor
  3325. actualDamage = Inventory.ReduceDamage(actualDamage, DamageType, HitLocation);
  3326. else
  3327. actualDamage = Damage;
  3328. }
  3329.  
  3330. //===================================================================
  3331. for( i=-1; i < DamageTypesTracker; i++ )
  3332. {
  3333.  
  3334. if( i==-1 )
  3335. DamageNM = ReducedDamageType;
  3336. else
  3337. DamageNM = DamageTypes[i];
  3338.  
  3339. if( DamageNM!='' && DamageNM!='None' )
  3340. {
  3341. if( i==-1 )
  3342. DamagePct = 1.0 - ReducedDamagePct;
  3343. else
  3344. DamagePct = DamageScales[i];
  3345.  
  3346. if( DamageNM=='All' || DamageNM==damageType )
  3347. {
  3348. ActualDamage = float(ActualDamage) * DamagePct;
  3349. GenerateImpactEffect(DamagePct, HitLocation, InstigatedBy, damageType, ActualDamage);
  3350. break; //found a valid damage modifier, break loop
  3351. }
  3352. }
  3353. else if( i>=0 )
  3354. {
  3355. // 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
  3356. break;
  3357. }
  3358. }
  3359.  
  3360. //===================================================================
  3361. // Handle stun damage
  3362. //===================================================================
  3363. if( damageType=='Stunned' && ActualDamage > 0 )
  3364. {
  3365. StunLength += (ActualDamage * 0.01);
  3366. StunnedRotation = Rotation;
  3367.  
  3368. PlayHit(actualDamage, HitLocation, damageType, Momentum);
  3369. ActualDamage = 0;
  3370. GoToState('StunnedState');
  3371.  
  3372. //log(self$" stunned for "$StunLength$" seconds - ActualDamage is "$ActualDamage);
  3373. }
  3374.  
  3375. //===================================================================
  3376. // Hell Gun damage stacking support. Sorta hacky but it works
  3377. //===================================================================
  3378. else if(
  3379. damageType=='Hell'
  3380. && instigatedBy!=None
  3381. && instigatedBy.bIsPawn
  3382. && instigatedBy.Weapon!=None
  3383. && (instigatedBy.Weapon.MyDamageType=='Hell' && instigatedBy.Weapon.AltDamageType=='Hell')
  3384. )
  3385. {
  3386. HellDamageScale += ActualDamage * 0.0001;
  3387. //log(self$" HellDamageScale is now "$HellDamageScale);
  3388. }
  3389.  
  3390. //================================================
  3391. // Check self-damage and friendly damage here
  3392. //================================================
  3393. if( SelfDamageScale!=1.0 && instigatedBy==Self )
  3394. ActualDamage = float(ActualDamage) * SelfDamageScale;
  3395. else if(
  3396. FriendlyDamageScale!=1.0
  3397. && EXUScriptedPawn(instigatedBy)!=None
  3398. && EXUScriptedPawn(instigatedBy).default.TeamTag == Self.default.TeamTag
  3399. )
  3400. ActualDamage = float(ActualDamage) * FriendlyDamageScale;
  3401.  
  3402. if( Level.Game.DamageMutator!=None )
  3403. Level.Game.DamageMutator.MutatorTakeDamage( ActualDamage, Self, InstigatedBy, HitLocation, Momentum, DamageType );
  3404.  
  3405. if( !bNoPhysics && Mass < 1000000 )
  3406. AddVelocity( Momentum );
  3407.  
  3408.  
  3409. //===================================================================
  3410. // If the pawn takes negative damage (heals), ensure that the healing
  3411. // cap is nonzero and that it isn't exceeded.
  3412. // Negative cap = no health cap
  3413. //===================================================================
  3414. if( ActualDamage < 0 )
  3415. {
  3416. if( MaxHealingScale!=0 ) // do some healin
  3417. {
  3418. HealAmount = -ActualDamage;
  3419. if( Health < StartingHealth * MaxHealingScale || MaxHealingScale < 0 )
  3420. {
  3421. Health += HealAmount;
  3422. if( MaxHealingScale > 0 && Health > StartingHealth * MaxHealingScale )
  3423. Health = StartingHealth * MaxHealingScale;
  3424.  
  3425. // Increase score for pawns that can superheal, but don't decrease it when health decreases later on
  3426. if( Health > StartingHealth && (MaxHealingScale < 0 || InitialPointValue * MaxHealingScale > PointValue) )
  3427. PointValue += 5 * (Health / StartingHealth);
  3428. }
  3429. }
  3430. else
  3431. ActualDamage = 0; // MaxHealingScale=0, no healing
  3432. }
  3433. else
  3434. Health -= actualDamage; // *** Subtract actual damage from health (or add it if negative) ***
  3435. //===================================================================
  3436.  
  3437. if( CarriedDecoration!=None )
  3438. DropDecoration();
  3439.  
  3440. if( HitLocation==vect(0,0,0) )
  3441. HitLocation = Location;
  3442.  
  3443.  
  3444. // *** Figure out if dead or not based on new health, then decide what to do ***
  3445. if( Health > 0 )
  3446. {
  3447. if( instigatedBy!=None && instigatedBy!=Self )
  3448. damageAttitudeTo(instigatedBy);
  3449.  
  3450. if( ActualDamage > 0 && !bNoPhysics )
  3451. PlayHit(ActualDamage, HitLocation, DamageType, Momentum);
  3452. }
  3453. else if( !bAlreadyDead )
  3454. {
  3455. NextState = '';
  3456. PlayDeathHit(ActualDamage, HitLocation, DamageType, Momentum);
  3457.  
  3458. ///FIXME - my god this shit is dumb, ill find a better solution later that still permits easy gibbing
  3459. if( ActualDamage > Mass )
  3460. Health = -1 * ActualDamage;
  3461.  
  3462. if( InstigatedBy!=None && InstigatedBy!=Self )
  3463. DamageAttitudeTo(InstigatedBy);
  3464.  
  3465. Died(InstigatedBy, DamageType, HitLocation);
  3466. }
  3467. else
  3468. {
  3469. //Warn(self$" took regular damage "$damagetype$" from "$instigator$" while already dead"); // lol
  3470. // SpawnGibbedCarcass();
  3471. if( bIsPlayer )
  3472. {
  3473. HidePlayer();
  3474. GotoState('Dying');
  3475. }
  3476. else
  3477. Destroy();
  3478. }
  3479.  
  3480. MakeNoise(1.0);
  3481.  
  3482. if( bEnableDamageLoggers )
  3483. log(self$" now has "$Health$" health: took "$ActualDamage$" "$damagetype$" damage",'DISCORDUDAMAGELOGGER');
  3484. }
  3485.  
  3486.  
  3487. //===============================================================================================================
  3488. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  3489. //
  3490. // [6.2] GenerateImpactEffect() - creates flashes for healing/weakness/resistance/immunity damage
  3491. //
  3492. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  3493. //===============================================================================================================
  3494. simulated function GenerateImpactEffect( float F, vector HitLocation, pawn InstigatedBy, name damageType, int ActualDamage )
  3495. {
  3496. local bool bFlashReady;
  3497. local float s;
  3498.  
  3499. //log(self$" GenerateImpactEffect() called on "$getenum(enum'enetmode',Level.netmode)$" and Role="$ROLE,'DISCORDULOGGER');
  3500.  
  3501. if( bDisableDamageEffects || damageType=='Stunned' )
  3502. return;
  3503.  
  3504. bFlashReady = OldFlash==None || OldFlash.bDeleteMe;
  3505. if( bFlashReady )
  3506. OldFlash = None;
  3507.  
  3508. if( InstigatedBy==None )
  3509. return;
  3510.  
  3511. s = randrange(0.85, 1.1);
  3512.  
  3513. if( F > 1.0 )
  3514. {
  3515. if( bUseDamageFlashes && bFlashReady )
  3516. OldFlash = Spawn(Class'FlashWeakness', self);
  3517. PlayOwnedSound(EXUHitWeakness, SLOT_None, 8,,, s);
  3518. PlayOwnedSound(EXUHitWeakness, SLOT_Interact, 8,,, s);
  3519.  
  3520. if( Level.bDropDetail && FRand()<0.5 )
  3521. return;
  3522. else
  3523. Spawn(Class'ExtraDamageEffect', self,, HitLocation + (5 * vect(1,1,1) * VRand()), rotator(HitLocation - Location));
  3524. }
  3525.  
  3526. else if( F < 0 )
  3527. {
  3528. if( bUseDamageFlashes && bFlashReady )
  3529. OldFlash = Spawn(Class'FlashHealing', self);
  3530. PlayOwnedSound(EXUHitHealing, SLOT_None, 8,,, s);
  3531. PlayOwnedSound(EXUHitHealing, SLOT_Interact, 8,,, s);
  3532.  
  3533. if( Level.bDropDetail && FRand()<0.5 )
  3534. return;
  3535. else
  3536. Spawn(Class'HealinEffect', self,, HitLocation + (5 * vect(1,1,1) * VRand()), rotator(HitLocation - Location));
  3537. }
  3538.  
  3539. else if( F == 0 )
  3540. {
  3541. if( InstigatedBy==self ) // Don't generate invincibility effects for point-blank self-damage, only for damage from other pawns
  3542. return;
  3543.  
  3544. if( bUseDamageFlashes && bFlashReady )
  3545. OldFlash = Spawn(Class'FlashImmune', self);
  3546. PlayOwnedSound(EXUHitImmunity, SLOT_None, 8,,, s);
  3547. PlayOwnedSound(EXUHitImmunity, SLOT_Interact, 8,,, s);
  3548.  
  3549. if( Level.bDropDetail && FRand()<0.5 )
  3550. return;
  3551. else
  3552. Spawn(Class'InvincibilityEffect', self,, HitLocation + (5 * vect(1,1,1) * VRand()), rotator(HitLocation - Location));
  3553. }
  3554.  
  3555. else
  3556. {
  3557. if( bUseDamageFlashes && bFlashReady )
  3558. OldFlash = Spawn(Class'FlashResist', self);
  3559.  
  3560. PlayOwnedSound(EXUHitResistance, SLOT_None, 8,,, s);
  3561. PlayOwnedSound(EXUHitResistance, SLOT_Interact, 8,,, s);
  3562.  
  3563. if( Level.bDropDetail && FRand()<0.5 )
  3564. return;
  3565. else
  3566. Spawn(Class'ResistanceEffect', self,, HitLocation + (5 * vect(1,1,1) * VRand()), rotator(HitLocation - Location));
  3567. }
  3568. }
  3569.  
  3570.  
  3571. //===============================================================================================================
  3572. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  3573. //
  3574. // [6.3] PlayHit() - HEMOSPECTRUM CODE: Modified hit code to allow for different blood types and all sorts of other stuff
  3575. //
  3576. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  3577. //===============================================================================================================
  3578. function PlayHit( float Damage, vector HitLocation, name damageType, vector Momentum )
  3579. {
  3580. local Actor EHF;
  3581. local BloodEXU b;
  3582. local Bubble1 bub;
  3583. local bool bOptionalTakeHit;
  3584. local vector BloodOffset;
  3585. local EXUKetchupSpurt Blood;
  3586. local rotator durr, BloodDirection;
  3587.  
  3588. BloodDirection = rotator(HitLocation-location);
  3589.  
  3590. if( Damage > 1 ) //spawn some blood
  3591. {
  3592. if( damageType=='Drowned')
  3593. {
  3594. bub = spawn(class'Bubble1',,, Location + 0.7 * CollisionRadius * vector(ViewRotation) + 0.3 * EyeHeight * vect(0,0,1));
  3595. if( bub!=None )
  3596. bub.DrawScale = FRand() * 0.06 + 0.04;
  3597. }
  3598. else if( damageType != 'Corroded' )
  3599. {
  3600. BloodOffset = 0.2 * CollisionRadius * Normal(HitLocation - Location);
  3601. BloodOffset.Z *= 0.5;
  3602.  
  3603. if( Level.bHighDetailMode && !Level.bDropDetail && EXUHitEffect!=None && EXUHitEffectScale>0 )
  3604. {
  3605. EHF = Spawn(EXUHitEffect, self,, HitLocation, BloodDirection);
  3606. if( EHF!=None )
  3607. EHF.DrawScale *= ( EXUHitEffectScale * randrange(0.9, 1.1) );
  3608. }
  3609.  
  3610. if( Hemospectrum!=BLOOD_None )
  3611. {
  3612. b = spawn(class'BloodBurstEXU', self,, HitLocation + (vect(1,1,1)*randrange(0,20)) );
  3613. if( b!=None )
  3614. {
  3615. b.DrawScale = randrange(0.1, 0.15);
  3616. b.HSBloodNumber = Hemospectrum;
  3617. b.Initialize();
  3618. }
  3619.  
  3620. // "Static" blood
  3621. Blood = spawn(class'EXUKetchupSpurt', self,, HitLocation + BloodOffset, BloodDirection);
  3622. if( Blood!=None )
  3623. {
  3624. durr = rotator( class'exustaticfuncs'.static.randomspreadvector(0,20)>>BloodDirection );
  3625.  
  3626. Blood.HSSpurtNumber = Hemospectrum;
  3627. Blood.BaseScale = fclamp(CollisionRadius * 0.025, 1, 3); // Regular hit = small
  3628. Blood.SetPhysics(PHYS_Projectile);
  3629. Blood.settimer(0.2, False);
  3630. Blood.Velocity = vector(durr) * randrange(30,60);
  3631. Blood.Initialize();
  3632. }
  3633.  
  3634. if( Level.bHighDetailMode && !Level.bDropDetail )
  3635. {
  3636. // Directional blood
  3637. Blood = spawn(class'EXUKetchupSpurt', self,, HitLocation + BloodOffset, BloodDirection);
  3638. if( Blood!=None )
  3639. {
  3640. durr = rotator( class'exustaticfuncs'.static.randomspreadvector(0,25) >> BloodDirection );
  3641.  
  3642. Blood.HSSpurtNumber = Hemospectrum;
  3643. Blood.BaseScale = fclamp(CollisionRadius * 0.025, 1, 3); // Regular hit = small
  3644. Blood.SetPhysics(PHYS_Projectile);
  3645. Blood.settimer(0.2, False);
  3646. Blood.Velocity = vector(durr) * randrange(100, 200);
  3647. Blood.Initialize();
  3648. }
  3649. }
  3650. }
  3651. }
  3652. }
  3653.  
  3654. if( Weapon!=None && Weapon.bPointing && !bIsPlayer )
  3655. {
  3656. bFire = 0;
  3657. bAltFire = 0;
  3658. }
  3659.  
  3660. bOptionalTakeHit = bIsWuss || ( (Level.TimeSeconds - LastPainTime > 0.3 + 0.25 * skill)
  3661. && (Damage * FRand() > 0.08 * Health) && (Skill < 3)
  3662. && (GetAnimGroup(AnimSequence) != 'MovingAttack')
  3663. && (GetAnimGroup(AnimSequence) != 'Attack') );
  3664.  
  3665. if( (!bIsPlayer || Weapon==None || !Weapon.bPointing)
  3666. && (bOptionalTakeHit || (Momentum.Z > 140) || (bFirstShot && (Damage > 0.015 * (skill + 6) * Health))
  3667. || (Damage * FRand() > (0.17 + 0.04 * skill) * Health)) )
  3668. {
  3669. PlayTakeHitSound(Damage, damageType, 3);
  3670. PlayHitAnim(HitLocation, Damage);
  3671. }
  3672. else if( NextState=='TakeHit' )
  3673. {
  3674. PlayTakeHitSound(Damage, damageType, 2);
  3675. NextState = '';
  3676. }
  3677. }
  3678.  
  3679. //======================================================================================================
  3680. // [6.4] PlayDeathHit() -
  3681. //======================================================================================================
  3682. function PlayDeathHit( float Damage, vector HitLocation, name damageType, vector Momentum )
  3683. {
  3684. local Actor EHF;
  3685. local Bubble1 bub;
  3686. local BloodEXU b;
  3687. local EXUKetchupSpurt Blood;
  3688.  
  3689. if( Region.Zone.bDestructive && Region.Zone.ExitActor!=None )
  3690. Spawn(Region.Zone.ExitActor);
  3691.  
  3692. if( HeadRegion.Zone.bWaterZone )
  3693. {
  3694. bub = spawn(class'Bubble1',,, Location + 0.3 * CollisionRadius * vector(Rotation) + 0.8 * EyeHeight * vect(0,0,1));
  3695. if( bub!=None )
  3696. bub.DrawScale = FRand() * 0.08 + 0.03;
  3697.  
  3698. bub = spawn(class'Bubble1',,, Location + 0.2 * CollisionRadius * VRand() + 0.7 * EyeHeight * vect(0,0,1));
  3699. if( bub!=None )
  3700. bub.DrawScale = FRand() * 0.08 + 0.03;
  3701.  
  3702. bub = spawn(class'Bubble1',,, Location + 0.3 * CollisionRadius * VRand() + 0.6 * EyeHeight * vect(0,0,1));
  3703. if( bub!=None )
  3704. bub.DrawScale = FRand() * 0.08 + 0.03;
  3705. }
  3706.  
  3707. if( damageType!='Burned' && damageType!='Corroded' && damageType!='Drowned' && damageType!='Fell' )
  3708. {
  3709. if( Level.bHighDetailMode && !Level.bDropDetail && EXUHitEffect!=None && EXUHitEffectScale>0 )
  3710. {
  3711. EHF = spawn(EXUHitEffect, self,, HitLocation);
  3712. if( EHF!=None )
  3713. EHF.DrawScale *= ( EXUHitEffectScale * randrange(0.9, 1.1) );
  3714. }
  3715.  
  3716. if( Hemospectrum!=BLOOD_None )
  3717. {
  3718. b = spawn(class'BloodBurstEXU', self,, HitLocation);
  3719. if( b!=None )
  3720. {
  3721. b.HSBloodNumber = Hemospectrum;
  3722. b.Initialize();
  3723. }
  3724.  
  3725. if( Level.bHighDetailMode && !Level.bDropDetail )
  3726. {
  3727. Blood = spawn(class'EXUKetchupSpurt', self,, HitLocation);
  3728. if( Blood!=None )
  3729. {
  3730. Blood.HSSpurtNumber = Hemospectrum;
  3731. Blood.BaseScale = fclamp(CollisionRadius * 0.0365, 1, 4); // DEATH = BIG (sorta)
  3732. Blood.Initialize();
  3733. }
  3734. }
  3735. }
  3736. }
  3737. }
  3738.  
  3739.  
  3740. //===============================================================================================================
  3741. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  3742. //
  3743. // [6.5] Died() - Hook for pawns to use to do extra stuff when killed, stuff not handled in the carcass or in Destroy()
  3744. //
  3745. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  3746. //===============================================================================================================
  3747. function Died( pawn Killer, name damageType, vector HitLocation )
  3748. {
  3749. ExtraDeathStuff();
  3750. ClientDeathStuff();
  3751.  
  3752. Super.Died(Killer, damageType, HitLocation);
  3753. }
  3754.  
  3755.  
  3756. //======================================================================================================
  3757. // [6.6] SpawnCarcass() -
  3758. //======================================================================================================
  3759. function Carcass SpawnCarcass()
  3760. {
  3761. local Carcass Carc;
  3762.  
  3763. Carc = Spawn(CarcassType, self);
  3764. if( Carc!=None )
  3765. Carc.Initfor(self);
  3766. //else
  3767. // warn(self$" Failed to spawn Carcass "$CarcassType$" at Location "$Location);
  3768.  
  3769. return Carc;
  3770. }
  3771.  
  3772.  
  3773. //======================================================================================================
  3774. // [6.7] SpawnGibbedCarcass() - Carcass Management System v0.8.243.f.3453.5.546g
  3775. //======================================================================================================
  3776. function SpawnGibbedCarcass()
  3777. {
  3778. local carcass carc;
  3779. local EXUKetchupSpurt Blood;
  3780.  
  3781. if( GibMode==GIB_Never )
  3782. return;
  3783.  
  3784. carc = Spawn(CarcassType, self); // set carcass's Owner to Self for use by EXUCreatureCarcass and the like
  3785. if( carc!=None )
  3786. {
  3787. carc.Initfor(self);
  3788. carc.ChunkUp(-1 * Health);
  3789. }
  3790.  
  3791. if( Level.bHighDetailMode && Hemospectrum!=BLOOD_None && !Level.bDropDetail ) // yeah this should be done in EXUCreatureCarcass but you know what, fuck you, fuck you
  3792. {
  3793. Blood = spawn(class'EXUKetchupSpurt', self);
  3794. if( Blood!=None )
  3795. {
  3796. Blood.HSSpurtNumber = Hemospectrum;
  3797. Blood.BaseScale = fmax(CollisionRadius*0.09, 1); // GIBDEATH = BIG_GIB
  3798. Blood.Initialize();
  3799. }
  3800. }
  3801. }
  3802.  
  3803.  
  3804. //======================================================================================================
  3805. // [6.8] Gibbed() -
  3806. //======================================================================================================
  3807. function bool Gibbed( name damageType )
  3808. {
  3809. if( GibMode==GIB_Never )
  3810. return False;
  3811. else if( GibMode==GIB_Always || damageType=='LRPC' )
  3812. return True;
  3813. else
  3814. return Super.Gibbed(damageType);
  3815. }
  3816.  
  3817.  
  3818. //======================================================================================================
  3819. // [6.9] ExtraDeathStuff()
  3820. //======================================================================================================
  3821. // NOTE: THIS FUNCTION IS ALWAYS CALLED SERVER-SIDE. If you need to spawn effects clientside, see below:
  3822. //======================================================================================================
  3823. function ExtraDeathStuff(); // Implement in subclasses
  3824.  
  3825.  
  3826. //======================================================================================================
  3827. // [6.10] ClientDeathStuff() -
  3828. //======================================================================================================
  3829. // 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.
  3830. // Implement ClientDeathStuff() in the pawn, and have it spawn a proxy actor set up to generate anything you need clientside.
  3831. // See Effects >> EXUGenericEffects >> EXUClientEffectProxy for more info.
  3832. // Thanks to PCube, []KAOS[]Casey, and Core for help with this stuff!
  3833. //======================================================================================================
  3834. function ClientDeathStuff(); // Subclasses yo
  3835.  
  3836.  
  3837.  
  3838.  
  3839. //=====================================================================================================================
  3840. // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
  3841. //=====================================================================================================================
  3842. //
  3843. // SECTION 7: EXU ADDITIONS
  3844. // [7.1] simulated state StunnedState
  3845. // [7.2] function StunEffects()
  3846. // [7.3] state SpawnWhenTriggered
  3847. //
  3848. //=====================================================================================================================
  3849. // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
  3850. //=====================================================================================================================
  3851.  
  3852.  
  3853. //===============================================================================================================
  3854. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  3855. //
  3856. // [7.1] StunnedState - Take a quick break and spaz out for a bit
  3857. //
  3858. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  3859. //===============================================================================================================
  3860. simulated state StunnedState
  3861. {
  3862. ignores SeePlayer, HearNoise, Bump;
  3863.  
  3864. //======================================================================
  3865. function Timer()
  3866. {
  3867. StunEffects();
  3868. SetTimer(0.1, False);
  3869. }
  3870.  
  3871. //======================================================================
  3872. simulated function Tick(float dt)
  3873. {
  3874. local rotator StunRot;
  3875.  
  3876. if( StunLength > 0 )
  3877. StunLength -= dt;
  3878.  
  3879. if( StunShock!=None )
  3880. {
  3881. StunShock.ScaleGlow = StunLength / 2;
  3882. StunShock.SoundVolume = fclamp( (StunLength / 2) * 255, 0, 255 );
  3883. }
  3884.  
  3885. StunRot = StunnedRotation;
  3886. StunRot.Yaw += randrange(-2000, 2000);
  3887.  
  3888. SetRotation( StunRot );
  3889. }
  3890.  
  3891. //======================================================================
  3892. simulated function BeginState()
  3893. {
  3894. if( DrawType==DT_Mesh && StunShock==None )
  3895. {
  3896. if( Level.Netmode==NM_Standalone )
  3897. {
  3898. StunShock = Spawn(Class'StunOverlay', self);
  3899. if( StunShock!=None )
  3900. {
  3901. StunShock.Mesh = Mesh;
  3902. StunShock.DrawScale = DrawScale;
  3903. StunShock.Fatness = fclamp( Fatness + 2, 0, 255 );
  3904. }
  3905. }
  3906. else
  3907. {
  3908. StunShock = Spawn(Class'StunnerProxy', self);
  3909. if( ROLE==ROLE_Authority && StunShock!=None )
  3910. StunShock.RemoteRole = ROLE_None;
  3911. }
  3912. }
  3913. }
  3914.  
  3915. //======================================================================
  3916. simulated function EndState()
  3917. {
  3918. local StunOverlay E;
  3919.  
  3920. if( Level.Netmode==NM_Standalone )
  3921. {
  3922. if( StunShock!=None )
  3923. StunShock.Destroy();
  3924. }
  3925. else
  3926. {
  3927. foreach ChildActors( class'StunOverlay', E )
  3928. {
  3929. if( !E.bDeleteMe )
  3930. E.Destroy();
  3931. }
  3932. }
  3933. }
  3934.  
  3935. //------------------------------------
  3936. Begin:
  3937. Timer();
  3938. SetTimer(0.1, False);
  3939. Acceleration = vect(0,0,0);
  3940.  
  3941. Sleep(StunLength);
  3942. StunLength = 0;
  3943. GoToState('Attacking');
  3944. }
  3945.  
  3946.  
  3947. //======================================================================================================
  3948. // [7.2] StunEffects - Global for ease of overriding / enhancing
  3949. //======================================================================================================
  3950. function StunEffects()
  3951. {
  3952. local float Choice;
  3953.  
  3954. Choice = FRand();
  3955.  
  3956. if( Choice < 0.75 )
  3957. PlayGutHit(0.08);
  3958. else if( Choice < 0.5 )
  3959. PlayHeadHit(0.08);
  3960. else if( Choice < 0.25 )
  3961. PlayLeftHit(0.08);
  3962. else
  3963. PlayRightHit(0.08);
  3964.  
  3965. if( FRand() < 0.1 )
  3966. PlayTakeHitSound(0, 'None', 2);
  3967. }
  3968.  
  3969.  
  3970. //===============================================================================================================
  3971. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  3972. //
  3973. // [7.3] SpawnWhenTriggered - Enemy isn't interactable until triggered. Can spawn effects when appearing
  3974. //
  3975. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  3976. //===============================================================================================================
  3977. state SpawnWhenTriggered
  3978. {
  3979. ignores SeePlayer, HearNoise, Bump, TakeDamage, Killed;
  3980.  
  3981. //=====================================================================================
  3982. function Trigger( Actor Other, Pawn EventInstigator )
  3983. {
  3984. if( EventInstigator==None || EventInstigator==Self )
  3985. return;
  3986.  
  3987. Disable('Trigger');
  3988. SWTEnemy = EventInstigator;
  3989. 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
  3990.  
  3991. GoToState('SpawnWhenTriggered', 'SpawnStuff');
  3992. }
  3993.  
  3994. //=====================================================================================
  3995. function DoinThangs()
  3996. {
  3997. local Pawn currentEnemy;
  3998. local Actor TSE;
  3999.  
  4000. bHidden = Default.bHidden;
  4001. bProjTarget = Default.bProjTarget;
  4002. bQuiet = Default.bQuiet;
  4003. bIgnoreFriends = Default.bIgnoreFriends;
  4004. SoundVolume = Default.SoundVolume;
  4005. LightType = Default.LightType;
  4006. SetCollision(True, True, True);
  4007. AttitudeToPlayer = OriginalAttitudeToPlayer;
  4008. SetPhysics(OriginalPhysics);
  4009.  
  4010. BagOfJunk = True; // Gotta be the most hilarious variable name yet
  4011.  
  4012. if( TriggeredSpawnEffect!=None )
  4013. {
  4014. TSE = Spawn(TriggeredSpawnEffect, self);
  4015. if( TSE!=None )
  4016. {
  4017. if( TriggeredSpawnEffectScale < 0 )
  4018. TSE.DrawScale *= CollisionHeight / 25;
  4019. else
  4020. TSE.DrawScale *= TriggeredSpawnEffectScale;
  4021. }
  4022. }
  4023.  
  4024. bStasis = Default.bStasis; // Restore original bStasis condition
  4025. Enable('Trigger');
  4026.  
  4027. if( SWTEnemy!=None && bHateWhenTriggered ) ///FIXME: we need a check to be sure the player is *visible* if Relentless is False
  4028. { // Otherwise, all SpawnWhenTriggered enemies will immediately seek the player
  4029. if( SWTEnemy.bIsPlayer )
  4030. AttitudeToPlayer = ATTITUDE_Hate;
  4031. else
  4032. Hated = SWTEnemy;
  4033.  
  4034. currentEnemy = Enemy;
  4035. SetEnemy(SWTEnemy);
  4036.  
  4037. if( SWTEnemy!=currentEnemy )
  4038. {
  4039. PlayAcquisitionSound();
  4040. if( AlternateStartupState!='' )
  4041. {
  4042. Orders = AlternateStartupState;
  4043. GoToState(Orders);
  4044. }
  4045. else if( AlternateStartupState=='' )
  4046. GoToState('Attacking');
  4047. }
  4048.  
  4049. SetFall();
  4050. }
  4051. else
  4052. {
  4053. if( AlternateStartupState!='' )
  4054. {
  4055. Orders = AlternateStartupState;
  4056. GoToState(Orders);
  4057. }
  4058. else
  4059. GoToState('Waiting');
  4060.  
  4061. mtimer2(); // Enemy scan radar (using AutoHateRadius)
  4062. }
  4063. }
  4064.  
  4065. //=====================================================================================
  4066. function SetFall()
  4067. {
  4068. if( Enemy!=None )
  4069. {
  4070. NextState = 'Attacking'; //default
  4071. NextLabel = 'Begin';
  4072. NextAnim = 'Fighter';
  4073. GotoState('FallingState', 'FastLanded');
  4074. }
  4075. }
  4076.  
  4077. //=====================================================================================
  4078. function BeginState()
  4079. {
  4080. local Actor a;
  4081.  
  4082. OriginalPhysics = Physics;
  4083. OriginalAttitudeToPlayer = AttitudeToPlayer;
  4084.  
  4085. bHidden = True;
  4086. bProjTarget = False;
  4087. bQuiet = True;
  4088. bIgnoreFriends = True;
  4089. SoundVolume = 0;
  4090. LightType = LT_None;
  4091. AttitudeToPlayer = ATTITUDE_Ignore;
  4092.  
  4093. SetPhysics(PHYS_None);
  4094. SetCollision(False, False, False);
  4095. }
  4096.  
  4097.  
  4098. //------------------------------------
  4099. SpawnStuff:
  4100. if( TrigSpawnDelayMax > 0 )
  4101. Sleep(randrange(TrigSpawnDelayMin, TrigSpawnDelayMax));
  4102. DoinThangs();
  4103. }
  4104.  
  4105.  
  4106. defaultproperties
  4107. {
  4108. AutoHateRadius=600
  4109. HellDamageScale=1.000000
  4110. AttitudeToOwnClass=ATTITUDE_Friendly
  4111. AttitudeToSubClass=ATTITUDE_Friendly
  4112. DefaultAttitude=ATTITUDE_Friendly
  4113. TriggeredSpawnEffectScale=-1.000000
  4114. TrigSpawnDelayMax=0.000000
  4115. TrigSpawnDelayMin=-1.000000
  4116. DamageScales(0)=1.000000
  4117. DamageScales(1)=1.000000
  4118. DamageScales(2)=1.000000
  4119. DamageScales(3)=1.000000
  4120. DamageScales(4)=1.000000
  4121. DamageScales(5)=1.000000
  4122. DamageScales(6)=1.000000
  4123. DamageScales(7)=1.000000
  4124. DamageScales(8)=1.000000
  4125. DamageScales(9)=1.000000
  4126. MaxHealingScale=1.000000
  4127. MeleeDamageType=hacked
  4128. EXUHitEffectScale=1.000000
  4129. EXUHitHealing=Sound'AmbModern.OneShot.teleprt3'
  4130. EXUHitImmunity=Sound'EXU-Sounds.GunSounds.Invulnerability'
  4131. EXUHitResistance=Sound'EXU-Sounds.PawnSounds.UT3Spark1'
  4132. EXUHitWeakness=Sound'AmbAncient.OneShot.explo7'
  4133. MuzzleEffectScale=1.0
  4134. ProjectilesPerShot=1
  4135. ShotsPerBurst=1
  4136. TimeBetweenShots=0.05
  4137. ShootVolume=2.0
  4138. ShootMagnitude=1
  4139. PawnTags(0)=Organic
  4140. PawnTags(1)=Living
  4141. DeathLightingMode=DLM_GibsLit
  4142. bEnableDamageLoggers=False
  4143. NameArticle="a "
  4144. MaxWanderDist=1500
  4145. PointValue=100
  4146. SelfDamageScale=1.0
  4147. FriendlyDamageScale=1.0
  4148. PawnDescription="An EXU2 Monster"
  4149. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement