*E@# oj J -ɋl# None AttackingSoundsBeginTakeHitAnimEnd TakeDamageBumpBreath AttitudeTo PlayTurning BeginState PlayWaitingTweenToRunningTweenToFighterCoreEngine TeamMonsterSystem PlaySwimming TacticalMoveTweenToPatrolStopBotpack MenuName PlayWalking FallingState SetEnemyWalkFighterPickDestinationTweenToSwimmingPlayPatrolStop PlayRunningHealthLandedPlayRangedAttackPlayChallenge MeleeAttackTweenToWalkingMeleeDamageTarget RangedAttackFlyRunTimerSetFallSpeakSwimCollisionHeightTweenToWaitingEnemyNotVisibleSetMovementPhysics EndStatePlayMeleeAttackPlayThreatening PlayTakeHitCollisionRadiusBreath2 SeePlayerPlayThreateningSound CombatStyleMassLand ChargingAggressivenessPlayVictoryDance footstepMovingFloat WhatToDoNextPlayWaitingAmbush PlayLandedWaitingMesh MeleeRange NeedToTurn Threaten HitSound1 GroundSpeedCanFireAtEnemyDie RotationRateTweenToFallingTriggerRotatorAdjustFromWallRoam HitSound2Bowing CarcassType PlayInAir NoChargeSkin SightRadius AdjustAim RetreatingEnemyAcquired RefireRate Buoyancy wandering Flopping Guarding TryToDuckHuntingFearAcquireDragJumpZFlying PlayDyingDeath2Initfor Swimming Intelligence AccelRatebHasRangedAttack SpecialNavig Acquisition AmbientSound ZoneChangePlayRoamingSoundHitWallPlayMovingAttackwanderGetUpRangedProjectile TriggerAlarmPlayAcquisitionSoundUnderWaterTimeJog WarnTargetTwirl TWalk001Shoot3 WaterSpeedTurnDead2KeepAttackingCombatRoaming AirSpeedspin FaceTargetlunge Patroling AlarmPausedJogFireFiringCringePostBeginPlay PreBeginPlaybMovingRangedAttack AmbushingTickShieldSLITHERFallingprayTeamScriptedPawnTeamMercenaryBackup TurnFromWallShoot1WaverPreSetMovementDone TeamKrallDiedReadyToAttack bCanStrafePlayCombatMove StrafeLeftFr StrafeRightStrafeRightFr StrafeLeft StakeOutDoMove Visibility HearNoiseTransientSoundVolumeHiding ClawDamage AddVelocityReducedDamageTypegunfixGrazingPlayOutOfWater TeamSkaarjCrawldamageAttitudeTo ShieldedMoverAIRelativeStrength DrawScaleTestDirection HandleDoorJump LongFall WalkFireRiseUp WalkingSpeedPlayHeadDeathKilled StillLook bLeadTarget breathingUncurlDeathGrabGrazeGetDownAttitudeToCreaturePunch DrowningPlayFearSoundStab PlayDiveBecomeInvulnerable WhipDamageReducedDamagePctDuckingStepFatnessTalk2TeamCowCharge FearThisSpotDead1 SwimFireDead3 DecapitatedPlayWaitAround ChallengePlayLeftDeathPlayRightDeathDie2RunAwayWhipRecover MovingAttack PlayBigDeath NearWall GoBerserk StartRoaming PlayCock PushButtonsPausing StrafeAdjust SpeakOrderToPlayOut levitate SpinDamageLook CanStakeOutScream LungeDamage SpawnShotCloseInContinueWanderChangeDestinationOrdersclaw PlayGutDeathSpeakToThrow TBrea001Belch WeaponTypeProjectileSpeed TStom001 TeamTitan AfterFallShoot2Dead ThrowOther TeleportingPeripheralVision PunchDamage PlayerPawnHearingThreshold RateSelfTouch PlayFiring FireWeaponPawn TryToCrouch ReachedHomeChooseAttackModeShoot TeamQueen TeamPupae TeamNali TacticalTick hairflipAttitudeWithFearSweatWaitForPlayer DoneFiringSmackPatrol FaceEnemy Shieldup syllable3 syllable4 syllable5 BecomeNormal VoicePitch syllable1LeftHit PoundDamage ShieldDown RightHitGutHitFollowDead5 syllable6startup MeditateMunchStrafeFromDamageDoneAttackingSkillFadeOutTimeBetweenAttacks syllable2bIsBoss SpeechTimerChooseLeaderAttack TDeat001Talk1TFistTalk3 StrikeDamageFinalSequenceFlyFireTeamDevilfishLaughPound TFigh001 FollowMomPlayRetreating GoToGuardStrike1BackOffSlap TDeat002 SpeakPrayerSetHome MoveToPatrolStrike2T8WalkingCoughDeath4 PrechargSwish ShldFire guncheckStingLungeDamageTarget Mutilating LFighter PickNextSpotSLASHDie3HideMove1Move2 TeamManta Invulnerable TeamBrute TeamWarLord TeamSquid ThreateningFindAmbushSpot TeamGasbagJumpOutOfWaterGiveUpTactical StingDamagebIsWussValidRecovery AlarmDone RecoverEnemy PlayHitAnimFindBestPathToward FindAlarmFire DoStrafeMoveLookingHelp RightDodgeTauntClawDamageTarget ShakeView JumpOffPawn explodedshot PlayDeathHit LeftDodgeAttitudeToPlayerDead4shakeSleep WaitAroundGiveUpAttack CorrodedPlayTakeHitSoundBurned WaterStepWaitsplash TeamToggle GreenBloodTeamKrallElite TeamTentacle TeamSlithTeamSkaarjTrooperChooseDestination CheckDist PunchHit ThrowDamage MinDuckTimeWalkOut LavaDeath SpeakOrders KeepTurning SlapDamageTearTChest TDeat003Swat TShuffle NeckCrak WalkSpray Stealth1StrikeSquat3LegLossTossPointHeadRubStrike3Fiddle SpawnBelch HoldShield ShldLand ShldDownThrustripper SpawnRocketSittingPoundDamageTargetPunchDamageTarget UnrealShare MButton3Root LeglessDeath DestroyedT3TeamCreatureFactory SetTeamTSP BiteDamage GreetingWeaponDuck WalkStepJump2 KeepWaitingSprayDelayedPatrol MButton2 FindViewSpot MoveToEnemyMayFall VictoryDanceNoReachBiteSetTurnAllMaxStepHeightstomped FastLanded WaitForEnemy ResumePatrol MoveToAmbushReachedPatrolhacked ContinueRoam FinishDodgeKeepCringeing KeepBowingChewButton5HangOutPickThreatenDestination Footstep2Button4TriggerFirstHateButton3HeadHit AnnoyedByChooseTeamAttackForButton2 KilledByHeadupDeath3Button1InitAmbushLoc MButton4SCRATCHCLAW2DiscardInventory HomeBaseInitPatrolLocPlayHitFindShootTarget SpawnCarcass SetAlarm WFighterRunFire GotThereCLAW1grab1CockGunbite3AltFire SoundRadiusSurface adjustJumpDie4SkaarjWarrior FindAmbush TurnAtHomeLanding MButton1Fellbite2FindNextPatrolSpawnRightShot ResumeCharge WalkToolPickGuardDestination ReduceDamageDIVEPoop PistolWhipbite1DropDecorationBigHitDrownedCreatureKillMessageFootstepSound LightEffectAdjustHitLocationLightSaturation PlayLeftHit HidePlayer PlayGutHitSkaarjMaxDesiredSpeed PrePivotDyingChangedWeapon SoundVolume FovAngleLightBrightnessChunkUpCreateMutatorTakeDamageNali PlayHeadHitSpawnTwoShots StopFiring TraceShotCheckWaterJumpGibbedRunStepDodge AnimSequence KillMessage GameEnded PlayRightHitSpawnGibbedCarcass LightRadiusIdle DeActivated NameArticle AdjustToss StopWaitingCowSuggestDefenseStyleHitSuggestAttackStyleDrop TossWeapon bAttackBumpTeamGiantGasbag HitSound4TeamMercenaryElite HitSound3AcceptTeamSkaarjOfficer TeamBehemothjolted TeamBabyCowTeamCaveMantaTeamSkaarjBerserkerTeamStoneTitanTeamSkaarjScoutTeamSkaarjLordTeamSkaarjInfantryTeamSkaarjSniperTeamSkaarjAssassinTeamSkaarjGunnerTeamLeglessKrallTeamLesserBruteTeamSkaarjWarriorTeamIceSkaarj TrackWarhead PlayActivate DamagedStatePlayDeactivate ActiveCannonChestStartDeactivate SameTeamAsbHasInvulnerableShield CheckWeapon spearHit spearThrow bSpearToss WeaponSprayinvulnerableChargebCanFireWhileInvulnerable slapgrabhit ThrustDamage' ThreeHitGouge GrabTargetShldUp LightHue QueenDest TwoPunch ThreatBelchDie1 ThreatShoot1Crouch TeleportSleep1Grasp ShotMoveGPunch1GPunch2ThrowDamageTarget ThrowTargetFDodgeL bWarnTarget GrabDice ThrowDice ShootTargetButton6Squat1Squat2 Stealth2 SpawnRockSlapDamageTargetFDodgeRStompTexture TSnif001 TSlap001 TThro001SwingDeath5 TPunc001SpinDamageTargetGKick2TGetUp SlapTargetStabDamageTarget DoDirectMoveGKick1 ThrustTargetOutColdFrozenStrikeDamageTargetStretch BaseChangeEncroachingOnGutShotTargetWhipDamageTargetSpawnLeftShotTeamGiantMantaTeamFlyTeamNaliPriest PistolHit StabDamageBlademebax StompSoundFlip ScreamSound thrusthit SpawnShield FDodgeUp CoopGame ShldTestTSitASMDHitDamageTarget wingBeat bFixedStartDeflateripFlap AcquTurnVector suffocated SprayTargetbCovertFootZoneChangepickTeamSpawnpointPostKillMessage PickAnim bFirstShotFireProjectileHit2sliceHeadZoneChange TakeHit2 RipDamageSetTeam StartMovingDead2A bStayClose ThreatSting SetAlertness StillFire WanderRadius urgefollow Footstep1GutshotMinigun MadeInOz SmackTarget bGreenBlood bCanDuckSLICKCurl WTakeHitRifleInAir PainTimer PlayFall LTakeHit CHARGEUPExtentHitLocDesiredRotation ScaleGlow bIsPlayer bCanJump MoveTarget LightType Destination AmbientGlow FootRegionPackageFocus AlertnessMinDist DesiredSpeedResultbUnlit MoveTimer SpeechTimeKillerGameNext instigatedByClassTeambQuietASpot AIRating capacity CowCarcassStyle BloodPuffBigBlackSmoke FlyCarcassGreenBloodPuff GuardPointLesserBruteCarcass MantaCarcassBruteProjectile StartTimeSkaarjCarcassSkaarjProjectileBase AmbushpointbStasis BruteCarcassBubble1 Spawnpoint TeamInfoCreatureChunksTentacleCarcassTentacleProjectile Location hitdamageDevilfishCarcassBlood2 BloodBurstQueenWarLordPupae PointRegionTest InstigatorZone Rotation TweenTime RespawnTime TimerCounter DamageType TimerRate AlarmPoint ThingFactory LastSeenPosP nextPawnTag ScriptedPawn decorMassRegion AnimFramePlayerViewOffset bChangeDir bSpecialGoal bClearShotbFirstHatePlayerbMoraleBoosted bCrouchingbFiringPaused bCanFire NaliCarcassbSpecialPausing bStrafeDir OldEnemyPhysics bFrustrated LastPainAnimbReadyToAttack HidingSpot numHuntPathsHuntStartTime TeamLeader NewAlertnessfish OrderObjectdesired NextAnim LastPainTime FireSpot FireRotation TargetDist enemyDistattduckDirDir2D NewStrength NewEnemy enemyDiradjustedOther bFindDest SlithCarcass SmallSpark2 newHeadZone strafemagSlithProjectile bProjTargetpickdirjumpDir LikelyLabel LikelyState changeEnVelDir OtherDir oldTargetzdiffsideDir healthpct bWasOnGround bNoChargetargYawErr collSpec enemyPart strafeSizeoptDist walldist ViewSpotposZelapsed leadTarget bAlwaysTry bReversedTeamTag OrderTagHatedRoamStartTimeFirstHatePlayerEventbTeamSpeaking bTeamLeaderbIgnoreFriendsSuccessTargetshooterbDelayedPatrolratingLastSeeingPos aimerror NewAttitude TeamMember oldAttitudeSimAnim oldestRoamer numRoamers StartOffset noOldEnemyScriptedOther bFoundTeamXYadjustedStrengthpushdirspeedEnemyUpnewspotLoc2Dpat bSuccess bAlongWall desiredDest bFalling destpoint bWasFriendly FlockPawnNaliCow injurC1c injurC2cManta ExitActorbForageSlithNextPatrolPointbHidden TentacleEvent PatrolPointlookDirCreatureCarcassTeamNumStart OldAnimRateamb1br bBerserkbTurretbOptionalTakeHit pausetimeBrute3Manta1whip1minjur2mcall2mfly1msting1mland1mtbHighDetailMode bPointingJManta2minDest bNoReach Razorfishambfs chomp1fs death1fsflop1fstear1fsmiss1fs breath1fs nextSpotbCanSeeLastSeen Razorflybuzz3rf injur1rf death1rfNali1velZFullVelsyl1nsyl2n bCanSpeaksyl5nsyl6n follow1ninjur1ninjur2n contct1n contct3nfear1n breath1ndeath1ndeath2n bowing1n backup2ncough1nsweat1npray1n Teleport1 bNeverBow bCringing bGesturebFading bHasWandered bCanBePissed NewFatnessJNali2amb1sksyl07sksyl09sksyl11sksyl12sksyl13sksyl15skspin1sclaw2s clawhit1s injur1sk injur3sk chalnge1s chalnge3s death1sk death2skroam11s lunge1sk hairflp2skThumpAttackSuccessbButtonPusher bFakeDeathphrasephrasesyllable inflectionSkaarjwinjur1mBrute NextpatrolRoleaNode SpecialPauseoldspotamb1slFocus2D SeenPlayeraPlayer currentEnemy ZoneInfo Decoration Projectile bIsSpectator bJumpOffPawn bFirstAttack Tentacle1 injured1tn strike2tncurltnAttEn numspotsitemtagAirTime spawnspotAddedCoopCapacity DeathC1ccMoo2c DeathC2cshakeCambCowswishCmomBrute1 injur1br pwhip1bryell1br death1br death2brwalk2br pstlhit1br bLongBerserkdeath2madjustMaxMove TeamIndex NextAlarm ducktime AlarmAnimbAttackWhilePausedbNoFailbStopIfNoEnemybKillMebDestroyAlarmTriggerer AlarmSoundNextAlarmObject newcreature pawnFactory creatureFlyM injur2rf carcRotationThrown NaliHeadsyl3nsyl4n SkaarjHeadTool injur2skGibscall1m Skaarjw4Slith1Land1yell3slroam1sl decisionsurf1sldive2slswim1slyell1tn injured2tn waver1tnyell2tn splat2tn death2tn prototypeSkins bStrafeToGenericLSplashrndbub BloodOffset cringe2nbReducedHeightbNoWait bInitialFearoldestRoamTime MercenaryBestKrallFactory TextBufferObjectEnumTitanTeamID FunctionState TargetPointStructEnemyRowName PlayerNameCompare NewVelocityUnrealI StrProperty MaxSpeed MinHitWall HeadRegion PainTime OtherPawn OldLocation Velocity SniperRifle Acceleration NewRotationDest2DbMeshEnviroMap bMeshCurvyaPawn bFromWall UT_EightballbCanFlybCanDoSpecial PulseGun minJumpZN EnforcerSquid bWaterZoneCalcDrawOffsetDir AlarmSpot DamagePerSec LoudnessGasbag TraceDir SpecialGoalwalkC bUseAltMode EAttitudeLastPainSound DeltaTimeOtherStartLocation bAltFiremaxZcMoo1c bHasBabybFire NextState NextLabelhome AnimCountSharedAlarmTagcarriedDecorationadjZtemp AlarmTagMessageA AmmoTypeX EyeHeightZ checkpoint bDestructive bPainZone numAnimsWallPitchYOwner newFootZone NoiseMakerRollbaby PatrolSound AmmoAmount Accuracyi bAlreadyDeadNavigationPointList ScriptTextbTempFireDir TimeSecondscarc HitActordist PawnList ViewDist bVeryLowGoreSoundCountActorPathLodMeshLevelBBrush projStartYawOldLastSeenPos ScaryGuy animspeedBaseEyeHeightMult GasBagBelchBigRock SelectSound impactVelAttitudeToEnemylandVolWarlordCarcassWarlordRocket bJustLanded AggressionSpriteSmokePuff MercCarcassDamageMutatorNewRotwalk1br PatrolAnimGassiusCarcass InventoryG injur2bryell2br nearby2br Boulder1TrooperCarcassAmmoQueenTeleportLightQueenTeleportEffect QueenShield PupaeCarcass MercFlare MercRocket HitActor2 KrallCarcass HitActor1 bAnimLoopEliteKrallBoltDiceQueenProjectile KraalBoltBrute2 Skaarjw3 Skaarjw5 Skaarjw2SkaarjL sktrooper sktrooper1 myWeapon sktrooper2GasBagM twopunch1ginjur1ginjur2gyell2gyell3g nearby1gdeath1ghit1gamb2g ParentBag numChildrenKrallMamb1krsyl1krsyl2krsyl3krsyl4krsyl5krsyl6krdeath1kdeath2k strike1k staflp4kinjur1kinjur2kchlng1kchlng2khit2kthrow1ksnore1k bHasDice bHeldDiceToy1Toy2 LastDuckTimerepd1d2 ThrowLoctweeninekrallMercSilveramb1mr spray1mrsyl1mrsyl2mrsyl3mrsyl4mrsyl5mrsyl6mrswat1mr injur2mr injur3mr chlng2mr nearbymr weapon1mr chlng3mrland1mrwalk2mr death1mr death2mr death3mrflip1mrhit1mr OrdersGivenbTalker bSquatter bPatrolingbIsInvulnerable bAlertedTeam sprayoffsetinvulnerableTime OldPainTimeAdjRotJMerc2Pupae1 scuttle1pp injur1pp injur2pproam1pphiss1pphiss2pphiss3ppbite1pptear1ppmunch1p death1ppSkQueenclaw1Qshoot1Qyell1Qyell2Qyell3Qstab1Q outcoldQ nearby2Qamb1Qstep1t ScreamEventbJustScreamed bEndFootStep TelepDest EnemyRot ViewPoint newratingSquid1amb1sq death1sqgrab1sqhit1sqslap1sq thrust1sq injur1sq injur2sqturn1sqflopTitan1Throw1tstomp4t punch1TiSwing1tyell1tyell2tyell3tdeath1tinjur1tinjur2tamb1Ti sniff1Ti slaphit1Tiroam1Ti chestB2TibStomp bLavaTitan realSpeed StompEvent StepEventProjJtitan2 WarlordM injur1WL injur2WL acquire1WL DeathCry1WLfly1WLroam1WL threat1WL breath1WL laugh1WL Teleport2bTeleportWhenHurt projRotation KrallHead KrallFoot MercHead PupaeBody PupaeHead sktrooper3 bDicePlayer bSleepingStructProperty TeamCannonStationaryPawnPlayerReplicationInfoblade1s StartSpotAssault ReturnValuedist2d duckLeftmoveDircurrentWinner Attacker DefenderMyTeam injur1slClassProperty NamePropertyObjectPropertyEventInstigator HitNormalNewZoneNavigationPointDamageCarcass EndTraceyell1sl injur2slyell2slFloatProperty BoolProperty HitLocationnextNavigationPoint bUpAndOut Momentum IntPropertyyell4sl GameInfo CockingSound ViewRotation bCanWalk LevelInfotakenMutator projSpeedCreatureFactory ByteProperty bCanSwim FireOffset actualDamagebCanOpenDoors bAvoidLedges slithr1sl deathLsl deathWslbSplashDamage bHunting scratch1sl bAvoidHitTSPawn bIsSpeakingViewDir TnewspotbHateWhenTriggereda,x]B7DEW(!rArArAtrArArAtrArAԝXrArArArArArArAԝXԝXrArArArArArArAttttrArArArArAttԝXrArAԝXrArArAEԝXrAttԝXrArAԝXtrArAԝXrArAԝXttԝXԝXԝXԝXԝXԝXԝXԝXԝXԝXԝXԝXԝXԝXtt1ttttttttttttttttttt1t1t1E1ԝXtԝXttt1ttttttttttttttԝXyrүtԝXtԝX1t1ttX'ttX'tttttttttԝXttttttttttX'ttttԝXԝXyrүtt1tttԝXԝXttԝXԝXԝXttw4ԝXw4M**ԝXԝXԝXyrүttԝXԝXԝXM**tttԝXԝXԝXtԝXԝXtttttԝXԝXttttttEttttԝXԝXԝXԝXtttttttttGGtGGԝXԝXԝXyrүtԝXԝXFFԝXtԝXyrүtFFFFFFFFFFFFFԝXԝXyrүtԝXԝXyrүԝXtt  tEEtEEEEEtw4w4w4GGttttԝXԝXttttԝXEEEEEtEEtEEEEEEEEtEEEEEEEEEEEEEttEw4M**w4tt{#Ut{#UEttX'X'ttX'ttX'ttEEEEttttttt1ttt{#UtEttttttttttttttEttttttEEtttԝXttttttttԝXԝXԝXԝXԝXԝXԝXԝXԝXԝXԝXX'ԝXԝXԝXttX'X'X'ԝXtԝXԝXԝXEԝXtttEEtt]H]H]H11111ٳcٳcٳcٳcsxX'X't{#UГtEEtt =$:eXC$?H$>LR W L$HDU ]Hope you don't see this!I p$?M$CE$HCK$Cq$Cj$C`$Ap\$@EW$?Op=Y]TSP!K -a 'B a`c  :PN`4?`?`` n$Z(jeB6`CbE11ԝXԝXԝXԝXtԝXԝX> YԝXԝXtt]H]H]H]H]H11111111111111ECbCbCbCbCbCbCbCb8GaCb8GaCbCb8Ga8Ga8Ga8Ga8Ga8GaEEEEEEEELEE111]H]H]H]H]H]H]H]H]H]HttԝXU U ]H]H]HLeuw V]B s D n o p { k u  v  f$AX?$?`$?rVLS|h gKI$HBM$pCK$pCj$CW$!"pL V O ;$L?]Krallu Hr$?7$A/$8B<$ Ca$ CP:S ` B\D: :$ppppV client damage type WO by V+ -z%g::$2::$6^6^>^r+^?^^%_\O+S-!_%%PEw*%_%O^P%\w+*?+a/ a/+%D?%?33>!_! O%D?%?&gw* y%+^^Ou^%w*d^#^%w+* w+|+C?%^O^-z!M?%^O^P?%%sw+* w+|+f+O^-mq!rab? kD,?IH0eDdm1b @w44DpV Error - PlayMeleeAttack should be implemented in subclass T\}#G#i B6 L\;؎111111tt{ {t;$?MSkaarj WarriorHo~F [,`F53w*!!!q! )D$~L- = zuII_u[@Ww*&ruq!% TTw.u*.uq!% w.u*u.u.u-'~q! ?%a?(-w.u*r*-G.uZZ?&HZ6HJu 6JJJHJL?66H66HZCv! |^{~ ITh  _US@#EpV Error - PlayRangedAttack should be implemented in subclass qIjj$Ov-UO-+-RR::$M::$Xo$::$t-o$o$-66?% k xk  g2"8::$ o$ cGnhIf_; `IG Q| CWf~ i _,K`B6L*^Etf's5ttԝXf's5f's5f's5f's5L*^tԝXf's5tttta e $CQcAXDx?$?r{hUKM$4CE$Bj$`$A\$DT$ W$333?!"<$ BOpLVO;$]CowuH7$@B/$B<$BP:S0u@} S+I`*uwB6 SLEԝXԝXԝXԝXԝXԝXSLU uTQd X?$333?`$?rV|L$Dh gU K hI$HBK$HCj$ A\$Du$B!"L VO ;$>]GasBagu H7$`B/$B<$BP:S TLDgSda ף< >u!o::$P   b(-u!a%!o! =-(au!-'a?:w* b| !~.-'q! >u!::$P   b' !ou!a !o = !ou!-'t-(ի?,Y-?,aaar*#J  a- Nv!P r*#a =-(a'(6[6-$$-=u!1u!tի?,t !o-?-(q! ~TZ.Cj ovdL&IzW pOyDv{ o[ |L D] B6 f's5L*^ԝXL*^L*^tL*^L*^ԝXL*^!"(] Baby CowA$?7$A/$A<$B]o YehmhMIVXAa % W Xe:W:$ :W:$U::$|Xe:W:$ -G r* ::$ ::$ ->  ?> s X s IG=> o za X s l o L? az?%z?ez'ez( tH`yc+NMtK LKJ#fff?L?,K?,KLJ?,JLUaI H KJ'rU* rU)w.U*: .U:$'UaI H K'rU* rU)w.U*: .U:$ llE BpZ}\H$i$aB6D@6'\;؃tԝXԝXԝX1ԝX1ԝXtԝXԝXttttttttt1X'X'ѸBX'ѸB1X'X'ѸBX'ѸBX'X'X'1111X'X'X'X'ttX'X'X'X'X'X'X'tttX'X'X'X'X'X'X'X'X'X'X'K {t X|M$C!";$>MSkaarj Trooper[H7$B/$(B<$Ba$BZ Pzp oG]H^] UQ2 )--h'A?,-5'xx?% -5(D@?D-AD?>?-_ ::$ rb,%Q[7Qsl$lLTrw"ef ^vWs X  Qb?fe`T ի6s fի6s eի6s `aY!T ]&T DU-5-q |hdDwq ZN C X,L lsBXH  r 1FQ Sn["C;OGVpE[cY(WS`,l|mLNE TZw iJ`+Vawt#FBzT^TXCtK yw w DA<>-- ?,(-(-( k[~D5wT*aT$ ' dV5ws*as$ ' ab3Lހ*-(>(?%-' igl _RV D!a;-(*6w *  *q!O!Oq!Oh!dq!d!Wq!W!vV ! 33>qV ds g a l%pr*q!P I?,>TG=#J  a=a ::$ ::$ q!(!g66 ?6 q!(!gP 4u!a !v!HJ>=#P $a= !M @gMTTwAKTq^ya*N `uzAJyC9H)'.C  rPisJAZ@nC~BfW gGnxrt]r9rb 8 # F Ecq [h:66 r* (?a$ '4aT$ ' ew6>%w* >a$ '<wt*at$ ' ~nLz>\(d^B63pEt1ԝXԝXԝXԝXtt]H]H]H]H]H111111111111EEEEEEpEE111111Us Td~ t x  sD n op{g y $AX?$?`$?rVl |hgUKhI$HBM$CK$Cq$HD!"$pLV=O;$?] Mercenaryu^  H7$ B/$@Bi vB k`H  <$Ca$CP:S ]txY vkwaiNZRJy I:~} YRXMWy# ]m0r r*%(n- - 6 -(-r.*r.*(--(-M r*-F(Q -M  r'ta/!]. -F'[:Q:$-w (Xw*% -::X: :  -F'[ :Q:[S:Q:[@   b-a/!Va/!Vh@hL>@h a!fj?,-F(-F' -F' :Q:$-F':Q:$:a/!].-F'E-w (Y-(w*%-F'-.w.*r.``w-F _t-Q- G !r- :Q:$ -F V)ze ](Ag B6U CbCbCbCbCbCbCbCbCbCbCbCbtt?$ AVSI$M$Bj$$?C vq:N A/$Aco IQyJ {b % 'R--{ 'T.RX*! wT*T**T-H*!XT@@@XX-H:w*#w.*w..**-e ':X-e -H(*!nr R *`rR*Yry r *Dw*-a/!Va/!]  ? b-q! Rq![`q! ([E#-o$ !%, "|&xzB74\;EԝXԝXԝX1ԝX1ԝXԝXtԝXԝX11t1ԝXԝXԝX]H]H]H]H]H111111111EEEEEEEELEE111{tX V sDnop{LEZ NekApr$?X?$?`$?rV|hUKhI$ BM$Cq$D!"$pLVO;$ff&?]Skaarjur$@@7$ B/$8B<$Ca$CP:S `E^ [,[pB6c1EtttttttԝXԝXԝXԝX1zZmH fX ?$L>`$?H$?{hgUKI$BE$CK$Cq$HDj$ A\$D!"N$LV=OY;$]MantaH7$A/$@A<$Ba$BP:S@:^,rrB6 dEԝXtttԝXԝXtttZApby kX?$?`$>H$?rVLS|L$/DhgUKhI$BM$ CE$Bj$p\$D!"TvK[$>$pBLV=OY;$L?]BruteuH r$@@7$PB/$PB<$Ca$CP:S ȯv|_ ge t6Ak e \O_ 5qMr*%;!!D!! !-::$q!P!h ::$-_ q!} O :O:$q!^ :O:$q!u 5:O:$ -q!O0D!! hbw *:  :$ b v   v e!d bq!dc- @ ?X@?Xq!fcS-A ::$j6%q!ncD!G!` w*v S- q!% S-?a'(SS- --NS- @q!( h- q!>oq! Y GYF@O Ga!fC63J6?,x?>? >a!m333?!L !N !mCBE UTMtK T ]+gR(Rrg % K-| @N-$K`Ny N}wy ~q! u FiW XW+r Qcnenmg Dl#i g ^I`Oqn |"i&kb -e (k6- --?,K#?6?,d 6 --i-i --i-i- -- (_ 0@̌?::$k- ::$ ?%00?,?,w*0?,Q w*0?,O _?0?&- -i-i0<::$ ::$p66 ?,00?<<66 -i ::$ 0?% ?q!> <<_̌?6 6 b-F ::$0-i0?,-F  ::$ >q!>!\q!> _ pC0>d _y C@@6-vB_zCSvHB_C[ d#?::$6[ 6d6d6dw333Y?@0>ddww?ww[ :-{?-{-{666@?,"yd)a|p"(r)*- ::$p- 6`A?66)a|p"ծ?,#?"(- w)*- "dv - 66"yd)a|p"(r)*- ::$- 6`A?66)a|p"ծ?,#?"(- w)*- "dv !?% - ::$d#GGdd?%d?ddp"y66)a|p"( r)*- ::$f - 6`A?66)a|p"ծ?,#?"(- w)* - "v - y-i` _` _y?,_)a|pի?,(` w)*p|ի?, xxpaIc U(-'y>?J>L>-G?It-j??%&Y??,-'&̌?a/!^-5( 3^JTf | Q>Ua !A  !a >-(Zr*%q!6 --q!!Z- -q!!Z ::$P   b::$ b-'B>:a}--(qba}q!!Zd-(-(@aq!!Z-D'!>!Bq!(1  @-'a d'- b?, #?6 6 #?6 6?%a%!o! =aE-'a d- ?:  !I-)-- =q!-( !Aq!% =4r-'a !a  IBs\A2a*\T<P]SD Rv eNW$W3_U?%-' XUV RO# T-(* \ ]Yx5 } j{G4 R]bcdYT2ua-^4 U(yy|BvSlqGUSQ?Q Q 9 oYUC[^BpGFy gISi { SMZeSM vwLx y hr L r ShMHr a/!]p .r Bp $E$K$ Z)uKr* b6%b Bw*q!J!vIq!b 6e6,Pq!bw*ubw*ubu*wu*uu q!b fD  'v!-( nK dHdbr*%6 q! DmsPIMy|` C {f~J zO N "8F C-'Y6LF -b6F F66ī`D #6C`@#!Xb6b ף;@bb?6-a$AbV%q!!"6LF6q!!bq!!d Uzs A M N Qq KR vK@ U F"oY (}v!#P $ao-S6-aL?-S(= !Mr*q!#P >v! J  a=aY fff?q!%!gk- q!P #u!r*q!a !Rv!H !M iRgYMh*\ic ^d ^o^Z VH!F!"+G=633b6C-' {4m!#8a!R? P NqUVEt A QWME~ C F `H ~Z p|$Xq`  L ^mSRT U V Q#HDf ] qM Axmkd xK O l Sbxia @!\,T r 1j ,T,TԝXԝX,TԝX,TԝX,TԝXElsElsElsElsElsEEEtEEEFWv Qls~'kcB6*z AEtԝXtԝX11tԝXtw41ԝX11]H]H]H]H]H1tt11111111111tttttsDnop{f S` gW_\XC$??$ `$?r{hgUKI$ BM$CE$Bq$aDj$\$D!"($@OpLVO]NaliH7$A/$@Ba$BP:S@R$U^ a=(- ?a'(-( =b =jb-D'!^!Bq!(-o'#>a-o( =r*a !l- b?, #?6 6 #?6 6?%-(a-'a  !l = !Baa !B#a. q!W!v U"TBsMlG"<\G p~ j L@h C C#Wt f*xa,w* !s2 !y6%j >-(bybv!#$au!r*aa::$ >w>:@!d bq!d !y sy`OM2THJ N#CEx \*G);(q@?,2 a0>-("66a+~::$o$! T~(`k_h Va]+R-'U q!%- 333?=q!(-  -?L?a?(q! K+ 82::$o$ JS"B)NB6[ /3Ett11ԝX____ԝXtԝXttttt> YttttԝXGԝXkUUP]} X b  H p  ?$A`$?H$@?rEh gU KI$ CM$CK$Cq$zDj$p!"vK[$>pL V =O ;$Y?]Titanu HO tr$A7$B/$B<$DP:S0uJu r#p#x  E::$ k` a/!~.` C]?%#q!>!s bq!>!T [(g@qdU:U>62?62lU?6262?62@?&62@?&::$62@?&2262U?22-SB2g?-S-SB?2gV-Sgbq!b!F XEfuqT+s[]\xsvws*_sa/!As.s ss LQ K)JԿt&>!ba|#>a&=aaD-i-i( !U#>a!#a- >w !Ua !Ua !B Th vB(U<Vp ^cY" U'*-(? s 3ϥ&-(-($?%-' ] {VJ+|)X[!F0*!M\p!da me!e-!OB!W|?!!!w*q!s-I !Oq!O!Vq6::$,<2Fq!G H_w N`t H"35 C)!6--(t  q` v! ;` !mq! cF N ~ NKH IN,Z,fR "r.*?$ .C a@ (rC *$$ hP o` a?,aL=n::$6-#!q!!\!qq!  }Jiz td _} l!Yu S @ yO-o$ !da333?L>c-  w*aaZN#a$aQ6?jo$w* 6zC !Ea !d-#a-- ?,a ף=i!-(b!qiq!-!L>a&L>-(a!qq!r*v!1v!qv!9/-,-6%6CW6-o$qk-Qs-(QaY::$ !da@ !E \t s[d-"bE}iIz U+I-'FF?FW>>-B!mk?6F?,&̌? Af OtVe%zV Y,t u B \IS$ "_ }H ziTD Rv`F B%A%v D GKS8GBCe~,% Q!!(! W HywlO@ dt} v9v!-(7-Da( X 3_ -D( Z\ j{b Rp {ef eh {jej SN"ByEwI* I ?I  -@dd d xd B'wI*IS 6e e >6?6w:e ?66?w6@?&6@?&-oB(-o-oB?'-owI*ISq!x!F ~yDp(uvf1[Crv}Aw.v*.vq!% prv.vq!% ?%a?(tRt?&^t6^]v 6]]]R^]fff?66^66^tHCv! q pK`L*qGIF~ x--j-j(-Y(H6-~  a!Pa !* -a&!*~  PDGoO{DPaSz v!1v!9v!+ |Aj FN46FN-h N333?CNL>a!Vai $gN>a!]aj $N333?a!zai $a!Haj $ LiZaY+ec[qvec Y T DJ"3Aծ?,<64Co$-', r}I`ehsQ wUYDU_ .Jl  ,N[\ a b ^sFUYr&-m(h-$?@?? ff&?  ?-'p-(-@ @ g@C|sVa"_"EǕ3r*%D!! -(fjf?,::$ f?,ZD!! ?%-'Db2-A?6?, f?,' 9 *6BD!! 6n#?-e( ::$=aihn(-er=*-e=aih (-w=*-' @ *N--(Lb<}q!nLD!! -A 6,::$ 6,<D!! U#$tI#$tI=aih n(Ur=*S?,=aih n(Sr=*  -?,* ::$g 6g  6gg =aihgn(r=*g/-e=aihn(w=*bXq!f!T-A  ?q!nD!G!`   hh"SU a! > HP a!* > pff+} ]MzVr*'r*Ta/!\P  lD?l?&?,   ? ??&lD?l@?-R } ?%?333??  W} 1aUW(w1*? 1-%6?,6 a/!\ w*-??&1aU#B(w1*U#@@1aUW(1w1*66 1aUW(Ww1*66 fff?1aUW(w1* r666?w*1aUW(w1*$$a'(#PW6#D?6#??,ll-Hw.*.A} 9#6#6#?6#6? )?6#6?v6#696#66#66#6 6#6 ## z!Tm Lb^"_edf T&g8TpwvD,% -g' !: :$!^!!!q!q! tyo I J!nh\#$au- -| ? ?,}#a$-S6-a?-S(a?)-  -|@ ?^@?^q!f!OG;} !Gq!f!O LwqLm |Dvd`@`LKE |EaqOq!(!i ^q!%!@ x`vCeBv"ag#zYxO%4-w !Qb&L>au!a>#a&!>?aa!H>>u!!a@?, v!a !za !z# ^a !Q FBQBB.zMrNE Z O Yc8YTXZ],% [!!!q!a_ Xw# <$-(-o(* oHVJKPV66G 66{G  G _(' Z[^V 6cbZw.*BL>H-Z ,b?q!`C{w.*b?BL>-Z ,q!^!U-Z ' ](\s6 3rw.s*>rs.sq!%w.*- .^ ?%a?(XiX?&OX6OMs 6MMMiOMfff?66O66OXHCv! ^A C 1A ;rA B>q!!dqborq*B>q!!dqq  (Qn p<n  L?gw.n *.n _v! {# /ecr.*b cr*K-a@@(q!(cB>q!!Z b` a&!` s | !|#, <,*!^!"q! eN A+a!̌ > a!w > ia!̌ > gklugqXAwya!F̌? kJ"jrz{Ng ~l@BsKDlZ8>T _X$tR h#8?aaL= !y2#mJ aPL>a: :$V b?!q!D4b ?&>aa?D#D!! M >8yHv%d%"r o$ EMyNAm L}PPB#a>aa !G#u!+a.(- .-u!1.!D- ::$$2.!a&.L>?J aaqw.*a.a.2.?%wa.2?%a.?&(2.aaWJ  a>aP #a !U.-u!1J.  a. H.!a&.L>aa.\>aa.+v!!#J  a0L>a a) ?,b !Z >q!}v!#w.*!J.  a. w.*.!a&.L>aa.a}L>aTJ  aL>gagaga=a!D!!q!} S;ZhxU23G$cSWX] Up[jM%W r * 333?Tw.*v!" *.-'2 L>a bba&w*bb w*#>a =a a !e&sG::$#L>a a. !u!"v!w * *::$#2L>a a-'"66#>au!!Ea+::$o$ semv B#^di a`+ce-'u!\ q!%- 3-? L??{.>q!(  BS8BD~FY,% Q!!%! beEfn'w%d laa !Uv!Y ?, !F L>a bba@?D#>a =a a !U#>a a?9 !-(L>au!!"66a+::$o$ FsU-&TDlm\D#H xEb::$ }-e  ?! H ?%P y(-e 'H ? otsRu{^f}Lw.*.- b!q!-( >-(bu!r*!q! b-w.*.--'a  -(a (w*b6bgr*!no path to alarmq!7w.*.--D'!>!Bq!(-o'#> @ a/!zAa =-o(-w.*.--'a -(a -m ::$F ?@ b#q!P!hzw.*8 Y ?, Y !A ArLnF@De~YAGrm M(b&>bau!xaD#lq@?,2 a~>wu!!L>a?v!a !za- >wL> !F !z# a?, !va !B T#FBv1BzDILN] PRUVWS_*^*"o$ }Ri s1 q! \_`afHb!RP-D:D r*% Nq! ~YX| ,rX rX*w.X* X-u,B?$B?::$$::$$::$$LSX:L:$ :L:$`XX N4i-?--J y??>D-(a'?(- a333?(  h+S lOkoLp+ws8|uv z7%u-Lo$5o$ Yqzp~x' 33?w::$ ::$W66 ?W aY i (wW *(xY p!g'( t|".8q!c"|  h#P ]M -V ::$8P mkS T >% !z: :$!^!::$- -S ?P T (!!Z!>!q! 8::$- -S ?P T '   -V  r ::$ ::$U ?-{U V  #?6V իU 333?V  L>-{-{ U,GX. - -?q!(,q!!Z C w_ X FJLPN@Ja_)RVbXb_C`by&ec gI&~$le#oqsrgnwKI {!@ f9oC{|OAEBwt!E21aa] )wa*ana HFQ KGIS LHOHQTo KQ &\--3 Q STolZZQ %HH?Q ,d> b WDZ [W X+\@+C^iS*Mf=&-la!I q!S;MLJ rsO{)X rOpf(z^~{9u2#o$ ~|]PlN^L&8l Jv fO(J-%::$o$MM::$o$q!c hB kNj| [a#je %> ?,2Y 6j-V-Z6M6M6MRa@ ~ ?,j(MwR*-V-Vj?Ra@ ~ ?,j(M wR*Y Ra@ ~ ?,j#??,j(MprR*Y ,-Va!N̬?a!F̬?j6HCo$q!!\ ] @ \]^_k M"Q#ZF9Q #?#333?"Q?,96- 6 -aq $? Q6?Q::$o$u!a!N7v!a!R? (PAC&-U !Nv! ,g-Uw.P*.P4u`jGP P d!eF{R35&e?a&!"=3a&!== g_WW@ku K} K fI-j-j(@6-K d- !Pa !* -a&!*K S|6aY!]&-5-q b@A%a#fff?C lq Sl+j ` X*c*"d do$aF6Z633b6C-' iRd eSa8lx/J[ll6Cy-' `)5I^GHIJKLte uk u mo e@xEN\eO[6M%w, s,6K6 ?-[Ks ,a  #?a<" @:w,*, ,n, 6, 6, 6,a  #?a<" @w,*, ,n, 6, 6, 6a(((YSwY*YJ!YYdw*d!/a0 GG R10@6ff?{a U{n{a KcHFsj&wdsNn>B |BL#fff?|?,B?,B|L?,L|GOzRիfff?Gի333?OeaBDRBLR'Qre* re)w.e*: .e:$'eaBDRBR're* re)w.e*: .e:$ e  \@{=)aS$? Ca!B?= Rq - p6- ]>?q!- q=ax$? HDa!`Y? qu>a\ $> Ca!g] - q{>a!\]> @@!\+q>a!]>>Za!\] aH$?'C]?a!] VfgjW(6-M(!!6 ף=jDf \#H` nt`C\ zb(kHCS k B k; }Bm[ 7.6- a&!> it J ?6- b-YV??a!J Va $ t-jV>?r*tfff?a!8V?a!yV -u!-K-Z0!w-Z(.-S(KKL?a!wV .-S ff&?tL?a!8V?tfff?a!PVa!yV .-S'-Z'a!K V r!|U- t>a!B>?aS$? Cma!L>333? !Bt?aS$? Ca!B>?a!L>333? tL>?a!|L>333?=a!L>333? 4Tw#S}Hg'6-a!d@ H!aw>Sw33>a!a?w 'G6- d! >?a!|L>333? "- !| >aS$? Ca!B>? ""!B ?aS$? Ca!B>? a!L>333? BEe*U6- ;>a!|>Sa!>? $C$.+Q6- 7]a&!H = :a!K333?> {|z Y,W-j-j(-Y(H6-z  a&!z  NP }  &/3$6-  a&!  h Jb0!/K$6-b <-ja&!8b a&!b L@003$6-@ a&!@ ENQ:.1a&!D33> PY?g1a&!DL> QyD1a&!=L? RhFI1a&!== SyN*2H'6-a!d@ >L>a!P U [2k6- ?Ua!* > a!*w > Vl3.6- a!Ga? WYvu4+)!. -a&!.Y X|4a!. > ZU5Z56- U>?aU?a!>U333?aS$? Ca!B>:UL?a!K>Ufff?a!G >>a&!> un%z4)z 6-a!Jz{.>||!z{.>z?a!Ja!!Tz{.>!kz{.>z?a!Ta!k J{  PX d+U#U@--m >-(-m-X  ]".&-a!ǎ ?,i gD3>^'-g jga!ff > i A+a!ff > a!w > YS <5r.l*.la jr.A*.Aa .l-'.A-' e]VOG- w*-u!gp$- e j_W-R-b'W,w*-'\W +>aF$> y:W~>aG$> y:W?aH$> y:W*?aI$> y:W}?U?aJ$> y:aK$> y=> QaW~eEQp3$'-Q Wc K$rW vfya!Fff? \ ty(v&8Z|vzt \-|-6|-?OO::$8| YGrRa&!)r m{y.$!Ca!J?L>,a!J nL MB ? _Y%~!^ ja%!P ?,  ?@a&!Y|a!^?> AD6CB@':d ?:d  at$ zO C"-f ':{# DX, L> Ms <sa#? HD Bqr3-m(D-$?@?? 333?-'L-(-@ff@L> ~@p8*aL$@a!k333?= [t .3A?':bի<bzD aE $ EI8ZE!f ?-{a  #L?a<" @w{*{ {n{ 6{ 6{ 6a!z333?=W6?,x96C{?a!R333?=a!l333?=a$@ olc%bJ 8rb Lu $a#?333?>;D }LU -'y>?J>L>-G?}?-G(-(L  FUw!L> UM?UVWiLfLWV Bz@/Jw*zj*=::$jbz'Kjbz-l wj*-l jj -l  j`0.&-a!ǎ ?,i (Vv!K!m':q ի<q zD !f':s ի<s zD -D'?6?%6? "wSmNr prG#fff?p?,r?,rpG?,GpM A {Mի?M իL?A ի>{saO N MrGM'Ywsw.s*: .s:$(Mի?M իL?A ի>{\aO N MrGM'r\* r\)w.\*: .\:$'\aO N MrM'r\* r\)w.\*: .\:$ {NF a!C BSi;*a!R333?=a$@ Br-m(-( OTj@<*a!l333?=a$@ BD3a&!i> CUE8a&!i> DV$=Sa&!D> hjwUM- w*- ?u!- h [\T ,\.lX.Au Kv `u Kv ?\a `Xa `#@@@\\ HKXX HK } F[ Ga&!i[ gX:T]U- ?r*-u!Kp$- g Q`F<Q'6?,da!l333?=9a!F 333?=a$@ dk~OG- w*-u!tp$- d L\v0Qa&!iv ]hpGH5p-bw*- u!- oF3;3>-b(0w*-(9- rR a!C > sKHjr*q!hJw.*.%q!hh-Da'(q!!Z Rmyea&!D> SdnFja&!I= Is U9<I&?&D??:?%$ Ueyo; a!D [adxpu!6d- ?-n_w.d*.dA!d- 9k25&6-o$$o$ Xym~a&!im fc'r?>-'-'-'-'Z::$-'p::$-' }[z5e a&!D> ~m a!i [pxe3o >?T 6xj?% ?x?6G6G6GZa}C?,x(GwZ*x?Za}C?,x(GwZ* Za}C?,x#??,x(G{rZ* o ,a&!D>x?6HCo$q!!\ 9s2 46-o$22::$o$ i =a!G=? I L0!Ja!C?>Ja!C > BD}o>%U0 a&!CU |vF6*a!c333?=a$@ CuO_iK-Lu \r*%N!!q!G!` v:O:$q!u bw *:  :$ b C  Cq!n =-4 q!%;q!( q!(!h Wxj*a!e333?=a$@ y xz"}qBaE$a!)> bS& +)!C -a&!CS Tl4 a!D oEv8   AO{{ a&!O [Y[Po$ "ktMb)/H6-w6*a66-ma  ի>9իL?#?wm*m ף=<ma  իL>ի333?#??wm*m ף=<ma  ի>ի?#?wm*m ף=<-e!X e!V e!f e!Xma !Y--h wm*m] ~EH?  kB a&!iB $E$Msa!)>= LCI*a!P333?=a$@ Tc,F4gwF-h Fff&?9FGa>a!VuSFG>a!]umFff&?a!zua!H `uF O@Y> u!wa&!xuMa&!wu _PHp#*aR$@a!G333?= Pv&]+)!) -a&!)v Tha&!8h D}KE?K_a] _n_-'_ _ ut W+)!) -a&!)t MR0ca!VL>L?o$ !EG,q!!E sE -' dQ a&!)L> Qzia&!)z [ [m|e2.6|7?% ?|?6j6j6j~a[ \ ?,d|(jw~*|?~a[ \ ?,d|(jw~* ?,|?| @q!!o V n&aE$a!) > hsF a!V jy # _ Y B?a&!L>@aE$a!) > Zt? &aE$a!) > ^5z 5&L?aE$a!)>3a!b > ]bl, *a$@a!O333?= Qt 5m~ et ,t 333?a!8>>cPt L?a!b>>c:a&!> c`C6 a&!C f`}C$"7n}?&f!faa  ի333?9ի>#?wa*au= #=nnf!VqիL>S6q6q?Oa  SqPq$-h wO*O]n-X-ha  Sqna  Sqw*- -$$-y -BY>>} ף=? ?,a%!oa%!U- r*-v-y 6|?,,-M!}u<?,?'}{.> #=?WD}f,S}55!WD}f,! UYI a!) m4[ Na!a@',ի?,zD a$q!!W 4iB# a!a djR IAij?-3 ?%i= oa 4F a #L? a u!-D(~?a!fai$a!mag$ m@ .>0>,a!k?L= [@ a!m?=a$ }Q' a&!kL> 9p2[` 46-o$22::$o$ ]_O 0?w.O *r.O * ?%q!x!z{{O  L?v! WwwmG| K5]v` Rի?]ի>` I& L>XaY!R]&R-5-qwX*X?,3Ga S !Rծ? S]3wG*GRGI g3g 4@#V`KA!^ ?,[a!d Ia!h  nt~D!B@':Q ?:Q   a^$ T rr a!k X Y`+)!k -a&!kX mEsB@':j?:j a^$ cVT a&!kV }H4C@H,H?aE $a!b>aE $a!T xo BB@':c ?:c  at$ UFC;3>-b(0w*-(9- [BbxpF!6b- ?-n_w.pb*.pbF!b- KjrxJ-w !Q&L>au!xu!a>#u!!L>a@v!a !za !z aX !Q FBQYB+z]CTGH5T-bw*- F!- {pP "XD-f = ?aN$p 6pa+pw.*.CuPCG #?w.*.IL>D  jEI-p-b'I,w*-'aI +>as$>?, pXI~>ap$>?, pXI?ar$>?, pXI*?aO$>?, pX5I}?U?aE$>?, pXa^$>?, p=> D@G]Ba$ D IRa$L> C REP  KEJ  A]43 ?aM$ D1aN$ D E V. -g '  NE\z   y[F [06)o$-Y '%, "Q =-::$a&!G A+a!k@? 4jq#fq#6q?, qa!J T T #g-c (-d (-o(<6-T  e!* -a&!*T  SX Ma!* > T^ &$3$6-^  a&!^  Wn qM`o 9c#?ho n _aw Vchc(qr_*(hV#?n ?h?_aw Vchc(r_*h'h?_aw Vchc(Br_*h'o ?,' VY 0$K$6-Y  <-oa&!uY  a&!Y  ` 3$:-b?-( Xr%3$6-r a&!r E[)a#?333>;D Z 3&k?*6- Ua!* > a!*w > \7'.6- a!L? ]G'+)!. -a&!.G M@2a!Q?=a^$ ^7(a!. > `Q(a&!S33> aY(a&!SL> by(a&!=L? ceFG)a&!== dy)D-3 ->G?,  Dqe6-a!d >L>?a%!oa!Fa!F?L=;%a~$a%!oa!ra!r?L= fC5e,6- Cr?>aC>a!r>Cff>a!Pr>:Cff&?a&!>CY?a!Ir>a!_r>  iID WDgIP pppP D  F"` _s4s#6s sx?ay$a!D az$a!Q q lpA.*a!G333?=a $@ O vO!qi^2*a!P333?=a $@ psjd2*a!O333?=a$@ rh!Fj*3*a!e333?=a $@ mGnD#f! cbG 1Fba] Dwb*bnbw w!B^] W0wI* 33>I t`wW* ?W t?,P66B?D?66UB?@B?!B?66@=66@?,9 wf!j!N5@ v@|#fff?v?,@?,@v|?,|vb p yKիfff?b ի?p aao_ K@|K'Qra* ra)w.a*: .a:$'aao_ K@K'ra* ra)w.a*: .a:$ Zu{6)Za&!i{ AY a!C l  _v9r!2?D86-o$6o$q!c OQza&!CL> Cz .a&!i> yB79a#fff?̾C FW]Ba&!D] !H,a*!x!Bq! zJbE Ls#w*: :$ bT-$_`B?q!  q  A]_-'~q! L4M#,at$ ף< La!a333? N@a!?= $d#$oa!?= Zn62?a&!n0a&!Y ?n P"G >B@':}?:} a@$ 4P#1@P-3 -<G?,qPP@?$ q6-a!d b?33>a!`B;%a~$a!U ~QG1BB--V -3 H?%YBa!q v-@ :b ,b =:b &q!iq!!Z R^i,F-@'#@J  aa&!_=aF!-}?a!_?a!K?a> !d?a!_fff?a!Kfff?a-'q! dY\JD6Y\u`4% -Hq! RUTaDZ8a_^]\,% X!!!q! W[Yl Ka$@7?a!J 333?=Ia!G333?= f  a!C JZt&LGa&!it N^rVa&!ir X1*F ScqbIX#a!s33?)\=aa !j j%@{J#a"Jvo$a>>L(q6q%6q@ 6%a+qa$ Ca&!M> qI#SHja!s-3'-'G?$F-'$a!Y hq! \ _h(3L+(L?&=L?,?,f*!O  o$?,6*C?,6 6a&!c= bt5 et,t333?a!C>>cPtL?a!E >>c:a&!> E"Spa!o=> X W# wTKTX R-3-V- H?, @?-'Y (jv!m!c !Y !M':R ի<R zD o -l'?6?%6? "c#P]Q[1a&!D> QlY`ka&!D> pqrsoVg tq a!i vj#Fa&!"= wYFa&!*? DQ a&!e? Wty a!i Zj- a!i xc.]T!f*.-'(!W!z }Z) an e~V/'@'w* >a$ ' >ws*as$ ' cj<=fooccի?oba%!\ !Wi6L>i6>b6ci6o?%(o i6c6o6ci6c6c6oo 6c6c6oo bc(' nFl %a$@a&!I>  ]$lr z l o G{l ,?a$< LIa $< L~6?, @?a!e333?=?a!Q333?=a!G333?= NH @ a&!> Q 5 E>? ; >!n 333?ag$<!Qah$<!caE uWo a&!CW L n#Kfa $ fJV|h q,rV rV*w.V* IV-$ddr.V*`VV dA@o a&!D> bMVN3 C TCN#fff?T?,C?,CTN?,NTYZaPիfff?Yիfff?ZTaw[PCNP'QrT* rT)w.T*: .T:$'Taw[PCP'rT* rT)w.T*: .T:$ o$X{ a&!X m$]} a $? C v@a!b333?> Jn"q!c"n oXX#% wP_C'TW2 }${X%6-{VI!Wa!{>>Va&!{ \[&q a&![ Yy s%6-y!* !H -v!Wa!{>>a&!*y ^Z k+)!* -a&!*Z [v &s%6-v qI!Wa!{>>qdw*a&!]v qa&!v  ``fOa&!` ]v0X%6-vVI!Wa!{>>Va&!v E%Ea   _u s%6-u qI!Wa!{>>qda!da&!\u qa&!u  BQ D!Ja B!C -a&!CQ a ;6- a!* > hci N;6- a!ff > dc6- Gw*a!]@ >aa!@ > e5"6- #k!_a` $a!S>333?>!S?a` $a!S>333?!Wa] $a!W>333? >a!W>333??T fT@26- -'aq$P D a!_ g O{a&!> hr lUvdr !f%6q6?-Ir  r q ky 84N >>y4H!Qy>!%zy?N ?!l%yH:?!H%yL?at$ ף< L!a%yfff?ag$<!Q%ah$<!caN  o%]1as$D< zD nO@a#fff?fffC \~q   s%rivY*a $@a!Q333?= qtj|*a$@a!G333?= sE&Fo Ka$@7?a!G333?=Ia!Q333?= DCy>xMnr-M--M-MMMMMM!a!v333?o$M M M !!q! @@# a!D }f8fTUVW,% !h: :$!^!?,f7?f?? ?,-P'!!Z!>!q! J&4!'6- 5 4z#P"'6- 5 {"9o$a!U?fff? |M#a&!UM C@ WJ>?@4H!CaJm!Cj@>!{!{@?!C@ff&?!P!C Hni.*a!G333?=a$@ jwFY\&^%kLbCw.**, b?ICi,q!B [DZ%'Yw.Z*YrZ.Z-' q! a?(i6iq Z 6q iq fff?6i66i66i6iv! eKYSde0Ya/!N Ya/!`$c`Ya/!oYa/!z$c$ ^E)r.*b  \IkC E*{k7rk r**yUbZrU**yUU  L w`&f$ UJ +-'v!9 rOA\ t%j a&!> Q'L"!o$ S{&\f0La&!8f Ti&P'P9e 7YQ-q  >-q 'ao$!ya>?W8  Vg8I5!W !Ra!W@?=Ga!R333?> wZ%-P 333?kC0kD-P([ w@?[?,ww[ pCww[ [x C@W [#?cL?@wL>yw?%c?[[cL?6[?6[6[c?c~cW ~[xk66?,<ff&?ktx6p6p6pqaABt(prq* [~xk66?,<?ktxqaABt(prq* [xk66?ktxqaABt(p3rq* T-Z [?,xq!>իk666 9X2KFo$ cF1:9]L>?F!p- F=ax$? HDa!`Y? Fu>a\ $> Ca!g] - Fff&?a!\]> FL?a!R>=  n!\2FL>a!]>iVF33>a!R>=iZa!\]  !Ra] $a!W]=  !{a!\]=  !WF>a!{>a] $a!W] aH$?'C]?a!] Wvvd]d&a&!d _A Z-a&!aA/a !F X! -a&!A  F%W@o8F^_C],% [!!!q!mmw*q! m@s<=Fk@k^*%E wE*w.E*E-(Ea!JEa!b.Ek@ r^*^E@.EkEEA+,^ q!G!`*e!q!J VIl +O@Y> u!ta&!xIMa&!tI [a"=q!c"a $T$[ a!b333?L> N @ 0"N !f N !L(-A?_??>??=?L> L? gEXa!o=> f+  u! (F(f  O1w.f * wf .f F?%a?(v! c' UC-a (v!X g3[-D(-($? m X'jJ|^FfvE1!-m =q!B'f-m' Jilb:Gb F1!-m =q!B'b -m' qc Aa-'-'-(-'-G'I::$-'_::$-' dC]"a&!C @(@ a!A?= D(Y a!c333? pjJ#wR*RIp ar~ `?>r{!8Lr>a!K`xkr?a!L`xa!8`rL>a!K`a!8`!K333?- 333?w .[T!.333?= atJ/aa!{?L> (XjXgv!-D'-D(eJrj-'q!%ee%q! }} ,CN>?}hH }>Z-a$333? HD!~} ?!S }333?-aR$333? HD!W}333?!]!laN TQO!8b?#0L> (wFc  mR rD-'mrs f_ q!b m @}J~q!b  c(v ]+)!{ -a&!{v W\[l 6?a?a'( !d W\u&ca&!{u DAt0hpa&!~t Cqma&!~q E r &a $a!{ > Gx &a $a!{ > H5~   I 2 a&!{> JLl a$`@733>a!Q333?=?/a  #L?a<" @w/*/ /n/ 6/ 6/ 6a!G333?=/a  #L?a<" @w/*/ /n/ 6/ 6/ 6a!e333?= M/BUy9?v!9u!+q!P! KP6U a! e(Bf 8P-'a>?f!Rff)\=a!8a> a!R>> m,!8fL>a!Ra> )fp>a!Ka) f ?a!La)a!8>>>mPf=a!Ka>ma!8>>>!K333?- 333?w O@a!W?= pi)1U :8.-u!9v!1v!+q!P!c Zz {k\Y> u!tL?a&!tz Ya&!wz ia&!tz  oL)X%H(AJhv!frA !Nf':X#\?a~$faV$ ".bTP.?&-5'5?%&Y?NN?,&̌? hB nk\Y> u!xL?a&!tB Ya&!wB ia&!xB  }2o$ Q R)GpqB a0>-(B::$o$! TB`PRI}U/$~-'p?@?IH-V-V @?&-G-V|-?-?L>> ]K*T6 a&!T !q), *!}!nq! 8^D v;|\-D -6D -?OO::$8D  g Rt-(*-o(l-)::$ -_  ::$q! A h;-o,&- ,i--? sAr*pw.*..!/a0 10r*!q! a}eR-$$a@??'( .~TT<.&D?,d?&= jx r !,(wx *w. x *'( it[$Sw* Xt \t %$$ N?$$ B?Z neF a!= pYa a!k G ki[ SA^i?-3 ?%^= Q*5 +?a!o>)a!> l r9rX*l MbXbXMw*  wW*X ի?,XW X X  r \}MK.PwK*K!/a0 rKw.r*K-.r`r R10~K-\w\*\ J!\\ J!Y!/a0 rXr R10*@a KK#: :$q!P!Sq!PN!Aq!}!N?: :$#q!JN-'q! !x::$q!P!S-'q! t Z*^Y]r^} D!z,NU*!}!nq! W*A];-v(aQ$A xg ~f;J!/a0 g J:g R10a@$@a@$@a@$@a@$@a!~-U '  u77-m -m- ::$8u|{ut_% !-m  ::$!!!!}!nq! yM w <-vAMe L>?a!}e  Lg6 a&!g d+ * $|$W 0-vA(a !Y ~ t D-v! !* =a&!t @s +)!* -a&!*s A_Yh[ b -3 LG?%HG?,G`H?,q!q b*f0 a&!}f Eqvr b$-(-($G-3(`6- Fh a&!}h Gs ]  % w-3[-V6-6%Yu-3? H?H?%$G?,?,q? H !a!* L? rI_A_" -3r_[W Pzl@ *a$ @a!Q333?= L+ )-vAa&!*> MOla!m 333?=a$ N+Q #::$a!_!a!k R59 &L?a!k$a!a> |w5+::$a!_ >3a!k X^m0a&!k^ V+}@u}|y*:P%b?Pի?&}ի333?L><PyիL>|aY!P]&PD?,:P`@(-qPի?&}ի333?L><PyիL>|aY!P]&PD?,:P`@'-qP ^+Ksa&!oK ]S0ga!=L>?o$ Y sG&h+)!o -a&!oG k+H186'~PCG aX $ []i K]Z ZI'S`jFZ #?aF$ }O &_I::$a&!_O GG!k -a&!kO  \ ~[Lbr*M ff? !G &>au!b#>a&=aaDu!Y ff? !G !Y#L>a a"66a+L>a@aD!G!` G_YQA tXE8Avqwz<% k!!!q!rq! \r4s-vAr;r>aF$a!Wq_r333?aX $a!EqaX $a!  c+h" -D =q `Qa&!DL> $L$Oa!a?= o+eFPa&!==ONwO*ROOO! O1^ 4d#(-vA1-U  >~w`* ?1 ` ?%~w`*`aP$-U (a!aao$ WgiFwwAx$>q!S"w-w \ Sv!q!x!z I hlfPYMN: q!S kL S#i oU pqrC,nE bw+)!o -a&!oE nuxU rtwAU  xyv{fU |}J zS X\r::$?,S >a  va  vC P 6C %a va+C a $q! @ D<?,dS @ ,P-'@$=@ %, M M W+ A 3v5 -( D k%r*v!1#v!qv!9 ~JbJHD wJ*Ja/!C fwHHJ ~ J #?} aRQ ~ (r} *f@FffJ  ??,J m6J 6 f?fD D fHJ JJ*vH u//============================================================================= // TeamCreatureFactory. //============================================================================= class TeamCreatureFactory extends CreatureFactory; var() int MyTeam; //Team which spawned creature will be assigned to - 0 is defenders var int Team; function PreBeginPlay() { //Azathoth - I've removed the secion that destroys the cf in the case od NoMonsters Super.PreBeginPlay(); } function PostBeginPlay() { local TeamSpawnpoint Tnewspot; local Assault Test; //variable definition Super.PostBeginPlay(); if ( (Level.Game != None) && Level.Game.IsA('CoopGame') ) capacity += AddedCoopCapacity; //Azathoth - same team assignment as in teamscriptedpawn Team=MyTeam; foreach AllActors(class'Assault', Test) { //log("Assault found by cf"); if (MyTeam==0) { Team=Test.Defender.TeamIndex; } else if (MyTeam==1) { Team=Test.Attacker.TeamIndex; } } foreach AllActors( class 'TeamSpawnpoint', Tnewspot, tag ) { if (numspots < 16) { spawnspot[numspots] = Tnewspot; Tnewspot.factory = self; numspots += 1; } } if (itemtag == '') itemtag = 'MadeInOz'; } AH _eA!t! J 6-  >?-c u>a! ?>a!W ?a!W ?a!G 333?a!} @?a!{ /L?a!w NY?a!s mfff?a!q 33s?a!m a!V  v-d r*-=a!q ?a! ? F!-;?a!I ?q_@?a!_ ?qa!K ? -or*-a!u  F!-?a!W a!X  -g >Q! >a!P a{$! >a!q a! -g ( 9U 2((w*o$&&::$o$ r//============================================================================= // TeamSkaarjOfficer. //============================================================================= class TeamSkaarjOfficer extends TeamSkaarjTrooper; !I ,_-q! M 1Yu!9u!q @G Z B6J ~P@6'K !"MSkaarj Officer[ A$̌?^7$ B/$8B<$Ca$CB "#b K 3B#(-($? BI n9R 89nv!9v!q b^ +0rw*-' p//============================================================================= // TeamMercenaryElite. //============================================================================= class TeamMercenaryElite extends TeamMercenary; pP W B6Q NpUz !"A$?]Mercenary Elite[ h //============================================================================= // TeamKrallElite. //============================================================================= class TeamKrallElite extends TeamKrall; function PreBeginPlay() { Super.PreBeginPlay(); bCanDuck = true; } function PlayMeleeAttack() { local float decision; decision = FRand(); if (!bSpearToss) decision *= 0.65; if (decision < 0.22) PlayAnim('Strike1'); else if (decision < 0.44) PlayAnim('Strike2'); else if (decision < 0.65) PlayAnim('Strike3'); else PlayAnim('Throw'); } [ U z"K-c (-d (-o(<6-U  a&!U  8V MvwuM-[w* 6 6q!!Wu#? c=-'-'-(-'-(-( (y!J]!gv!-l'-l(eJrJ-'q!%ee%q! e!$O$a r6- 7]a&!Q= :^?a!I333?L>pa!_333?L> Z Xu! L> QUa! > L Q_ Z$=-L (48Z-L '!!-L   a R۾8Rm VWX,% Xr*m !!ww* !!!q! x #Ld*-(-'v!!yr*-w(v!1u!9-w'u!1v!9 b zQz6Y 66?,Y 6zb 6fff?6z Y 6zb  8o g v68vg 4g -0>q!![ R I^B6c FCbLe&uf$@L|L$\Dh!"$A$?] Krall Elite[ J//============================================================================= // TeamGiantGasbag. //============================================================================= class TeamGiantGasbag extends TeamGasbag; function SpawnBelch() { local TeamGasbag G; local vector X,Y,Z, projStart; local actor P; GetAxes(Rotation,X,Y,Z); projStart = Location + 0.5 * CollisionRadius * X - 0.3 * CollisionHeight * Z; if ( (numChildren > 1) || (FRand() > 0.2) ) { P = spawn(RangedProjectile ,self,'',projStart,AdjustAim(ProjectileSpeed, projStart, 400, bLeadTarget, bWarnTarget)); if ( P != None ) P.DrawScale *= 2; } else { G = spawn(class 'TeamGasbag' ,,'',projStart + (0.6 * CollisionRadius + class'TeamGasbag'.Default.CollisionRadius) * X); if ( G != None ) { G.ParentBag = self; G.Team = Team; //azathoth Hack numChildren++; } } } d d A >;$?ah $L? aD9af $L? aD g RF;$?ah $L> C9af $L> C 8h h vNJ\-h -6h -?OO::$8h  f i c\~l333?=-'-'-(-(-'b::$-'-G' 9k 2j 46-o$22::$o$ l Fv ;3>-b(0w*-(9- [m {x pA!6{- ?-n_w.{*.{A!{- rj A\ ]n AG H5A-bw*- A!- g 7f..6- a&!> jp Q- -b'Cff&???}F>off??}FL?Qw*-'Q +>aH$ }qQ~>aN$ }q Q?aL$ }q3Q*?aI$ }q[Q}?U?aK$ }qaG$ }=> Se vU B6s hSLԝXSLSLSLU(uA!"X;$?] Giant GasbagA$@@7$ C/$Bb//============================================================================= // TeamCaveManta. //============================================================================= class TeamCaveManta extends TeamManta; ct ^ B6u [mc1zZ!"2= Cave Manta[dr ~OG- w*-A!tZ $- d ev VOG- w*-A!gZ $- e hw wUM- w*- ?A!- h gx :v]U- ?r*-A!KZ $- g y Hu.333C>?HMHL>a!8C?|H>L>a!C?H>a!WCH?a!WCH?a!GCH333?a!}CH\B?a!{C6HQ?a!wCUHGa?a!sCtHףp?a!qCa!mC  h//============================================================================= // TeamBehemoth. //============================================================================= class TeamBehemoth extends TeamBrute; function GoBerserk() { bLongBerserk = false; bBerserk = false; } d{ P[ B6| ^CdZ#`$?L\$D!"] Behemoth[A$ff?r$@7$B/$B<$CkD!FIGY=6=FDK q!! ] N %6- *-B ;-Tu >?N!N>a!w333?-at$N)\>a/!Sa!p a!D a!8 #N!8<NL>>a!L>?Ia!8 #!wN>ta!eNp>a!ya!w #C!DN333?a!w>&NY?a!8333?>?a!D #!yN=a!8333??a!D-at$ #!e̾NR^?a!wta!e #a!w?  S#//============================================================================= // BabyCow. // Don't add to world directly. Rather, set bHasBaby of an adult cow. //============================================================================= class TeamBabyCow extends TeamCow; var TeamCow mom; function PlayRunning() { LoopAnim('Run', -1.5/GroundSpeed,,0.3); } function PlayWalking() { LoopAnim('Walk', -2.0/GroundSpeed,,0.3); } function FollowMom() { Disable('AnimEnd'); GotoState('Grazing', 'Wander'); } state Grazing { function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { Mom.Help(self); Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType); if ( health <= 0 ) return; if ( NextState == 'TakeHit' ) { NextState = 'Attacking'; NextLabel = 'Begin'; GotoState('TakeHit'); } else GotoState('Attacking'); } function Bump(actor Other) { if ( (Pawn(Other)!= None) && (Cow(Other) == None) && (MoveTimer < 0) ) GotoState('Grazing', 'Wander'); else if ( (Normal(Destination - Location) Dot Normal(Other.Location - Location)) > 0.8 ) MoveTimer = -1.0; Disable('Bump'); } function PickDestination() { if ( Mom == None ) Super.PickDestination(); if ( !LineOfSightTo(mom) ) { MoveTarget = FindPathToward(mom); if ( MoveTarget != None ) { Destination = MoveTarget.Location; return; } } if (ScaryGuy != None) Destination = mom.Destination - 2 * mom.CollisionRadius * Normal(ScaryGuy.Location - mom.Destination); else Destination = mom.Destination; } Begin: //log(class$" Grazing"); Wander: if (!bForage) Goto('Graze'); PickDestination(); TweenToWalking(0.2); FinishAnim(); PlayWalking(); Moving: Enable('HitWall'); Enable('Bump'); MoveTo(Destination, 0.4); Acceleration = vect(0,0,0); Graze: Enable('AnimEnd'); NextAnim = ''; TweenToPatrolStop(0.2); Sleep(4); Disable('AnimEnd'); FinishAnim(); Goto('Wander'); ContinueWander: FinishAnim(); PlayWalking(); Goto('Wander'); Turn: PlayTurning(); TurnToward(Mom); Goto('Graze'); } ^//============================================================================= // TeamSpawnpoint. //Used by Team Creature Factories for spawning monsters //============================================================================= class TeamSpawnPoint extends SpawnPoint; var ThingFactory factory; function bool Create() { local TeamScriptedPawn newcreature; local TeamCreatureFactory pawnFactory; local TeamScriptedPawn creature; local actor temp, A; local rotator newRot; if ( factory.bCovert && PlayerCanSeeMe() ) //make sure no player can see this return false; temp = Spawn(factory.prototype); if (temp == None) return false; newRot = rot(0,0,0); newRot.yaw = rotation.yaw; temp.SetRotation(newRot); temp.event = factory.tag; temp.tag = factory.itemtag; newcreature = TeamScriptedPawn(temp); if( Event != '' ) foreach AllActors( class 'Actor', A, Event ) A.Trigger( Self, Instigator ); if ( factory.bFalling ) temp.SetPhysics(PHYS_Falling); if (newcreature == None) return true; pawnFactory = TeamCreatureFactory(factory); if (pawnFactory == None) { log("Error - use Team creature factory to spawn Team monsters"); return true; } if (newcreature != None) { newcreature.Orders = pawnFactory.Orders; newcreature.OrderTag = pawnFactory.OrderTag; newcreature.SetEnemy(pawnFactory.enemy); newcreature.Alarmtag = pawnFactory.AlarmTag; newcreature.MyTeam = pawnFactory.Team; } else log("no newcreature?"); if (newcreature.enemy != None) newcreature.lastseenpos = newcreature.enemy.location; newcreature.SetMovementPhysics(); if ( newcreature.Physics == PHYS_Walking) newcreature.SetPhysics(PHYS_Falling); return true; } ~ E |6- *-B ;-Tu bL?a!8>?za!>? A!X" L> B!\ 0K"> -B /6-\  a&!w\  i +E-'C?%-b(Cw*-( C![ #x-T(-B(46-[  i!m L?,q!!Gva&![  E!T a$-T(-B(46-T  i!m L?,q!!G!@ !Q -a&!@T   o!8ouAwk G!R &%3$6-R  a&!R  L!3;?%-' I!Q &> -B /6-Q  a&!Q  p! 8#-(-|'-'? K!T'.6- a!Ga? M!}'+)!. -a&!.} kgII/V,g!f ?-ga  #L?a<" @wg*g gng 6g 6g 6a!z333?=;%>a!O333?=a$@ N!Y(a!. ? P! (c6- T!m L?,q!!Gaa&!> Q!S!p)K!33>a!O333?=3a!m333?=aK$@ R!hI*gh!f ?-_a  #L?a<" @w_*_ _n_ 6_ 6_ 6a!c 333?=da/!S6?,x96C?a!O333?=a!a333?=a$@ |dT!X!i9-K!?a!O333?=3a!a333?=a$@ W!Z!jB~.K!>a!z333?=3a!a333?=a$@ Y!\!FKC/*a!z333?=a$@ [!^!WS/!> GfG>a$@?FG?a$@?FG@?aP$@?FaO$@?F _!FV!`!]!Qd10?a&!@L>.a!D333?= b!YlF2M!@a!@>K>!Qa!Q>Ka&!r > c!yv3a&!"L? U!i!b 4|4Qb #!ob L>aU$Gb >a!TOa!o X t@r3a|$a!D?= oIe  5B@':H ?:H  aQ $ k!H5B@':J ?:J  aQ $ l!n!46K&!LKL>AA!EKL>-U(6- K? a!LaF$a!EaH$ o!KVq!g!]l0cHD?H??,EaO P cX (wE*6cfff?EaO P cX (-|rE*dPcX 6dD?6d??,HHdd I"+`-'u!a?( {c4=-'-(-'-(-(-( i y"B9xk!mC@?6o;CCC #<a $Cq!!Gvi y aM//============================================================================= // TeamWarlord. //============================================================================= class TeamWarlord extends TeamScriptedPawn; //FIXME - use TakeOff animation (maybe for falling start) var() byte StrikeDamage; var() bool bTeleportWhenHurt; var float LastDuckTime; function PreSetMovement() { bCanJump = true; bCanWalk = true; bCanSwim = false; bCanFly = true; MinHitWall = -0.6; bCanOpenDoors = true; bCanDoSpecial = true; bCanDuck = true; } function Died(pawn Killer, name damageType, vector HitLocation) { if ( bTeleportWhenHurt ) { Health = 1000; PlayAnim('Teleport'); GotoState('Teleporting'); } else Super.Died(Killer, damageType, HitLocation); } function TryToDuck(vector duckDir, bool bReversed) { local vector HitLocation, HitNormal, Extent; local bool duckLeft, bSuccess; local actor HitActor; local float decision; //log("duck"); if ( Level.TimeSeconds - LastDuckTime < 0.6 - 0.1 * skill ) return; duckLeft = !bReversed; Extent.X = CollisionRadius; Extent.Y = CollisionRadius; Extent.Z = CollisionHeight; if ( (Physics != PHYS_Flying) && (FRand() < 0.4) ) // try to duck up { HitActor = Trace(HitLocation, HitNormal, Location + vect(0,0,300), Location, false, Extent); if ( HitActor == None ) { if ( FRand() < 0.7 ) PlayAnim('Fly', 1.6, 0.1); else PlayAnim('FDodgeUp'); SetPhysics(PHYS_Flying); Destination = Location + vect(0,0,300); Velocity = AirSpeed * vect(0,0,1); LastDuckTime = Level.TimeSeconds; GotoState('TacticalMove', 'DoMove'); return; } } HitActor = Trace(HitLocation, HitNormal, Location + 200 * duckDir, Location, false, Extent); bSuccess = ( HitActor == None ); if ( !bSuccess ) { duckLeft = !duckLeft; duckDir *= -1; HitActor = Trace(HitLocation, HitNormal, Location + 200 * duckDir, Location, false, Extent); bSuccess = ( HitActor == None ); } if ( !bSuccess ) return; LastDuckTime = Level.TimeSeconds; if ( FRand() < 0.7 ) PlayAnim('Fly', 1.6, 0.1); else if ( duckLeft ) PlayAnim('FDodgeL'); else PlayAnim('FDodgeR'); SetPhysics(PHYS_Flying); Destination = Location + 200 * duckDir; Velocity = AirSpeed * duckDir; GotoState('TacticalMove', 'DoMove'); } event Landed(vector HitNormal) { SetPhysics(PHYS_Walking); if ( !IsAnimating() ) PlayLanded(Velocity.Z); if (Velocity.Z < -1.4 * JumpZ) MakeNoise(-0.5 * Velocity.Z/(FMax(JumpZ, 150.0))); bJustLanded = true; } function Step() { PlaySound(sound'step1t', SLOT_Interact); } function Flap() { PlaySound(sound'fly1WL', SLOT_Interact); } function SetMovementPhysics() { if (Enemy != None) { if (Physics == PHYS_None) SetPhysics(PHYS_Walking); else if ( Region.Zone.bWaterZone || (Physics != PHYS_Walking) ) SetPhysics(PHYS_Flying); } else if (Physics != PHYS_Falling) SetPhysics(PHYS_Walking); } singular function Falling() { SetPhysics(PHYS_Flying); } function PlayWaiting() { local float decision; if (AnimSequence == 'Land') { TweenAnim('Breath', 0.3); return; } PlaySound(sound'breath1WL', SLOT_Interact); if (FRand() < 0.9) LoopAnim('Breath', 0.2 + 0.7 * FRand()); else LoopAnim('Twirl', 0.5 + 0.5 * FRand()); } function PlayPatrolStop() { if (Physics == PHYS_Flying) LoopAnim('Fly', 0.7); else PlayWaiting(); } function PlayWaitingAmbush() { PlayWaiting(); } function PlayChallenge() { if (Physics == PHYS_Flying) PlayAnim('Fly', 0.7, 0.1); else if ( FRand() < 0.5 ) { PlaySound(sound'laugh1WL', SLOT_Talk); PlayAnim('Laugh', 0.7, 0.1); } else PlayAnim('Point', 0.7, 0.1); } function TweenToFighter(float tweentime) { if (Physics == PHYS_Flying) TweenAnim('Fly', tweentime); else TweenAnim('Fighter', tweentime); } function TweenToRunning(float tweentime) { if ( IsAnimating() && ((AnimSequence == 'WalkFire') || (AnimSequence == 'FlyFire')) ) return; if (Physics == PHYS_Flying) { if ( (GetAnimGroup(AnimSequence) != 'Dodge') && ((AnimSequence != 'Fly') || !bAnimLoop) ) TweenAnim('Fly', tweentime); } else if ( (AnimSequence != 'Run') || !bAnimLoop ) TweenAnim('Run', tweentime); } function TweenToWalking(float tweentime) { if (Physics == PHYS_Flying) TweenAnim('Fly', tweentime); else TweenAnim('Walk', tweentime); } function TweenToWaiting(float tweentime) { PlayAnim('Land', 0.2 + 0.8 * FRand()); SetPhysics(PHYS_Falling); } function TweenToPatrolStop(float tweentime) { if (Physics == PHYS_Flying) { if (FRand() < 0.3) { SetPhysics(PHYS_Falling); PlayAnim('Land', 0.7); } else TweenAnim('Fly', tweentime); } else TweenAnim('Breath', tweentime); } function PlayRunning() { if (Physics == PHYS_Walking) LoopAnim('Run', -1.0/GroundSpeed,, 0.4); else LoopAnim('Fly', -1.0/AirSpeed,, 0.4); } function PlayWalking() { if (Physics == PHYS_Walking) LoopAnim('Walk', -1.4/GroundSpeed,, 0.4); else LoopAnim('Fly', -1.7/AirSpeed,, 0.4); } function PlayThreatening() { if (Physics == PHYS_Walking) TweenAnim('Fighter', 0.3); else LoopAnim('Fly', 0.6); } function PlayTurning() { if (Physics == PHYS_Walking) TweenAnim('Walk', 0.3); else LoopAnim('Fly'); } function PlayDying(name DamageType, vector HitLocation) { PlaySound(Die, SLOT_Talk); if ( Physics == PHYS_Flying ) PlayAnim('Dead2A', 0.7, 0.12); else PlayAnim('Dead1', 0.7, 0.12); } function PlayTakeHit(float tweentime, vector HitLoc, int damage) { TweenAnim('TakeHit', tweentime); } function TweenToFalling() { TweenAnim('Fly', 0.2); } function PlayInAir() { LoopAnim('Fly'); } function PlayLanded(float impactVel) { PlayAnim('Land'); } function PlayVictoryDance() { PlayAnim('Strike', 0.6, 0.1); } function PlayMeleeAttack() { if (Physics == PHYS_Flying) { PlayRangedAttack(); return; } PlayAnim('Strike'); if ( MeleeDamageTarget(StrikeDamage, (StrikeDamage * 1000.0 * Normal(Target.Location - Location))) ) PlaySound(Threaten, SLOT_Talk); } function bool CanFireAtEnemy() { local vector HitLocation, HitNormal,X,Y,Z, projStart, EnemyDir, EnemyUp; local actor HitActor; local rotator EnemyRot; local float EnemyDist; EnemyDir = Enemy.Location - Location; EnemyDist = VSize(EnemyDir); EnemyUp = Enemy.CollisionHeight * vect(0,0,0.9); if ( EnemyDist > 300 ) { EnemyDir = 300 * EnemyDir/EnemyDist; EnemyUp = 300 * EnemyUp/EnemyDist; } GetAxes(Rotation,X,Y,Z); projStart = Location - 0.5 * CollisionRadius * Y; HitActor = Trace(HitLocation, HitNormal, projStart + EnemyDir + EnemyUp, projStart , true); if ( (HitActor == None) || (HitActor == Enemy) || ((Pawn(HitActor) != None) && (AttitudeTo(Pawn(HitActor)) <= ATTITUDE_Ignore)) ) return true; HitActor = Trace(HitLocation, HitNormal, projStart + EnemyDir, projStart , true); return ( (HitActor == None) || (HitActor == Enemy) || ((Pawn(HitActor) != None) && (AttitudeTo(Pawn(HitActor)) <= ATTITUDE_Ignore)) ); } function PlayRangedAttack() { local vector X,Y,Z, projStart; local rotator projRotation; if (Physics == PHYS_Flying) PlayAnim('FlyFire'); else PlayAnim('Fire'); GetAxes(Rotation,X,Y,Z); projStart = Location - 0.5 * CollisionRadius * Y; projRotation = AdjustAim(ProjectileSpeed, projStart, 0, bLeadTarget, bWarnTarget); spawn(RangedProjectile ,self,'',projStart,projRotation); } function PlayMovingAttack() { local vector X,Y,Z, projStart; local rotator projRotation; if (Physics == PHYS_Flying) PlayAnim('FlyFire'); else { DesiredSpeed = 0.4; PlayAnim('WalkFire'); } GetAxes(Rotation,X,Y,Z); projStart = Location - 0.5 * CollisionHeight * Y; projRotation = AdjustAim(ProjectileSpeed, projStart, 600, bLeadTarget, bWarnTarget); if ( FRand() < 0.5 ) { if (FRand() < 0.5) projRotation.Yaw += 3072; else projRotation.Yaw -= 3072; } spawn(RangedProjectile ,self,'',projStart,projRotation); } State Charging { function HitWall(vector HitNormal, actor Wall) { if ( (Physics == PHYS_Flying) && (HitNormal.Z > 0.7) ) { SetPhysics(PHYS_Walking); return; } Super.HitWall(HitNormal, Wall); } function BeginState() { local vector HitLocation, HitNormal; local actor HitActor; if ( (Enemy.Location.Z > Location.Z + MaxStepHeight) || (FRand() < 0.3) ) { Velocity.Z = 400; SetPhysics(PHYS_Flying); } else if ( !Region.Zone.bWaterZone ) { HitActor = Trace(HitLocation, HitNormal, Location - 2 * CollisionHeight * vect(0,0,1), Location, true); if (HitActor == Level) SetPhysics(PHYS_Falling); } Super.BeginState(); } } State TacticalMove { function HitWall(vector HitNormal, actor Wall) { if (HitNormal.Z > 0.7) { SetPhysics(PHYS_Walking); return; } Focus = Destination; if (PickWallAdjust()) GotoState('TacticalMove', 'AdjustFromWall'); else { DesiredRotation = Rotator(Enemy.Location - location); GotoState('Attacking'); } } function BeginState() { local vector HitLocation, HitNormal; local actor HitActor; if ( (FRand() < 0.3) || (Enemy.Location.Z - Location.Z) > MaxStepHeight + 2 * (CollisionHeight - Enemy.CollisionHeight) ) { Velocity.Z = 400; SetPhysics(PHYS_Flying); } else if ( !Region.Zone.bWaterZone ) { HitActor = Trace(HitLocation, HitNormal, Location - 2 * CollisionHeight * vect(0,0,1), Location, true); if (HitActor == Level) SetPhysics(PHYS_Falling); } Super.BeginState(); } } State Teleporting { ignores TakeDamage, SeePlayer, EnemyNotVisible, HearNoise, KilledBy, Bump, HitWall, HeadZoneChange, FootZoneChange, ZoneChange, Falling, WarnTarget, Died; function Tick(float DeltaTime) { local Actor A; ScaleGlow -= 3 * DeltaTime; if ( ScaleGlow < 0.3 ) { PlaySound(sound'Teleport2',, 8.0); if ( Event != '' ) ForEach AllActors( class'Actor', A, Event ) A.Trigger( Self, Enemy ); Destroy(); } } function BeginState() { bStasis = false; SetPhysics(PHYS_None); Disable('Tick'); } Begin: FinishAnim(); Style = STY_Translucent; bUnlit = true; ScaleGlow = 2.0; Enable('Tick'); } state Mutilating { function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { } function Bump(actor Other) { if ( Other.IsA('Pawn') && Pawn(Other).bIsPlayer ) GotoState('Mutilating', 'FinalSequence'); } function EnemyAcquired() { GotoState('Mutilating', 'FinalSequence'); } function AnimEnd() { local float decision; decision = FRand(); if ( AnimSequence == 'Grab' ) PlayAnim('Munch', 0.3 + 0.7 * FRand()); else if ( decision < 0.2 ) PlayAnim('GKick1', 0.3 + 0.7 * FRand()); else if ( decision < 0.4 ) PlayAnim('GKick2', 0.3 + 0.7 * FRand()); else if ( decision < 0.6 ) PlayAnim('GPunch1', 0.3 + 0.7 * FRand()); else if ( decision < 0.8 ) PlayAnim('GPunch2', 0.3 + 0.7 * FRand()); else PlayAnim('Grab', 0.3 + 0.7 * FRand()); } function Landed(vector HitNormal) { SetPhysics(PHYS_None); } function BeginState() { Enemy = None; Acceleration = vect(0,0,0); SetAlertness(0.0); Health = 100000; } FinalSequence: Disable('AnimEnd'); PlayTurning(); TurnToward(Enemy); PlayAnim('Point', 0.7, 0.15); FinishAnim(); PlaySound(sound'laugh1WL', SLOT_Talk); PlayAnim('Laugh', 0.7); FinishAnim(); GotoState('Attacking'); Begin: TweenToWaiting(0.2); bReadyToAttack = false; DesiredRotation = rot(0,0,0); DesiredRotation.Yaw = Rotation.Yaw; SetRotation(DesiredRotation); if (Physics != PHYS_Falling) SetPhysics(PHYS_None); } Is!@6:&$!m86@A x!+u!9-w( B}x9l-w'W.xZ.x%.xx v!9a@( wo-T(~ G@?t~G?&~ pCG>: ~6 -6:?Y C@@c:#?X?@GL>sG?%X?::X6:6:X?XEXcvE:Y?}YE:8b }-T'v-Tv:EY?6v6}Y:Eb }-T'v-Tv:Y?6v6?,?,d n a zC">!ma? !G1-o$ !da333?L>-  w*aawN#a$aQ6?jo$w* 6zC !Ea-G(#C-Ba??,a!{333?a-G' !d iPGE}dr}!A; ~!!I |!~"; k!mO@?6o;OOO #<a $Oq!!G !N !FO6Oo<OO6-a$AOq!!i I ~ WV#X V"u!F,sB6B"q!EԝXtԝXtt1tt1ttԝX1L(X?$?`$333?H$>rVE|h gU KhI$BM$CK$Cq$D\$;E!"LvKpL V O ;$?] WarLordH r$@A7$PB/$B<$zDI@"}6>&$!m86}|{ `WXI::$9!Ma $ Ca!MFa&!ML>Va!c333? @ N a!o=>  G"oV   K"l  s /B-'s  QL"WOtp8Wn .n >~CCn ?:-'P q!'( M In  !V",E*!n!q! cgOEQO':z ?:z  -U'v!aQ $ G\B&C6\\\k 4C@t\k ?j aMnt(SM!Sk 6n333?-x(tM\n#??,j aMnt(wj *(?tMի?,\' EEm P :n9!z6n ,;U6n,;;P 9nO;& ;, ;,i l b!Ua !ի?i իL>?;>l Oa !ի?i ի=?;=l e!z;m ?P 6m 6 ?Z~~Qm +rZa  ~Q?,PQ?,a  ~Q?, wZ wZ Z, ~@FP !La  ~Q?,  .dT%.#?,H $J $ [Q"Oe!6O-a-w6N6N6NnaCp ?,O(N-crn*C?,"-c-a-aO?naCp ?,O(N-crn*C?,/-c Qrn*C?,OnaCp C#?C(Nrn* ,-aa!N̬?a!F̬?O6HCo$q!!\ A//============================================================================= // TeamTitan. //============================================================================= class TeamTitan extends TeamScriptedPawn; //FIXME - use fall1ti for titancarcass landed //TITAN variables; var() byte SlapDamage, PunchDamage; var bool bStomp; var bool bLavaTitan; var bool bEndFootStep; var float realSpeed; var() name StompEvent; var() name StepEvent; var(Sounds) sound Step; var(Sounds) sound StompSound; var(Sounds) sound slap; var(Sounds) sound swing; var(Sounds) sound throw; var(Sounds) sound chest; function PlayAcquisitionSound() { if (Acquire != None) { PlaySound(Acquire, SLOT_Talk,, true); PlaySound(Acquire, SLOT_Misc,, true); } } function PlayFearSound() { if (Fear != None) { PlaySound(Fear, SLOT_Talk,, true); PlaySound(Fear, SLOT_Misc,, true); } } function PlayRoamingSound() { if ( (Threaten != None) && (FRand() < 0.3) ) { PlaySound(Threaten, SLOT_Talk,, true); PlaySound(Threaten, SLOT_Misc,, true); return; } if ( FRand() < 0.5 ) { PlaySound(Sound'roam1Ti', SLOT_Talk,, true); PlaySound(Sound'roam1Ti', SLOT_Misc,, true); return; } if (Roam != None) { PlaySound(Roam, SLOT_Talk,, true); PlaySound(Roam, SLOT_Misc,, true); } } function PlayThreateningSound() { if (Threaten == None) return; if (FRand() < 0.5) { PlaySound(Threaten, SLOT_Talk,, true); PlaySound(Threaten, SLOT_Misc,, true); } else { PlaySound(Fear, SLOT_Talk,, true); PlaySound(Fear, SLOT_Misc,, true); } } singular event BaseChange() { local float decorMass; if (Pawn(Base) != None) { Base.TakeDamage( 1000, Self,Location,0.5 * Velocity , 'stomped'); JumpOffPawn(); } else if ( (Decoration(Base) != None) && (Velocity.Z < -400) ) { decorMass = FMax(Decoration(Base).Mass, 1); Base.TakeDamage(1000, Self, Location, 0.5 * Velocity, 'stomped'); } } //Azathoth deleted function eAttitude AttitudeToCreature(Pawn Other) function ThrowOther(Pawn Other) { local float dist, shake; local PlayerPawn aPlayer; local vector Momentum; if ( Other.mass > 500 ) return; aPlayer = PlayerPawn(Other); if ( aPlayer == None ) { if ( !bStomp || (Other.Physics != PHYS_Walking) ) return; dist = VSize(Location - Other.Location); if (dist > 500) return; } else { dist = VSize(Location - Other.Location); shake = FMax(500, 1500 - dist); if ( dist > 1500 ) return; aPlayer.ShakeView( FMax(0, 0.35 - dist/20000), shake, 0.015 * shake); if ( Other.Physics != PHYS_Walking ) return; } Momentum = -0.5 * Other.Velocity + 100 * VRand(); Momentum.Z = 7000000.0/((0.4 * dist + 350) * Other.Mass); if (bStomp) Momentum.Z *= 5.0; Other.AddVelocity(Momentum); } function FootStep() { local actor A; local pawn Thrown; //slightly throw player if nearby ,& play footstep sound bStomp = false; bEndFootstep = false; if (StepEvent != '') foreach AllActors( class 'Actor', A, StepEvent ) A.Trigger( Self, Instigator ); Thrown = Level.PawnList; While ( Thrown != None ) { ThrowOther(Thrown); Thrown = Thrown.nextPawn; } realSpeed = DesiredSpeed; //fixme - don't stop if very low friction DesiredSpeed = 0.0; PlaySound(Step, SLOT_Interact); } function StartMoving() { DesiredSpeed = realSpeed; } function Stomp() { local actor A; local pawn Thrown; if (StompEvent != '') foreach AllActors( class 'Actor', A, StompEvent ) A.Trigger( Self, Instigator ); //throw all nearby creatures, and play sound bStomp = true; Thrown = Level.PawnList; While ( Thrown != None ) { ThrowOther(Thrown); Thrown = Thrown.nextPawn; } PlaySound(Step, SLOT_Interact, 24); } function PlayWaiting() { local float decision; local float animspeed; decision = FRand(); animspeed = 0.2 + 0.5 * FRand(); if (bEndFootStep) FootStep(); if ( (AnimSequence == 'TBrea001') && (decision < 0.17) ) { SetAlertness(0.0); if (decision < 0.1) { PlaySound(sound'sniff1Ti', SLOT_Talk); LoopAnim('TSnif001', animspeed); } else if (decision < 0.17) LoopAnim('TFist', animspeed); } else { SetAlertness(0.3); LoopAnim('TBrea001', animspeed); } } //PlayPatrolStop(), and PlayWaitingAmbush() all use PlayWaiting(); function PlayPatrolStop() { if (bEndFootStep) FootStep(); DesiredSpeed = 0.0; PlayWaiting(); } function PlayWaitingAmbush() { if (bEndFootStep) FootStep(); DesiredSpeed = 0.0; PlayWaiting(); } function PlayChallenge() { local float decision; if (bEndFootStep) FootStep(); DesiredSpeed = 0.0; decision = FRand(); if ( decision < 0.2 ) PlayAnim('TStom001', 1.0, 0.2); else if ( decision < 0.4 ) PlayAnim('TFist', 1.0, 0.2); else if ( decision < 0.64 ) PlayAnim('TFigh001', 1.0, 0.2); else if ( decision < 0.75 ) { PlaySound(Chest, SLOT_Interact); PlaySound(Chest, SLOT_Misc); PlayAnim('TChest', 1.0, 0.2); } else PlayAnim('TShuffle',1.0, 0.2); } function TweenToFighter(float tweentime) { bEndFootStep = ( (AnimSequence == 'TWalk001') && (AnimFrame > 0.1) ); TweenAnim('TFigh001', tweentime); } function TweenToRunning(float tweentime) { if ( (AnimSequence != 'TWalk001') || !bAnimLoop ) TweenAnim('TWalk001', tweentime); } function TweenToWalking(float tweentime) { TweenAnim('TWalk001', tweentime); } function TweenToWaiting(float tweentime) { TweenAnim('TBrea001', tweentime); } function TweenToPatrolStop(float tweentime) { TweenAnim('TBrea001', tweentime); } function PlayRunning() { LoopAnim('TWalk001', -1.0/GroundSpeed,, 0.8); } function PlayWalking() { LoopAnim('TWalk001', -1.0/GroundSpeed,, 0.8); if (FRand() < 0.4) PlayRoamingSound(); } function PlayThreatening() { local float decision, animspeed; decision = FRand(); animspeed = 0.4 + 0.6 * FRand(); if ( decision < 0.5 ) PlayAnim('TBrea001', animspeed, 0.4); else if ( decision < 0.7 ) { PlaySound(StompSound, SLOT_Talk); PlaySound(StompSound, SLOT_Misc); PlayAnim('TStom001', animspeed, 0.4); } else { PlayThreateningSound(); if ( decision < 0.9 ) PlayAnim('TFist', animspeed, 0.4); else TweenAnim('TFigh001', 0.4); } } function PlayTurning() { if (bEndFootStep) FootStep(); DesiredSpeed = 0.0; LoopAnim('TShuffle',, 0.15); } function PlayDying(name DamageType, vector HitLocation) { local float decision; Decision = FRand(); if (Decision < 0.4) PlayAnim('TDeat001', 0.7, 0.15); else if (Decision < 0.7) PlayAnim('TDeat002', 0.7, 0.15); else PlayAnim('TDeat003', 0.7, 0.15); PlaySound(Die, SLOT_Talk); PlaySound(Die, SLOT_Misc); } function PlayTakeHit(float tweentime, vector HitLoc, int Damage) { local float decision; Decision = FRand(); if (Decision < 0.4) TweenAnim('TDeat001', tweentime); else if (Decision < 0.7) TweenAnim('TDeat002', tweentime); else TweenAnim('TDeat003', tweentime); } function SpawnRock() { local Projectile Proj; local vector X,Y,Z, projStart; GetAxes(Rotation,X,Y,Z); MakeNoise(1.0); if (FRand() < 0.4) { projStart = Location + CollisionRadius * X + 0.4 * CollisionHeight * Z; Proj = spawn(class 'Boulder1' ,self,'',projStart,AdjustAim(1000, projStart, 400, false, true)); if( Proj != None ) Proj.SetPhysics(PHYS_Projectile); return; } projStart = Location + CollisionRadius * X + 0.4 * CollisionHeight * Z; Proj = spawn(class 'BigRock' ,self,'',projStart,AdjustAim(1000, projStart, 400, false, true)); if( Proj != None ) Proj.SetPhysics(PHYS_Projectile); projStart = Location + CollisionRadius * X - 40 * Y + 0.4 * CollisionHeight * Z; Proj = spawn(class 'BigRock' ,self,'',projStart,AdjustAim(1000, projStart, 400, true, true)); if( Proj != None ) Proj.SetPhysics(PHYS_Projectile); if (FRand() < 0.2 * skill) { projStart = Location + CollisionRadius * X + 40 * Y + 0.4 * CollisionHeight * Z; Proj = spawn(class 'BigRock' ,self,'',projStart,AdjustAim(1000, projStart, 2000, false, true)); if( Proj != None ) Proj.SetPhysics(PHYS_Projectile); } } function PlayVictoryDance() { if (bEndFootStep) FootStep(); DesiredSpeed = 0.0; PlayAnim('TStom001', 0.6, 0.2); //gib the enemy here! PlaySound(StompSound, SLOT_Talk); PlaySound(StompSound, SLOT_Misc); } function PunchDamageTarget() { if ( MeleeDamageTarget(PunchDamage, (70000.0 * (Normal(Target.Location - Location)))) ) { PlaySound(Slap, SLOT_Interact); PlaySound(Slap, SLOT_Misc); } } function SlapDamageTarget() { local vector X,Y,Z; GetAxes(Rotation,X,Y,Z); if ( MeleeDamageTarget(SlapDamage, (70000.0 * ( Y + vect(0,0,1)))) ) { PlaySound(Slap, SLOT_Interact); PlaySound(Slap, SLOT_Misc); } } //Titan doesn't need to face as directly function bool NeedToTurn(vector targ) { local int YawErr; DesiredRotation = rotator(targ - location); DesiredRotation.Yaw = DesiredRotation.Yaw & 65535; YawErr = (DesiredRotation.Yaw - (Rotation.Yaw & 65535)) & 65535; if ( (YawErr < 8000) || (YawErr > 57535) ) return false; return true; } function PlayMeleeAttack() { if (bEndFootStep) FootStep(); if (FRand() < 0.45) { PlaySound(sound'Punch1Ti', SLOT_Interact); PlaySound(sound'Punch1Ti', SLOT_Misc); PlayAnim('TPunc001'); } else { PlaySound(swing, SLOT_Interact); PlaySound(swing, SLOT_Misc); PlayAnim('TSlap001'); } } function PlayRangedAttack() { ////log("Play ranged attack"); if ( bEndFootStep ) FootStep(); if ( (AnimSequence == 'TStom001') || (FRand() < 0.7) ) { PlaySound(Throw, SLOT_Interact); PlayAnim('TThro001'); } else { PlayAnim('TStom001'); PlaySound(StompSound, SLOT_Talk); PlaySound(StompSound, SLOT_Misc); } } function ZoneChange(ZoneInfo newZone) { if ( newZone.bPainZone && (newZone.DamageType == 'burned') ) GotoState('LavaDeath'); else Super.ZoneChange(newZone); } state Sitting { ignores SeePlayer, HearNoise, Bump, TakeDamage; function Trigger( actor Other, pawn EventInstigator ) { if ( EventInstigator.bIsPlayer ) { AttitudeToPlayer = ATTITUDE_Hate; Enemy = EventInstigator; GotoState('Sitting', 'GetUp'); } Disable('Trigger'); } function BeginState() { bProjTarget = false; } GetUp: bProjTarget = true; PlayAnim('TGetUp'); FinishAnim(); SetCollisionSize(0, Default.CollisionHeight); SetPhysics(PHYS_Walking); DesiredSpeed = 1.0; Acceleration = vector(Rotation) * AccelRate; PlayAnim('TWalk001'); FinishAnim(); SetCollisionSize(Default.CollisionRadius, Default.CollisionHeight); GotoState('Attacking'); Begin: TweenAnim('TSit', 0.05); SetPhysics(PHYS_None); } state WalkOut { ignores SeePlayer, HearNoise, Bump, TakeDamage; function Trigger( actor Other, pawn EventInstigator ) { if ( EventInstigator.bIsPlayer ) { AttitudeToPlayer = ATTITUDE_Hate; Enemy = EventInstigator; GotoState('WalkOut', 'Walk'); } Disable('Trigger'); } function BeginState() { bProjTarget = false; } Walk: bProjTarget = true; SetPhysics(PHYS_Walking); DesiredSpeed = 1.0; Acceleration = vector(Rotation) * AccelRate; PlayAnim('TWalk001'); FinishAnim(); PlayAnim('TWalk001'); FinishAnim(); GotoState('Attacking'); Begin: TweenAnim('TWalk001', 0.05); SetPhysics(PHYS_None); } state LavaDeath { ignores SeePlayer, HearNoise, Bump, TakeDamage; Begin: ReducedDamageType = 'Burned'; Acceleration = vect(0,0,0); PlaySound(Chest, SLOT_Interact); PlayAnim('TChest'); FinishAnim(); PlayAnim('TDeat002'); FinishAnim(); bLavaTitan = true; TweenAnim('TDeat001', 2.0); GotoState('Attacking'); } bXp//============================================================================= // TeamTentacle. //============================================================================= class TeamTentacle extends TeamScriptedPawn; //----------------------------------------------------------------------------- // Tentacle variables. // Attack damage. var() int WhipDamage; // Damage done by whipping. var(Sounds) sound mebax; var(Sounds) sound whip; var(Sounds) sound Smack; //----------------------------------------------------------------------------- // Tentacle functions. function PostBeginPlay() { Super.PostBeginPlay(); bLeadTarget = bLeadTarget && (FRand() > 0.5); } function WhatToDoNext(name LikelyState, name LikelyLabel) { bQuiet = false; GotoState('Waiting'); } //Azathoth deleted function eAttitude AttitudeToCreature(Pawn Other) simulated function AddVelocity( vector NewVelocity ) { if (Physics == PHYS_Rotating) Velocity = vect(0,0,0); else Velocity += NewVelocity; } function PreSetMovement() { bCanJump = false; bCanWalk = false; bCanSwim = true; bCanFly = false; MinHitWall = -0.6; bCanOpenDoors = false; bCanDoSpecial = false; } function bool CanFireAtEnemy() { local vector HitLocation, HitNormal, EnemyDir, projStart, EnemyUp; local actor HitActor; local float EnemyDist; EnemyDir = Enemy.Location - Location; EnemyDist = VSize(EnemyDir); EnemyUp = Enemy.CollisionHeight * vect(0,0,0.9); if ( EnemyDist > 300 ) { EnemyDir = 300 * EnemyDir/EnemyDist; EnemyUp = 300 * EnemyUp/EnemyDist; } projStart = Location + CollisionHeight * vect(0,0,-1.2); HitActor = Trace(HitLocation, HitNormal, projStart + EnemyDir + EnemyUp, projStart, true); if ( (HitActor == None) || (HitActor == Enemy) || ((Pawn(HitActor) != None) && (AttitudeTo(Pawn(HitActor)) <= ATTITUDE_Ignore)) ) return true; HitActor = Trace(HitLocation, HitNormal, projStart + EnemyDir, projStart, true); return ( (HitActor == None) || (HitActor == Enemy) || ((Pawn(HitActor) != None) && (AttitudeTo(Pawn(HitActor)) <= ATTITUDE_Ignore)) ); } function SetMovementPhysics() { if (Region.Zone.bWaterZone) SetPhysics(PHYS_Swimming); else SetPhysics(PHYS_Rotating); } function bool SetEnemy( Pawn NewEnemy ) { local bool result; bCanWalk = true; //even though can't move, still acquire enemies result = Super.SetEnemy(NewEnemy); bCanWalk = false; return result; } function Drop() { //implemented in TentacleCarcass } singular function Falling() { SetMovementPhysics(); } function PlayWaiting() { TweenAnim('Hide', 5.0); } function PlayPatrolStop() { TweenAnim('Hide', 5.0); } function PlayWaitingAmbush() { TweenAnim('Hide', 5.0); } function PlayChallenge() { if ( GetAnimGroup(AnimSequence) == 'Hiding') { PlaySound(Mebax, SLOT_Interact); PlayAnim('Uncurl', 0.6, 0.2); } else PlayAnim('Waver', 1.0, 0.1); } function TweenToFighter(float tweentime) { if ( GetAnimGroup(AnimSequence) == 'Hiding') { PlaySound(Mebax, SLOT_Interact); PlayAnim('Uncurl', 0.6, 0.2); } else TweenAnim('Waver', tweentime); } function TweenToRunning(float tweentime) { if ( GetAnimGroup(AnimSequence) == 'Hiding') { PlaySound(Mebax, SLOT_Interact); PlayAnim('Uncurl', 0.6, 0.2); } else if ( (AnimSequence != 'Move2') || !bAnimLoop ) TweenAnim('Move2', tweentime); } function TweenToWalking(float tweentime) { if ( GetAnimGroup(AnimSequence) == 'Hiding') { PlaySound(Mebax, SLOT_Interact); PlayAnim('Uncurl', 0.6, 0.2); } else if ( (AnimSequence != 'Move1') || !bAnimLoop ) TweenAnim('Move1', tweentime); } function TweenToWaiting(float tweentime) { if ( GetAnimGroup(AnimSequence) != 'Hiding') { PlaySound(Mebax, SLOT_Interact); PlayAnim('Curl', 0.6, 0.2); } } function TweenToPatrolStop(float tweentime) { if ( GetAnimGroup(AnimSequence) == 'Hiding') { PlaySound(Mebax, SLOT_Interact); PlayAnim('Uncurl', 0.6, 0.2); } else TweenAnim('Waver', tweentime); } function PlayRunning() { LoopAnim('Move2', 1.0,, 0.4); } function PlayWalking() { LoopAnim('Move1', 1.0,, 0.4); } function PlayThreatening() { if ( FRand() < 0.8 ) PlayAnim('Waver', 0.4); else PlayAnim('Smack', 0.4); } function PlayTurning() { if ( GetAnimGroup(AnimSequence) == 'Hiding') { PlaySound(Mebax, SLOT_Interact); PlayAnim('Uncurl', 0.6, 0.2); } else LoopAnim('Waver'); } function PlayDying(name DamageType, vector HitLocation) { PlaySound(Die, SLOT_Talk, 3 * TransientSoundVolume); if ( Velocity.Z > 200 ) PlayAnim('Dead2', 0.7, 0.1); else { PlayAnim('Dead1', 0.7, 0.1); SetPhysics(PHYS_None); } } function PlayTakeHit(float tweentime, vector HitLoc, int Damage) { TweenAnim('TakeHit', tweentime); } function TweenToFalling() { TweenAnim('Waver', 0.2); } function PlayInAir() { LoopAnim('Waver'); } function PlayLanded(float impactVel) { PlayAnim('Waver'); } function PlayVictoryDance() { PlaySound(whip, SLOT_Interact); PlayAnim('Smack', 0.6, 0.1); } function PlayMeleeAttack() { PlaySound(whip, SLOT_Interact); PlayAnim('Smack'); } function SmackTarget() { if ( MeleeDamageTarget(WhipDamage, (WhipDamage * 1000 * Normal(Target.Location - Location))) ) PlaySound(Smack, SLOT_Interact); } function PlayRangedAttack() { local vector projStart; MakeNoise(1.0); projStart = Location + CollisionHeight * vect(0,0,-1.2); spawn(RangedProjectile ,self,'',projStart,AdjustAim(ProjectileSpeed, projStart, 900, bLeadTarget, bWarnTarget)); PlayAnim('Shoot'); } state Attacking { ignores SeePlayer, HearNoise, Bump, HitWall; function ChooseAttackMode() { if (Physics == PHYS_Swimming) { Super.ChooseAttackMode(); return; } if ((Enemy == None) || (Enemy.Health <= 0)) { if ((OldEnemy != None) && (OldEnemy.Health > 0)) { Enemy = OldEnemy; OldEnemy = None; } else { GotoState('Waiting'); return; } } if (!LineOfSightTo(Enemy)) GotoState('StakeOut'); else GotoState('RangedAttack'); } } state StakeOut { ignores EnemyNotVisible; function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType); if ( health <= 0 ) return; if (NextState == 'TakeHit') { NextState = 'Attacking'; NextLabel = 'Begin'; GotoState('TakeHit'); } } Begin: PlayChallenge(); TurnTo(LastSeenPos); HangOut: if ( bHasRangedAttack && bClearShot && (FRand() < 0.5) && (VSize(Enemy.Location - LastSeenPos) < 100) && CanStakeOut() ) PlayRangedAttack(); FinishAnim(); PlayChallenge(); Sleep(1 + FRand()); if ( FRand() < 0.1 ) GotoState('Waiting'); else LoopAnim('Waver'); Goto('HangOut'); } state Acquisition { PlayOut: FinishAnim(); Begin: PlayTurning(); FinishAnim(); GotoState('Attacking'); } yiO"q?w-+E  U"O*_B6 W"CEtttԝX1tt| mjX?$?`$333?rVLS|hgUKI$BE$Bq$Bj$ A\$zDT$W$ A!"2$pLV=O] TentacleH/$B<$HCa$CP:S0u^MX"XW^mn-r -g-g(^ao p  ?,m(r^* @m'^ao p  ?,m(r^* @m'S-r 1? @mQ @m'( w //============================================================================= // TeamSkaarjBerserker. //============================================================================= class TeamSkaarjBerserker extends TeamSkaarjWarrior; function WhatToDoNext(name LikelyState, name LikelyLabel) { local Pawn aPawn; aPawn = Level.PawnList; while ( aPawn != None ) { if ( (aPawn.IsA('PlayerPawn') || aPawn.IsA('TeamScriptedPawn')) && (VSize(Location - aPawn.Location) < 500) && CanSee(aPawn) ) { if ( SetEnemy(aPawn) ) { GotoState('Attacking'); return; } } aPawn = aPawn.nextPawn; } Super.WhatToDoNext(LikelyState, LikelyLabel); } function eAttitude AttitudeToCreature(Pawn Other) { if ( Other.IsA('TeamScriptedPawn') && !Other.IsA('TeamPupae') ) return ATTITUDE_Hate; else return ATTITUDE_Ignore; } wR"]"NLZ jZ#fff?j?,Z?,Zj?,jC F H ~իfff?C F ի>H Ra{ A ~Z~'RwRw.R*: .R:$(~իfff?C F ի>H 7a{ A ~Z~'w7w.7*: .7:$(_r7* r7 rR* rRw.7*w.R*'7a{ A ~Z~'r7* r7)w.7*: .7:$ { =_ b"`"x,L::$ k_ a/!~._ C]?%#q!f!s bq!f!T e"+%˒-'u!a?( Z"L#_ B6 c" `MLtttttt({(tr$>?$L?!"@A$?;$?]Skaarj Berserker[A$?^/$`B<$4Ca$4CP:S Pd//============================================================================= // TeamStoneTitan. //============================================================================= class TeamStoneTitan extends TeamTitan; k" v! [ d"` B6f"&[ /3] Stone Titan[ `//============================================================================= // TeamSquid. //============================================================================= class TeamSquid extends TeamScriptedPawn; //----------------------------------------------------------------------------- // Squid variables. // Attack damage. var() byte ThrustDamage, // Basic damage done by bite. SlapDamage; var(Sounds) sound thrust; var(Sounds) sound slapgrabhit; var(Sounds) sound thrusthit; var(Sounds) sound slap; var(Sounds) sound turn; var(Sounds) sound grab; var(Sounds) sound spin; var(Sounds) sound flop; //----------------------------------------------------------------------------- // Squid functions. function ZoneChange(ZoneInfo newZone) { local vector start, checkpoint, HitNormal, HitLocation; local actor HitActor; if ( newZone.bWaterZone ) { if (Physics != PHYS_Swimming) setPhysics(PHYS_Swimming); } else if (Physics == PHYS_Swimming) { SetPhysics(PHYS_Falling); MoveTimer = -1.0; GotoState('Flopping'); } } function PreSetMovement() { bCanJump = true; bCanWalk = false; bCanSwim = true; bCanFly = false; MinHitWall = -0.6; bCanOpenDoors = false; bCanDoSpecial = false; } function SetMovementPhysics() { if (Region.Zone.bWaterZone) SetPhysics(PHYS_Swimming); else { SetPhysics(PHYS_Falling); MoveTimer = -1.0; GotoState('Flopping'); } } function PlayWaiting() { LoopAnim('Fighter', 0.1 + 0.3 * FRand()); } function PlayPatrolStop() { LoopAnim('Fighter', 0.1 + 0.3 * FRand()); } function PlayWaitingAmbush() { LoopAnim('Fighter', 0.1 + 0.3 * FRand()); } function PlayChallenge() { PlayAnim('Fighter', 0.4, 0.2); } function TweenToFighter(float tweentime) { TweenAnim('Fighter', tweentime); } function TweenToRunning(float tweentime) { if ( (AnimSequence != 'Swim') || !bAnimLoop ) TweenAnim('Swim', tweentime); } function TweenToWalking(float tweentime) { if ( (AnimSequence != 'Swim') || !bAnimLoop ) TweenAnim('Swim', tweentime); } function TweenToWaiting(float tweentime) { PlayAnim('Fighter', 0.2 + 0.8 * FRand(), 0.3); } function TweenToPatrolStop(float tweentime) { TweenAnim('Fighter', tweentime); } function PlayRunning() { if ( ((AnimSequence == 'Spin') && (FRand() < 0.8)) || (FRand() < 0.06) ) LoopAnim('Spin'); else LoopAnim('Swim', -0.8/WaterSpeed,, 0.4); } function PlayWalking() { LoopAnim('Swim', -0.8/WaterSpeed,, 0.4); } function PlayThreatening() { if ( FRand() < 0.6 ) PlayAnim('Swim', 0.4); else { PlaySound(Spin, SLOT_Interact); PlayAnim('Spin', 0.4); } } function PlayTurning() { PlaySound(turn, SLOT_Interact); LoopAnim('Turn', 0.4); } function PlayDying(name DamageType, vector HitLocation) { PlaySound(Die, SLOT_Talk, 4 * TransientSoundVolume); PlayAnim('Dead1', 0.7, 0.1); } function PlayTakeHit(float tweentime, vector HitLoc, int damage) { TweenAnim('TakeHit', tweentime); } function TweenToFalling() { DesiredRotation = Rotation; DesiredRotation.Pitch = 0; TweenAnim('Spin', 0.2); } function PlayInAir() { LoopAnim('Fighter', 0.7); } function PlayLanded(float impactVel) { TweenAnim('Spin', 0.2); } function PlayVictoryDance() { PlayAnim('grab', 0.6, 0.1); PlaySound(Grab, SLOT_Interact); } function GrabTarget() { if ( MeleeDamageTarget(SlapDamage, (SlapDamage * 1500.0 * Normal(Location - Target.Location))) ) PlaySound(SlapGrabHit, SLOT_Interact); } function SlapTarget() { if ( MeleeDamageTarget(SlapDamage, (SlapDamage * 1500.0 * Normal(Target.Location - Location))) ) PlaySound(SlapGrabHit, SLOT_Interact); } function ThrustTarget() { if ( MeleeDamageTarget(ThrustDamage, (ThrustDamage * 1500.0 * Normal(Target.Location - Location))) ) PlaySound(ThrustHit, SLOT_Interact); } //FIXME - hold (turn off client's physics??? function PlayMeleeAttack() { local float decision; decision = FRand(); if (decision < 0.35) { PlaySound(Thrust, SLOT_Interact); PlayAnim('Thrust', 0.8); } if (decision < 0.7) { PlaySound(Slap, SLOT_Interact); PlayAnim('Slap', 0.8); } else { PlaySound(Grab, SLOT_Interact); PlayAnim('Grab'); } } function bool MeleeDamageTarget(int hitdamage, vector pushdir) { local vector HitLocation, HitNormal, TargetPoint; local float TargetDist; local actor HitActor; local bool result; result = false; TargetDist = VSize(Target.Location - Location); Acceleration = AccelRate * (Target.Location - Location)/TargetDist; If (TargetDist <= (MeleeRange * 1.4 + Target.CollisionRadius + CollisionRadius)) //still in melee range { TargetPoint = Location - TargetDist * vector(Rotation); TargetPoint.Z = FMin(TargetPoint.Z, Target.Location.Z + Target.CollisionHeight); TargetPoint.Z = FMax(TargetPoint.Z, Target.Location.Z - Target.CollisionHeight); HitActor = Trace(HitLocation, HitNormal, TargetPoint, Location, true); If (HitActor == Target) { Target.TakeDamage(hitdamage, Self,HitLocation, pushdir, 'hacked'); result = true; } } return result; } State Flopping { ignores seeplayer, hearnoise, enemynotvisible, hitwall; function Timer() { SetPhysics(PHYS_Falling); Velocity = 200 * VRand(); Velocity.Z = 170 + 200 * FRand(); DesiredRotation.Pitch = Rand(8192) - 4096; DesiredRotation.Yaw = Rand(65535); } function ZoneChange( ZoneInfo NewZone ) { local Rotator newRotation; if (NewZone.bWaterZone) { newRotation = Rotation; newRotation.Roll = 0; SetRotation(newRotation); SetPhysics(PHYS_Swimming); GotoState('Attacking'); } else if (Physics != PHYS_Falling) SetPhysics(PHYS_Falling); } function Landed(vector HitNormal) { SetPhysics(PHYS_None); DesiredRotation.Pitch = 0; SetTimer(0.3 + FRand(), false); } function AnimEnd() { PlayAnim('Spin', 0.7); } Begin: SetTimer(0.3 + FRand(), false); TweenAnim('Flopping', 0.7); } state TacticalMove { ignores SeePlayer, HearNoise; function Timer() { Spawn(class'BigBlackSmoke'); } function BeginState() { SetTimer(0.2, true); Super.BeginState(); } } //squid has own melee attack because he faces away from his target when attacking state MeleeAttack { ignores SeePlayer, HearNoise, Bump; function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType); if ( health <= 0 ) return; if (NextState == 'TakeHit') { NextState = 'MeleeAttack'; NextLabel = 'Begin'; } } function KeepAttacking() { bReadyToAttack = true; if ( (Target == None) || ((Pawn(Target) != None) && (Pawn(Target).Health == 0)) ) GotoState('Attacking'); else if (VSize(Target.Location - Location) > (0.9 * MeleeRange + Target.CollisionRadius + CollisionRadius)) GotoState('TacticalMove', 'NoCharge'); } function EnemyNotVisible() { //log("enemy not visible"); GotoState('Attacking'); } function AnimEnd() { GotoState('MeleeAttack', 'DoneAttacking'); } function BeginState() { Disable('AnimEnd'); bCanStrafe = true; //so he can turn in place } function EndState() { bCanStrafe = false; } Begin: if (Target == None) Target = Enemy; FaceTarget: Acceleration = Vect(0,0,0); if (NeedToTurn(2 * Location - Target.Location)) { PlayTurning(); TurnTo(2 * Location - Target.Location); TweenToFighter(0.15); } else if ( (5 - Skill) * FRand() > 3 ) { DesiredRotation = Rotator(Location - Target.Location); PlayChallenge(); } FinishAnim(); if (VSize(Location - Target.Location) > MeleeRange + CollisionRadius + Target.CollisionRadius) GotoState('Attacking'); ReadyToAttack: DesiredRotation = Rotator(Location - Target.Location); PlayMeleeAttack(); Enable('AnimEnd'); Attacking: TurnTo(2 * Location - Target.Location); Goto('Attacking'); DoneAttacking: Disable('AnimEnd'); KeepAttacking(); Goto('FaceTarget'); } p ] \"toN ad$ HD i"W u 6- 0-Tu W wW L=aV $a!e>>L>a!>? Qn"P8Pp L-7p >~LLp ?:-'P -  q!>q!'( $j"$LD6- :a!L??= l"[ a'*6- Ua!@ ? f 6f x6xk6kg f xK kx[ g K  [ L?a!@ ?%8[ La!@ ?%J g #?J kx?%!k !la!k  ?a!k =?%!m !ja!m  ?%a!m =? !q",*!f!Oq! Ng"K'tB6p"cBEtԝXԝXԝXԝXԝXԝXԝXԝXԝX1ԝXԝXԝXԝXԝXԝXԝXԝXԝXԝXԝX11| #k@ { @ X F P ?$L?I$BM$E$CK$\$DT$!"pL V O ]Squidu H7$ B/$pB<$HCa$HCP:S2a2yr"o"q}-+N   s"O8Ohfe_,% -g'!p: :$!^!!f!Oq! at"Fbƌ7?,xF q!b!B Z/.-::$ w* b  m"m yR36-a!d > ia!Q > x6xs6st6tqxsK tsm qK  m L?a!Q >PLm La!Q >PL>?v q#?v ts?%!k !la!l  ?a!l =?P2!m !ja!j  ?Pa!j =? #y"n//============================================================================= // TeamSkaarjScout. //============================================================================= class TeamSkaarjScout extends TeamSkaarjWarrior; [{"]f6-S(r*(j Dj?(R>'|  #?_#?^ | _jM ^ 6M M 9L?(D acb_?,d^ _(*rD *(-S'' j"mywhl4-m?,?,q!>j^-?,?&q!(jq!(!h u"x 56- x E>?ax 333?a!8E>x fff?:a!E>aV $a!eE> d A#~"|~g2d aEs (rd * }"H|!D h O b?Eիfff?D իfff?h ի>O H]&E-5-qaY!EHEEիff?h 6HaY!EH c1of=4B@-|q!!~4q!v!1 aqmbY|d+?,xm   M#O8kaZ8OLIrq,% X!!!q! x"a B6E#ϰLr$333?!";$>] Skaarj Scout[k @##.B36-a!d > a!R? F#@8`aV $a!e?= mxD Jnwn*na/!Vna/!] n ? bnnq! nnmxw _T"eOH tevv:>RKv-g6g%a+go$Lq!Po$ l//============================================================================= // TeamSkaarjLord. //============================================================================= class TeamSkaarjLord extends TeamSkaarjWarrior; eH#M S 72M a/!]M a/!b$5$ !,-G`H#!!!q! X 1T q!f K#b B6P#KeL#{#tr$>!"@A$?;$ff&?] Skaarj Lord[^V d T U-Ed 3''''?,>- (-?( R#s-(-?'- '?,  ?  ? S#S )XO r*      T#sf2I-(sts UD"cd_[#eqJ- ?Y siHpBr*)w.*.%q!nn-l ?a'(q!!Z IU#u689"a%!}a&!~?7Iurq Z#x Y#_#|SY BPY -'NwT *-'VaT NwV*V k ^#[O#k !wV*VY ]#YW0$$a!A @=q!(!m r`#{Ac iZ {X:Z:$ :Z:$H::$|{X:Z:$ r* ::$>L> I { W I pW => \ JY] { I ,] \ L? [oJ?%J?eJ'geJ( z"f#}%j::$ -(A ? (]a^ u #?(r]*]a^ u  #?(r]*( uc 6,?a$ ף< LIa$ ף< Lt6?,ȫ?,da&!ec ?a&!\ c a&!c  I ^ g`k#P0H.Z !L Z !\ y{.>9y>ybOy?(o-J'g #?Pg?%g?6]6]6]^aK L ?,dg(]cw^*g?^aK L ?,dg(]pw^*(::$^aK L ?,dg#??,dg(]r^*(?,gq!!C' r//============================================================================= // TeamSkaarjInfantry. //============================================================================= class TeamSkaarjInfantry extends TeamSkaarjTrooper; ao#Sb&GG7?,xS q!!C o@i#c B6m#.!@6'K ]Skaarj InfantryY@FJV(C,w.C*F-$YFCg !a ,F*!>!\q! ` p//============================================================================= // TeamSkaarjGunner. //============================================================================= class TeamSkaarjGunner extends TeamSkaarjTrooper; Z DIw !::$ -bG-q!!Z @q#f B6s#-;@6'K [^wXv#N}-I iIA#L?i?,I?,IiA?,Air*(v  ~ p 6 v ի?6  6 ~ a/!F a/!i a/!q Jay t  Ap'Jay t pIAp'rJ'wJ*y ?,()w.J*: .J:$(' y x# K<9-o71- bi7  Y[jv P9r*r* C f 6C6CC?,f ^b[r.**w*[b[br[*C[[  b#A rlE-Q'CG !/a0 A G BA R10 K cz#x ,-o(::$ sK a/!~.K Ce?%#q!^!s bq!^!T* @$+ +-'u! iz//============================================================================= // TeamSkaarj. //============================================================================= class TeamSkaarjWarrior extends TeamSkaarj; //----------------------------------------------------------------------------- // SkaarjWarrior variables. var(Sounds) sound Blade; //========================================================================================= function PostBeginPlay() { Super.PostBeginPlay(); if ( skill == 3 ) { SpinDamage = 20; ClawDamage = 17; } } function TryToDuck(vector duckDir, bool bReversed) { local vector HitLocation, HitNormal, Extent; local bool duckLeft, bSuccess; local actor HitActor; local float decision; //log("duck"); duckDir.Z = 0; duckLeft = !bReversed; Extent.X = CollisionRadius; Extent.Y = CollisionRadius; Extent.Z = CollisionHeight; HitActor = Trace(HitLocation, HitNormal, Location + 200 * duckDir, Location, false, Extent); bSuccess = ( (HitActor == None) || (VSize(HitLocation - Location) > 150) ); if ( !bSuccess ) { duckLeft = !duckLeft; duckDir *= -1; HitActor = Trace(HitLocation, HitNormal, Location + 200 * duckDir, Location, false, Extent); bSuccess = ( (HitActor == None) || (VSize(HitLocation - Location) > 150) ); } if ( !bSuccess ) return; if ( HitActor == None ) HitLocation = Location + 200 * duckDir; HitActor = Trace(HitLocation, HitNormal, HitLocation - MaxStepHeight * vect(0,0,1), HitLocation, false, Extent); if (HitActor == None) return; //log("good duck"); SetFall(); if ( duckLeft ) PlayAnim('LeftDodge', 1.35); else PlayAnim('RightDodge', 1.35); Velocity = duckDir * GroundSpeed; Velocity.Z = 200; SetPhysics(PHYS_Falling); GotoState('FallingState','Ducking'); } function bool CanFireAtEnemy() { local vector HitLocation, HitNormal,X,Y,Z, projStart, EnemyDir, EnemyUp; local actor HitActor1, HitActor2; local float EnemyDist; EnemyDir = Enemy.Location - Location; EnemyDist = VSize(EnemyDir); EnemyUp = Enemy.CollisionHeight * vect(0,0,0.9); if ( EnemyDist > 300 ) { EnemyDir = 300 * EnemyDir/EnemyDist; EnemyUp = 300 * EnemyUp/EnemyDist; } GetAxes(Rotation,X,Y,Z); projStart = Location + 0.9 * CollisionRadius * X + CollisionRadius * Y + 0.4 * CollisionHeight * Z; HitActor1 = Trace(HitLocation, HitNormal, projStart + EnemyDir + EnemyUp, projStart, true); if ( (HitActor1 != Enemy) && (Pawn(HitActor1) != None) && (AttitudeTo(Pawn(HitActor1)) > ATTITUDE_Ignore) ) return false; projStart = Location + 0.9 * CollisionRadius * X - CollisionRadius * Y + 0.4 * CollisionHeight * Z; HitActor2 = Trace(HitLocation, HitNormal, projStart + EnemyDir + EnemyUp, projStart, true); if ( (HitActor2 != Enemy) && (Pawn(HitActor2) != None) && (AttitudeTo(Pawn(HitActor2)) > ATTITUDE_Ignore) ) return false; if ( (HitActor2 == None) || (HitActor2 == Enemy) || (HitActor1 == None) || (HitActor1 == Enemy) || (Pawn(HitActor2) != None) || (Pawn(HitActor1) != None) ) return true; HitActor2 = Trace(HitLocation, HitNormal, projStart + EnemyDir, projStart , true); return ( (HitActor2 == None) || (HitActor2 == Enemy) || ((Pawn(HitActor2) != None) && (AttitudeTo(Pawn(HitActor2)) <= ATTITUDE_Ignore)) ); } function PlayCock() { PlaySound(Blade, SLOT_Interact,,,800); } function PlayPatrolStop() { local float decision; if (Region.Zone.bWaterZone) { PlaySwimming(); return; } if ( bButtonPusher ) { PushButtons(); return; } decision = FRand(); if (decision < 0.05) { SetAlertness(-0.5); PlaySound(HairFlip, SLOT_Talk); PlayAnim('HairFlip', 0.4 + 0.3 * FRand()); } else { SetAlertness(0.2); LoopAnim('Breath', 0.3 + 0.6 * FRand()); } } function PlayChallenge() { if (Region.Zone.bWaterZone) { PlaySwimming(); return; } PlayThreateningSound(); PlayAnim('Fighter', 0.8 + 0.5 * FRand(), 0.1); } function PlayRunning() { local float strafeMag; local vector Focus2D, Loc2D, Dest2D; local vector lookDir, moveDir, Y; DesiredSpeed = MaxDesiredSpeed; if (Region.Zone.bWaterZone) { PlaySwimming(); return; } if (Focus == Destination) { LoopAnim('Jog', -1.0/GroundSpeed,, 0.5); return; } Focus2D = Focus; Focus2D.Z = 0; Loc2D = Location; Loc2D.Z = 0; Dest2D = Destination; Dest2D.Z = 0; lookDir = Normal(Focus2D - Loc2D); moveDir = Normal(Dest2D - Loc2D); strafeMag = lookDir dot moveDir; if (strafeMag > 0.8) LoopAnim('Jog', -1.0/GroundSpeed,, 0.5); else if (strafeMag < -0.8) LoopAnim('Jog', -1.0/GroundSpeed,, 0.5); else { Y = (lookDir Cross vect(0,0,1)); if ((Y Dot (Dest2D - Loc2D)) > 0) { if ( (AnimSequence == 'StrafeRight') || (AnimSequence == 'StrafeRightFr') ) LoopAnim('StrafeRight', -2.5/GroundSpeed,, 1.0); else LoopAnim('StrafeRight', -2.5/GroundSpeed,0.1, 1.0); } else { if ( (AnimSequence == 'StrafeLeft') || (AnimSequence == 'StrafeLeftFr') ) LoopAnim('StrafeLeft', -2.5/GroundSpeed,, 1.0); else LoopAnim('StrafeLeft', -2.5/GroundSpeed,0.1, 1.0); } } } function PlayMovingAttack() { local float strafeMag; local vector Focus2D, Loc2D, Dest2D; local vector lookDir, moveDir, Y; if (Region.Zone.bWaterZone) { LoopAnim('SwimFire', -1.0/WaterSpeed,, 0.4); return; } DesiredSpeed = MaxDesiredSpeed; if (Focus == Destination) { LoopAnim('JogFire', -1.0/GroundSpeed,, 0.4); return; } Focus2D = Focus; Focus2D.Z = 0; Loc2D = Location; Loc2D.Z = 0; Dest2D = Destination; Dest2D.Z = 0; lookDir = Normal(Focus2D - Loc2D); moveDir = Normal(Dest2D - Loc2D); strafeMag = lookDir dot moveDir; if (strafeMag > 0.8) LoopAnim('JogFire', -1.0/GroundSpeed,, 0.4); else if (strafeMag < -0.8) LoopAnim('JogFire', -1.0/GroundSpeed,, 0.4); else { MoveTimer += 0.2; DesiredSpeed = 0.6; Y = (lookDir Cross vect(0,0,1)); if ((Y Dot (Dest2D - Loc2D)) > 0) { if ( (AnimSequence == 'StrafeRight') || (AnimSequence == 'StrafeRightFr') ) LoopAnim('StrafeRightFr', -2.5/GroundSpeed,, 1.0); else LoopAnim('StrafeRightFr', -2.5/GroundSpeed,0.1, 1.0); } else { if ( (AnimSequence == 'StrafeLeft') || (AnimSequence == 'StrafeLeftFr') ) LoopAnim('StrafeLeftFr', -2.5/GroundSpeed,, 1.0); else LoopAnim('StrafeLeftFr', -2.5/GroundSpeed,0.1, 1.0); } } } function PlayThreatening() { local float decision, animspeed; if (Region.Zone.bWaterZone) { PlaySwimming(); return; } decision = FRand(); animspeed = 0.4 + 0.6 * FRand(); if ( decision < 0.7 ) PlayAnim('Breath2', animspeed, 0.3); else if ( decision < 0.9 ) { PlayThreateningSound(); PlayAnim('Fighter', animspeed, 0.3); } else { PlaySound(HairFlip, SLOT_Talk); PlayAnim('HairFlip', animspeed, 0.3); } } function SpawnTwoShots() { local rotator FireRotation; local vector X,Y,Z, projStart; GetAxes(Rotation,X,Y,Z); MakeNoise(1.0); projStart = Location + 0.9 * CollisionRadius * X + 0.9 * CollisionRadius * Y + 0.4 * CollisionHeight * Z; FireRotation = AdjustAim(ProjectileSpeed, projStart, 400, bLeadTarget, bWarnTarget); spawn(RangedProjectile,self,'',projStart, FireRotation); projStart = projStart - 1.8 * CollisionRadius * Y; FireRotation.Yaw += 400; spawn(RangedProjectile,self,'',projStart, FireRotation); } function PlayRangedAttack() { if (Region.Zone.bWaterZone) { LoopAnim('SwimFire', -1.0/WaterSpeed,, 0.4); return; } PlayAnim('Firing', 1.5); } function PlayVictoryDance() { PlaySound(HairFlip, SLOT_Talk); PlayAnim('HairFlip', 0.6, 0.1); } Mz//============================================================================= // TeamSlith. //============================================================================= class TeamSlith extends TeamScriptedPawn; //FIXME - not using Charge1sl //----------------------------------------------------------------------------- // Slith variables. // Attack damage. var() byte ClawDamage; // Basic damage done by Claw/punch. var bool bFirstAttack; var(Sounds) sound die2; var(Sounds) sound slick; var(Sounds) sound slash; var(Sounds) sound slice; var(Sounds) sound slither; var(Sounds) sound swim; var(Sounds) sound dive; var(Sounds) sound surface; var(Sounds) sound scratch; var(Sounds) sound charge; //----------------------------------------------------------------------------- // Slith functions. /* PreSetMovement() default for walking creature. Re-implement in subclass for swimming/flying capability */ function PreSetMovement() { MaxDesiredSpeed = 0.79 + 0.07 * skill; bCanJump = true; bCanWalk = true; bCanSwim = true; bCanFly = false; MinHitWall = -0.6; if (Intelligence > BRAINS_Reptile) bCanOpenDoors = true; if (Intelligence == BRAINS_Human) bCanDoSpecial = true; } //Azathoth deleted function eAttitude AttitudeToCreature(Pawn Other) function SetMovementPhysics() { if (Region.Zone.bWaterZone && (Physics != PHYS_Swimming) ) SetPhysics(PHYS_Swimming); else if (Physics != PHYS_Walking) SetPhysics(PHYS_Walking); } function JumpOutOfWater(vector jumpDir) { Falling(); Velocity = jumpDir * WaterSpeed; Acceleration = jumpDir * AccelRate; velocity.Z = 460; //set here so physics uses this for remainder of tick PlayOutOfWater(); bUpAndOut = true; } function SetFall() { if (Enemy != None) { NextState = 'Attacking'; //default NextLabel = 'Begin'; NextAnim = 'LFighter'; GotoState('FallingState'); } } function PlayAcquisitionSound() { if ( FRand() < 0.5 ) PlaySound(Acquire, SLOT_Talk); else PlaySound(sound'yell3sl', SLOT_Talk); } function PlayWaiting() { local float decision; if (Region.Zone.bWaterZone) { LoopAnim('Swim', 0.2 + 0.3 * FRand()); return; } decision = FRand(); if (decision < 0.8) LoopAnim('Breath', 0.2 + 0.6 * FRand()); else if (decision < 0.9) { PlaySound(Slick, SLOT_Interact); LoopAnim('Slick', 0.4 + 0.6 * FRand()); } else { PlaySound(Scratch, SLOT_Interact); LoopAnim('Scratch', 0.4 + 0.6 * FRand()); } } function PlayPatrolStop() { PlayWaiting(); } function PlayWaitingAmbush() { PlayWaiting(); } function PlayChallenge() { TweenToFighter(0.1); } function TweenToFighter(float tweentime) { if (Region.Zone.bWaterZone) TweenAnim('WFighter', tweentime); else TweenAnim('LFighter', tweentime); } function TweenToRunning(float tweentime) { if (Region.Zone.bWaterZone) { if ( (AnimSequence == 'Shoot2') && IsAnimating() ) return; if ( (AnimSequence != 'Swim') || !bAnimLoop ) TweenAnim('Swim', tweentime); } else { if ( (AnimSequence == 'Shoot1') && IsAnimating() ) return; if ( (AnimSequence != 'Slither') || !bAnimLoop ) TweenAnim('Slither', tweentime); } } function TweenToWalking(float tweentime) { if (Region.Zone.bWaterZone) { if ( (AnimSequence != 'Swim') || !bAnimLoop ) TweenAnim('Swim', tweentime); } else { if ( (AnimSequence != 'Slither') || !bAnimLoop ) TweenAnim('Slither', tweentime); } } function TweenToWaiting(float tweentime) { if (Region.Zone.bWaterZone) TweenAnim('Swim', tweentime); else TweenAnim('Breath', tweentime); } function TweenToPatrolStop(float tweentime) { TweenToWaiting(tweentime); } function PlayRunning() { if (Region.Zone.bWaterZone) { PlaySound(Swim, SLOT_Interact); LoopAnim('Swim', -1.0/WaterSpeed,, 0.4); } else { PlaySound(Slither, SLOT_Interact); LoopAnim('Slither', -1.1/GroundSpeed,, 0.4); } } function PlayWalking() { if (Region.Zone.bWaterZone) { PlaySound(Swim, SLOT_Interact); LoopAnim('Swim', -1.0/WaterSpeed,, 0.4); } else { PlaySound(Slither, SLOT_Interact); LoopAnim('Slither', -1.3/GroundSpeed,, 0.4); } } function PlayThreatening() { local float decision; decision = FRand(); if (decision < 0.8) { PlayWaiting(); return; } NextAnim = ''; if (Region.Zone.bWaterZone) TweenAnim('WFighter', 0.25); else TweenAnim('LFighter', 0.25); } function PlayTurning() { if (Region.Zone.bWaterZone) TweenAnim('Swim', 0.35); else TweenAnim('Slither', 0.35); } function PlayDying(name DamageType, vector HitLocation) { if (Region.Zone.bWaterZone) { PlaySound(Die2, SLOT_Talk, 4 * TransientSoundVolume); PlayAnim('Dead2', 0.7, 0.1); } else { PlaySound(Die, SLOT_Talk, 4 * TransientSoundVolume); PlayAnim('Dead1', 0.7, 0.1); } } function PlayTakeHit(float tweentime, vector HitLoc, int Damage) { if (Region.Zone.bWaterZone) TweenAnim('WTakeHit', tweentime); else TweenAnim('LTakeHit', tweentime); } function PlayOutOfWater() { PlayAnim('Surface',,0.1); } function PlayDive() { PlayAnim('Dive',,0.1); } function TweenToFalling() { TweenAnim('Falling', 0.4); } function PlayInAir() { TweenAnim('Falling', 0.4); } function PlayLanded(float impactVel) { TweenAnim('Slither', 0.25); } function PlayVictoryDance() { PlayAnim('ChargeUp', 0.3, 0.1); PlaySound(Charge, SLOT_Interact); } function ClawDamageTarget() { MeleeDamageTarget(ClawDamage, (ClawDamage * 1000.0 * Normal(Target.Location - Location))); } function PlayMeleeAttack() { local float decision; decision = FRand(); Acceleration = AccelRate * Normal(Target.Location - Location); //log("Start Melee Attack"); if ( Region.Zone.bWaterZone ) { if (AnimSequence == 'Claw1') decision += 0.17; else if (AnimSequence == 'Claw2') decision -= 0.17; if (decision < 0.5) PlayAnim('Claw1'); else PlayAnim('Claw2'); } else { if (AnimSequence == 'Punch') decision += 0.17; else if (AnimSequence == 'Slash') decision -= 0.17; if (decision < 0.5) { PlayAnim('Punch'); } else { PlayAnim('Slash'); } } } function bool CanFireAtEnemy() { local vector HitLocation, HitNormal, EnemyDir, projStart; local actor HitActor; local float EnemyDist; EnemyDir = Enemy.Location - Location + Enemy.CollisionHeight * vect(0,0,0.8); EnemyDist = VSize(EnemyDir); if (EnemyDist > 750) //FIXME - what is right number? return false; EnemyDir = EnemyDir/EnemyDist; projStart = Location + 0.8 * CollisionRadius * EnemyDir + 0.8 * CollisionHeight * vect(0,0,1); HitActor = Trace(HitLocation, HitNormal, projStart + (MeleeRange + Enemy.CollisionRadius) * EnemyDir, projStart, false, vect(6,6,4) ); return (HitActor == None); } function ShootTarget() { FireProjectile( vect(1, 0, 0.8), 900); } function PlayRangedAttack() { if (Region.Zone.bWaterZone) PlayAnim('Shoot2'); else PlayAnim('Shoot1'); } function PlayMovingAttack() { PlayRangedAttack(); } state MeleeAttack { ignores SeePlayer, HearNoise, Bump; function PlayMeleeAttack() { if ( Region.Zone.bWaterZone && !bFirstAttack && (FRand() > 0.4 + 0.17 * skill) ) { PlayAnim('Swim'); Acceleration = AccelRate * Normal(Location - Enemy.Location + 0.9 * VRand()); } else Global.PlayMeleeAttack(); bFirstAttack = false; } function BeginState() { Super.BeginState(); bCanStrafe = True; bFirstAttack = True; } function EndState() { Super.EndState(); bCanStrafe = false; } } ~#|%`B6#Q0E1t1tttԝX1ԝX111111111111tkkZ.`P~XC$??$333?`$>H$>rV|L$;DhgUKI$HBM$zCE$Cq$TDj$Bp\$D!"vV[$?$LVO;$Y?]SlithuH7$@B/$0B<$HCa$HCP:S @p n *Z8nlkge,% X!!^!q! ] u#tcljw*<w*a$ /Djjw*a$ /D A$C$U6- 0-Tu L>a!>? $B$$z\6- 7]a&!Q= :a!L??= D$^ 7$$:6- ea!@fff ? i6if6f[6[W if@ [f^ W @ ^ L?a!@ ?5H^ La!@ ?5j W #?j [f?%!k !la!k  ?a!k =?5!m !ja!m  ?5a!m =? G$3{ $?%-' I$ v # -( @//============================================================================= // TeamSkaarjTrooper. //============================================================================= class TeamSkaarjTrooper extends TeamSkaarj; //----------------------------------------------------------------------------- // SkaarjTrooper variables. var() class WeaponType; var Weapon myWeapon; var float duckTime; //========================================================================================= function PreBeginPlay() { Super.PreBeginPlay(); if ( TimeBetweenAttacks == Default.TimeBetweenAttacks ) TimeBetweenAttacks = TimeBetweenAttacks + (3 - Skill) * 0.3; bHasRangedAttack = false; bMovingRangedAttack = false; } function ChangedWeapon() { Super.ChangedWeapon(); bIsPlayer = false; bMovingRangedAttack = true; bHasRangedAttack = true; Weapon.AimError += 200; Weapon.FireOffset = Weapon.FireOffset * 1.5 * DrawScale; Weapon.PlayerViewOffset = Weapon.PlayerViewOffset * 1.5 * DrawScale; //Weapon.SetHand(0); } function TossWeapon() { if ( Weapon == None ) return; Weapon.FireOffset = Weapon.Default.FireOffset; Weapon.PlayerViewOffset = Weapon.Default.PlayerViewOffset; Super.TossWeapon(); } function Died(pawn Killer, name damageType, vector HitLocation) { bIsPlayer = false; Super.Died(Killer, damageType, HitLocation); } function PlayTakeHit(float tweentime, vector HitLoc, int damage) { if ( GetAnimGroup(AnimSequence) == 'Shielded' ) TweenAnim('ShldLand', 0.5); else Super.PlayTakeHit(tweentime, HitLoc, damage); } auto state Startup { function BeginState() { Super.BeginState(); bIsPlayer = true; // temporarily, till have weapon if ( WeaponType != None ) { bIsPlayer = true; myWeapon = Spawn(WeaponType); if ( myWeapon != None ) myWeapon.ReSpawnTime = 0.0; } } function SetHome() { Super.SetHome(); if ( myWeapon != None ) myWeapon.Touch(self); } } function Shield() { bFire = 0; bAltFire = 0; PlayAnim('ShldUp', 2.0, 0.1); GotoState('RangedAttack', 'Shieldup'); } function WarnTarget(Pawn shooter, float projSpeed, vector FireDir) { local float MaxSpeed, enemyDist; local eAttitude att; local vector X,Y,Z, enemyDir; att = AttitudeTo(shooter); if ( (att == ATTITUDE_Ignore) || (att == ATTITUDE_Threaten) ) { if ( intelligence >= BRAINS_Mammal ) damageAttitudeTo(shooter); if (att == ATTITUDE_Ignore) return; } // AI controlled creatures may duck if not falling if ( (Enemy == None) || (Physics == PHYS_Falling) || (FRand() > 0.4 + 0.2 * skill) ) return; // and projectile time is long enough enemyDist = VSize(shooter.Location - Location); duckTime = enemyDist/projSpeed; if (duckTime < 0.1 + 0.15 * FRand()) //FIXME - pick right value return; // only if tight FOV GetAxes(Rotation,X,Y,Z); enemyDir = (shooter.Location - Location)/enemyDist; if ((enemyDir Dot X) < 0.8) return; if ( (FireDir Dot Y) > 0 ) { Y *= -1; TryToDuck(Y, true); } else TryToDuck(Y, false); } function TryToDuck(vector duckDir, bool bReversed) { local vector HitLocation, HitNormal, Extent; local bool duckLeft; local actor HitActor; local float decision; if ( (FRand() < 0.4) || (VSize(Velocity) < 50) ) { Shield(); return; } duckDir.Z = 0; duckLeft = !bReversed; Extent.X = CollisionRadius; Extent.Y = CollisionRadius; Extent.Z = CollisionHeight; HitActor = Trace(HitLocation, HitNormal, Location + 200 * duckDir, Location, false, Extent); if (HitActor != None) { duckLeft = !duckLeft; duckDir *= -1; HitActor = Trace(HitLocation, HitNormal, Location + 200 * duckDir, Location, false, Extent); } if (HitActor != None) { Shield(); return; } HitActor = Trace(HitLocation, HitNormal, Location + 200 * duckDir - MaxStepHeight * vect(0,0,1), Location + 200 * duckDir, false, Extent); if (HitActor == None) { Shield(); return; } SetFall(); if ( duckLeft ) PlayAnim('LeftDodge', 1.35); else PlayAnim('RightDodge', 1.35); Velocity = duckDir * GroundSpeed; Velocity.Z = 200; SetPhysics(PHYS_Falling); GotoState('FallingState','Ducking'); } function bool CanFireAtEnemy() { local vector HitLocation, HitNormal,X,Y,Z, projStart, EnemyDir, EnemyUp; local actor HitActor; local float EnemyDist; EnemyDir = Enemy.Location - Location; EnemyDist = VSize(EnemyDir); EnemyUp = Enemy.CollisionHeight * vect(0,0,0.8); if ( EnemyDist > 300 ) { EnemyDir = 300 * EnemyDir/EnemyDist; EnemyUp = 300 * EnemyUp/EnemyDist; } if ( Weapon == None ) return false; GetAxes(Rotation,X,Y,Z); projStart = Location + Weapon.CalcDrawOffset() + Weapon.FireOffset.X * X + 1.2 * Weapon.FireOffset.Y * Y + Weapon.FireOffset.Z * Z; if ( Weapon.IsA('ASMD') || Weapon.IsA('Minigun') || Weapon.IsA('Rifle') ) //instant hit HitActor = Trace(HitLocation, HitNormal, Enemy.Location + EnemyUp, projStart, true); else HitActor = Trace(HitLocation, HitNormal, projStart + EnemyDir + EnemyUp, projStart, true); if ( HitActor == Enemy ) return true; if ( (HitActor != None) && (VSize(HitLocation - Location) < 200) ) return false; if ( (Pawn(HitActor) != None) && (AttitudeTo(Pawn(HitActor)) > ATTITUDE_Ignore) ) return false; return true; } function PlayCock() { if ( Weapon != None ) { if ( Weapon.CockingSound != None ) PlaySound(Weapon.CockingSound, SLOT_Interact,,,700); else if ( Weapon.SelectSound != None ) PlaySound(Weapon.CockingSound, SLOT_Interact,,,700); } } //Skaarj animations function PlayPatrolStop() { local float decision; if (Region.Zone.bWaterZone) { PlaySwimming(); return; } if ( bButtonPusher ) { PushButtons(); return; } SetAlertness(0.2); LoopAnim('Breath', 0.3 + 0.6 * FRand()); } function PlayChallenge() { if (Region.Zone.bWaterZone) { PlaySwimming(); return; } if ( TryToCrouch() ) { TweenAnim('Duck', 0.12); return; } PlayThreateningSound(); PlayAnim('Fighter', 0.8 + 0.5 * FRand(), 0.1); } function PlayRunning() { local float strafeMag; local vector Focus2D, Loc2D, Dest2D; local vector lookDir, moveDir, Y; bFire = 0; bAltFire = 0; DesiredSpeed = MaxDesiredSpeed; if (Region.Zone.bWaterZone) { PlaySwimming(); return; } if (Focus == Destination) { LoopAnim('Jog', -0.9/GroundSpeed,, 0.5); return; } Focus2D = Focus; Focus2D.Z = 0; Loc2D = Location; Loc2D.Z = 0; Dest2D = Destination; Dest2D.Z = 0; lookDir = Normal(Focus2D - Loc2D); moveDir = Normal(Dest2D - Loc2D); strafeMag = lookDir dot moveDir; if (strafeMag > 0.8) LoopAnim('Jog', -1.0/GroundSpeed,, 0.5); else if (strafeMag < -0.8) LoopAnim('Jog', -1.0/GroundSpeed,, 0.5); else { Y = (lookDir Cross vect(0,0,1)); if ((Y Dot (Dest2D - Loc2D)) > 0) { if ( (AnimSequence == 'StrafeRight') || (AnimSequence == 'StrafeRightFr') ) LoopAnim('StrafeRight', -2.5/GroundSpeed,, 1.0); else LoopAnim('StrafeRight', -2.5/GroundSpeed,0.1, 1.0); } else { if ( (AnimSequence == 'StrafeLeft') || (AnimSequence == 'StrafeLeftFr') ) LoopAnim('StrafeLeft', -2.5/GroundSpeed,, 1.0); else LoopAnim('StrafeLeft', -2.5/GroundSpeed,0.1, 1.0); } } } function PlayMovingAttack() { local float strafeMag; local vector Focus2D, Loc2D, Dest2D; local vector lookDir, moveDir, Y; local int bUseAltMode; if (Weapon != None) { if ( Weapon.AmmoType != None ) Weapon.AmmoType.AmmoAmount = Weapon.AmmoType.Default.AmmoAmount; Weapon.RateSelf(bUseAltMode); ViewRotation = Rotation; if ( bUseAltMode == 0 ) { bFire = 1; bAltFire = 0; Weapon.Fire(1.0); } else { bFire = 0; bAltFire = 1; Weapon.AltFire(1.0); } } else { PlayRunning(); return; } if (Region.Zone.bWaterZone) { PlaySwimming(); return; } DesiredSpeed = MaxDesiredSpeed; if (Focus == Destination) { LoopAnim('JogFire', -0.9/GroundSpeed,, 0.4); return; } Focus2D = Focus; Focus2D.Z = 0; Loc2D = Location; Loc2D.Z = 0; Dest2D = Destination; Dest2D.Z = 0; lookDir = Normal(Focus2D - Loc2D); moveDir = Normal(Dest2D - Loc2D); strafeMag = lookDir dot moveDir; if (strafeMag > 0.8) LoopAnim('JogFire', -1.0/GroundSpeed,, 0.4); else if (strafeMag < -0.8) LoopAnim('JogFire', -1.0/GroundSpeed,, 0.4); else { MoveTimer += 0.2; DesiredSpeed = 0.6; Y = (lookDir Cross vect(0,0,1)); if ((Y Dot (Dest2D - Loc2D)) > 0) { if ( (AnimSequence == 'StrafeRight') || (AnimSequence == 'StrafeRightFr') ) LoopAnim('StrafeRightFr', -2.5/GroundSpeed,, 1.0); else LoopAnim('StrafeRightFr', -2.5/GroundSpeed,0.1, 1.0); } else { if ( (AnimSequence == 'StrafeLeft') || (AnimSequence == 'StrafeLeftFr') ) LoopAnim('StrafeLeftFr', -2.5/GroundSpeed,, 1.0); else LoopAnim('StrafeLeftFr', -2.5/GroundSpeed,0.1, 1.0); } } } function PlayThreatening() { local float decision, animspeed; if (Region.Zone.bWaterZone) { PlaySwimming(); return; } decision = FRand(); animspeed = 0.4 + 0.6 * FRand(); if ( decision < 0.7 ) PlayAnim('Breath2', animspeed, 0.3); else { PlayThreateningSound(); PlayAnim('Fighter', animspeed, 0.3); } } function PlayRangedAttack() { PlayFiring(); } function PlayFiring() { TweenAnim('Firing', 0.2); if ( (Weapon != None) && (Weapon.AmmoType != None) ) Weapon.AmmoType.AmmoAmount = Weapon.AmmoType.Default.AmmoAmount; } function PlayVictoryDance() { PlayAnim('Shield', 0.6, 0.1); } function PlayLanded(float impactVel) { if ( GetAnimGroup(AnimSequence) == 'Shielded' ) TweenAnim('ShldLand', 0.1); else if (impactVel > 1.7 * JumpZ) PlayAnim('Landed',1.0,0.1); else TweenAnim('Land', 0.1); } state TakeHit { ignores seeplayer, hearnoise, bump, hitwall; function BeginState() { bFire = 0; bAltFire = 0; Super.BeginState(); } } state Retreating { ignores SeePlayer, EnemyNotVisible, HearNoise; function EndState() { bFire = 0; bAltFire = 0; Super.EndState(); } } state Charging { ignores SeePlayer, HearNoise; function EndState() { bFire = 0; bAltFire = 0; Super.EndState(); } } state TacticalMove { ignores SeePlayer, HearNoise; function EndState() { bFire = 0; bAltFire = 0; Super.EndState(); } } state Hunting { ignores EnemyNotVisible; function EndState() { bFire = 0; bAltFire = 0; if ( !Region.Zone.bWaterZone ) bCanSwim = false; Super.EndState(); } } state MeleeAttack { ignores SeePlayer, HearNoise, Bump; ShieldDown: DesiredRotation = Rotator(Enemy.Location - Location); FinishAnim(); Goto('Begin'); } state RangedAttack { ignores SeePlayer, HearNoise; function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { if ( (GetAnimGroup(AnimSequence) == 'Shielded') && (AnimSequence != 'ShldFire') && ((Vector(Rotation) Dot Momentum) < -0.6) ) Damage *= 0.2; Super.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType); } function Bump (Actor Other) { if ( (GetAnimGroup(AnimSequence) == 'Shielded') && (Other == Enemy) ) { PlayAnim('ShldDown'); GotoState('MeleeAttack', 'ShieldDown'); return; } if ( AttackSuccess || (AnimSequence != 'Lunge') ) { Disable('Bump'); return; } else LungeDamageTarget(); if (!AttackSuccess && Pawn(Other) != None) //always add momentum Pawn(Other).AddVelocity((60000.0 * (Normal(Other.Location - Location)))/Other.Mass); } function PlayRangedAttack() { local float dist; if ( GetAnimGroup(AnimSequence) == 'Shielded' ) { TweenAnim('ShldFire', 0.05); FireWeapon(); return; } dist = VSize(Target.Location - Location + vect(0,0,1) * (CollisionHeight - Target.CollisionHeight)); if ( (FRand() < 0.2) && (dist < 150 + CollisionRadius + Target.CollisionRadius) && (Region.Zone.bWaterZone || !Target.Region.Zone.bWaterZone) ) { PlaySound(Lunge, SLOT_Interact); Velocity = 500 * (Target.Location - Location)/dist; //instant acceleration in that direction Velocity.Z += 1.5 * dist; if (Physics != PHYS_Swimming) SetPhysics(PHYS_Falling); Enable('Bump'); PlayAnim('Lunge'); } else { Disable('Bump'); FireWeapon(); } } function TryToDuck(vector duckDir, bool bReversed) { if ( FRand() < 0.5 ) return; bFire = 0; bAltFire = 0; if ( AnimSequence == 'ShldFire' ) { TweenAnim('HoldShield', 0.15); GotoState('RangedAttack', 'Shieldup'); return; } if ( GetAnimGroup(AnimSequence) == 'Shielded' ) { if (FRand() < 0.75) GotoState('RangedAttack', 'ShieldUp'); return; } Shield(); } function KeepAttacking() { if ( bFiringPaused ) return; if ( (FRand() > ReFireRate) || (Enemy == None) || (Enemy.Health <= 0) || !CanFireAtEnemy() ) { if ( GetAnimGroup(AnimSequence) == 'Shielded' ) { PlayAnim('ShldDown'); GotoState('RangedAttack', 'ShieldDown'); } else GotoState('Attacking'); } } function AnimEnd() { if ( (AnimSequence == 'Lunge') || (FRand() < 0.5) || ((bFire == 0) && (bAltFire == 0)) ) GotoState('RangedAttack', 'DoneFiring'); else TweenAnim('Firing', 0.5); } function EndState() { bFire = 0; bAltFire = 0; Super.EndState(); } ShieldDown: Disable('AnimEnd'); FinishAnim(); GotoState('Attacking'); Challenge: Disable('AnimEnd'); Acceleration = vect(0,0,0); //stop DesiredRotation = Rotator(Enemy.Location - Location); PlayChallenge(); FinishAnim(); TweenToFighter(0.1); Goto('FaceTarget'); ShieldUp: Disable('AnimEnd'); Acceleration = vect(0,0,0); //stop FinishAnim(); TweenAnim('HoldShield', 0.1); DesiredRotation = Rotator(Enemy.Location - Location); Sleep(duckTime + FRand()); if (NeedToTurn(Enemy.Location)) TurnToward(Enemy); Goto('CheckDist'); Begin: Acceleration = vect(0,0,0); //stop DesiredRotation = Rotator(Enemy.Location - Location); TweenToFighter(0.15); FaceTarget: Disable('AnimEnd'); if (NeedToTurn(Enemy.Location)) { PlayTurning(); TurnToward(Enemy); TweenToFighter(0.1); } FinishAnim(); CheckDist: if (VSize(Location - Enemy.Location) < 0.9 * MeleeRange + CollisionRadius + Enemy.CollisionRadius) GotoState('MeleeAttack', 'ReadyToAttack'); ReadyToAttack: if (!bHasRangedAttack) GotoState('Attacking'); DesiredRotation = Rotator(Enemy.Location - Location); PlayRangedAttack(); Enable('AnimEnd'); Firing: TurnToward(Enemy); Goto('Firing'); DoneFiring: Disable('AnimEnd'); KeepAttacking(); Goto('FaceTarget'); } J$hoa "hի>  {b hhmbh'wm*mm  K$P^D P ծ @  wP?,< b PPWbP'wW*WW  AL$_; : :$q! O$16  q!W E$S yD w*Nw* Xu u %$$ B?$$ N?  6- #a!Qfff > R 6R K6KR6RK R Ks RKS K s S L?a!Q > S La!Q > L>?t K #?t RK?%!k !la!l  ?a!l =? !m !ja!j  ? a!j =? k VQ$N$R+ .,k -k $q! p//============================================================================= // TeamSkaarjSniper. //============================================================================= class TeamSkaarjSniper extends TeamSkaarjTrooper; | Zt8|{zrq,% c!-'!!q!r-'q! y F$u >$`#-'4-v!9L>a!#J  aL>a!: :$q!5a: :$q!X!dU-D  ?,$q!tfff?B !l  @ !lb!d^o6&L>aaD#L>a! !l KlM@@T$  9#a'?(7::$2 U$+ S -' u1 5 M$w 5${6- w B >?aw 333?a!8B >y:a!B > v k$ N v!X k V$#S%Z HY$Z%_a&!RL>]w*w* Z$@>&a!Y?= f[$hF&\"a%!}a&!~=ZMh?a!"?=Za&!==  J E^ v  z\$_$' }B '$$B  | ^$a$^}(3G($$ D`$c$>)Q3($$Q Wb$e$)g3a)$$g zd$g$fU*@ 3)9$$16--(@  of$%*8P a ! v(xh$y$(}5Hv!aq!v!#P $a= !Mv!#aa&!}=P aW J a !c#P >v!IJ  a=a fff?q!%!g- q!P #u!a !Rv!H !M iRgcLMmahvM { +iHa%!} !d9| { L>M { iV| T Bz$}9A IG.}~b?! q! eL| Ss Q| a/!c$OL| a/!]| a/!`$O$ FZ\0vr a&!\ cj$I,9a%!} rIa!q!%!v _-U !Nv! eg-Uw.I*.I4u`jGI I @P$d B6q$@6'K ?$>!";$=]Skaarj Sniper[^rbp$y#-.Y'a%!}a&!dL=[ y #?JL>"y?,96- 6 -aq $? y6?y8::$o$u!a!NWv![ JXr$u$eH1|? $$H!da&!}>q!(!m ta%!}r@?q!(!m Y v$ct$H_t3y -D wD r*% Npa%!}a!q!(!vwq! }w$p4WH!N ?:% :%q!(!iUa&!R? Y x$3x5$$Y  y{$s$q2 @>JyrJ?J J 9w.J*r.J?.J .J 9>    I%G x 8GDB@~@% o!!!q!vq! D%XI L> $B u@%C%RcE96- a!z>> j\  A c#rq=J?)\=-'-'-'-(Z::$-'p::$-' 9F%23HD/6- ::$o$BB::$o$ G%H x;J[H H 6Cy-' rG A UL::$ u G J:u:$ :u:$|G  !H%,E53w*!!!iq! dJ%~P%?aT$#a $ K%o Zc16-a!.L>> ocoL?a!L>?offf?al$a!n >?aR$a!~>? R% ,8v!* *> L%r   N%EwJ   $O%$|} = P%Z  6'6-a&!GZ 4a&!iZ  T%mT \n/a0 mYXm-n?&X?&nm10 Q%J g \6-0!Pa Y!. -a&!.J u!aa !Z -a&!ZJ  AV%k_ Cb?k.4wk*k-(2q! S%E & nC6-@!. -a&!.E ll!Z -a&!ZE  X% |E U%D 06'6-a&!.D 4a&!D  ^%+ J u! W%_ 0_ imIb \a  #L?a<" @w\*\ \n\ 6\ 6\ 6a $@a!e?= Y% d>6-aF $a!. >baB $a!Ž > [%d>6-aF $a!. >baB $a!Zff > \%@ 5`@ @ L?  !Q6-a&!G>^a&!i> !J,w *!W!q! ]% 6'6-a&!.33>4a&!Z33> _%a%llB6-am$@a!G333?=ja$@a!c333?= b%`%n 66'6-a&!p n 4a&!u n  f%c%yMa!P = g%Xa!` = h%Q a&![> i%Ya&![> j%l%FHa&!Z> k%@a!v >=aj$ m%H"4':A ի<A zD  .GT#MLfff?L>.w.f*L33?}-yIa f 9?IX. t//============================================================================= // TeamSkaarjAssassin. //============================================================================= class TeamSkaarjAssassin extends TeamSkaarjWarrior; w^r%NPyk #L?\kY\?(kk\_իL?kիL?#?x aPN_ծk_(#@@@rx * PZ%ppp*a$@a!P333?= D&p%e B6u%V5qL!"]Skaarj Assassin[ ]` 8][USL,% Kw* z!!!q!w*q! x%  1**! !@&, o*!d!q! q%U `a#?L?aD 4y%#e,"6-a!P*a!a z%ymP# o{%%%^4vz6- -v>{.>a!. fff?84-v( l}% l-'-v' ~%3Y-( C&~ z~*#w*~bEEw*~b rw~*~~ xs e I Nk"q!c"k G&A&x u::$ ke a/!~.e C]?%#q!d!s bq!d!T uH&F/!a&!"= u& % F&@p!a\ $a!g?= | }w&^*6,l(6-= !U-e-]*a&!_L>abcr*q!6-L> !Ur*-e-e -] L?  ?Xr**jw*1  ?% b*r*a/!A*6-= !Ur*a&!_=aT !S-(-ea&!_=ar*q!Da!_ >a a#>a!S>?>?a` $aa!S>?a>a!S>? !j~~?a!R?>aa!W>333?=aq>a!W>333? !ka!{?a!_a&!_>a !* !H - =aa!* ?a !l !Ba Uk$jSfBlN$M&N&O&P&Kc/f=-'-(-'-(-(-( 9Q&2:!86-o$6o$q!c R& Fa!=> S&K+a!=> T&EPa!=> $U&$Ua!>L> V&HZ!a&!H 1$-e(v!1u!9 W&G _v+)!. -a&!.G BX&B9$b?u!1v!9 Y&I&e+)!. -a&!.I cZ&,$*!^!Bq! [&^&0k|a!L>L?> ]&apa&!a _& u% R6!L L? u=a!LPa!.L > a&} a!.L > b&5' 5?a!.>3ai$a!L> c& ag$a!F> d&f&l@ *a$@a!c333?= g&e&`6 a&!` }K&x&}o7k&h&Q& &6%a&!LL> l&Y a!333? m&o&F a&!LL> n&@" a!P?=ac $ p&@ A?':Oի<OD aB $ q&h /A?':Oի<OD aB $ r&l A?':l ի<l D aL$ s&U4kU.U33>aM$a!@L?WU333?ah$a!XL?iac $a!P Az&_ q!t yt&f'k-J(T  TbT33?sT96s6s6 6s6s6 V a^ _s'brV f^ e!g-J'-J M3%+-( r R 6H;w.R *.R - ::$ r R  ^ }&+ u! E//============================================================================= // TeamSkaarj. //============================================================================= class TeamSkaarj extends TeamScriptedPawn abstract; //----------------------------------------------------------------------------- // Skaarj variables. // Attack damage. var() byte LungeDamage, // Basic damage done by lunge. SpinDamage, // Basic damage done by spin. ClawDamage; // Basic damage done by each claw. var bool AttackSuccess; var() bool bButtonPusher; var() bool bFakeDeath; var(Sounds) sound hitsound3; var(Sounds) sound hitsound4; var(Sounds) sound syllable1; var(Sounds) sound syllable2; var(Sounds) sound syllable3; var(Sounds) sound syllable4; var(Sounds) sound syllable5; var(Sounds) sound syllable6; var(Sounds) sound spin; var(Sounds) sound claw; var(Sounds) sound slice; var(Sounds) sound lunge; var(Sounds) sound hairflip; var(Sounds) sound Die2; var(Sounds) sound Footstep; var(Sounds) sound Footstep2; var name phrase; var byte phrasesyllable; var float voicePitch; function PreBeginPlay() { Super.PreBeginPlay(); bCanSpeak = true; voicePitch = Default.voicePitch + 0.6 * Default.voicePitch * FRand(); if ( CombatStyle == Default.CombatStyle) CombatStyle = CombatStyle + 0.3 * FRand() - 0.15; if ( bFakeDeath ) { AnimSequence = 'Death2'; AnimFrame = 0.92; SimAnim.X = 9200; } if ( skill > 2 ) ProjectileSpeed *= 1.1; } function RunStep() { if (FRand() < 0.6) PlaySound(FootStep, SLOT_Interact,0.8,,900); else PlaySound(FootStep2, SLOT_Interact,0.8,,900); } function WalkStep() { if (FRand() < 0.6) PlaySound(FootStep, SLOT_Interact,0.2,,500); else PlaySound(FootStep2, SLOT_Interact,0.2,,500); } function ZoneChange(ZoneInfo newZone) { bCanSwim = newZone.bWaterZone; //only when it must if ( newZone.bWaterZone ) CombatStyle = 1.0; //always charges when in the water else if (Physics == PHYS_Swimming) CombatStyle = Default.CombatStyle; Super.ZoneChange(newZone); } /* PreSetMovement() */ function PreSetMovement() { MaxDesiredSpeed = 0.7 + 0.1 * skill; bCanJump = true; bCanWalk = true; bCanSwim = false; bCanFly = false; MinHitWall = -0.6; bCanOpenDoors = true; if ( Intelligence > BRAINS_Mammal ) bCanDoSpecial = true; bCanDuck = true; } function SetMovementPhysics() { if ( Region.Zone.bWaterZone ) SetPhysics(PHYS_Swimming); else if (Physics != PHYS_Walking) SetPhysics(PHYS_Walking); } //========================================================================================= // Speech function SpeechTimer() { //last syllable expired. Decide whether to keep the floor or quit if (FRand() < 0.3) { bIsSpeaking = false; if (TeamLeader != None) TeamLeader.bTeamSpeaking = false; } else Speak(); } function SpeakOrderTo(TeamScriptedPawn TeamMember) { phrase = ''; if ( !TeamMember.bCanSpeak || (FRand() < 0.5) ) Speak(); else { if (TeamSkaarjWarrior(TeamMember) != None) TeamSkaarjWarrior(TeamMember).phrase = ''; TeamMember.Speak(); } } function SpeakTo(TeamScriptedPawn Other) { if (Other.bIsSpeaking || ((TeamLeader != None) && TeamLeader.bTeamSpeaking) ) return; phrase = ''; Speak(); } function Speak() { local float decision, inflection, pitch; //if (phrase != '') // SpeakPhrase(); bIsSpeaking = true; if ( FRand() < 0.65) { inflection = 0.6 + 0.5 * FRand(); pitch = voicePitch + 0.4 * FRand(); } else { inflection = 1.3 + 0.5 * FRand(); pitch = voicePitch + 0.8 * FRand(); } decision = FRand(); if (TeamLeader != None) TeamLeader.bTeamSpeaking = true; if (decision < 0.167) PlaySound(Syllable1,SLOT_Talk,inflection,,, pitch); else if (decision < 0.333) PlaySound(Syllable2,SLOT_Talk,inflection,,, pitch); else if (decision < 0.5) PlaySound(Syllable3,SLOT_Talk,inflection,,, pitch); else if (decision < 0.667) PlaySound(Syllable4,SLOT_Talk,inflection,,, pitch); else if (decision < 0.833) PlaySound(Syllable5,SLOT_Talk,inflection,,, pitch); else PlaySound(Syllable6,SLOT_Talk,inflection,,, pitch); SpeechTime = 0.1 + 0.3 * FRand(); } function PlayAcquisitionSound() { if ( bCanSpeak && (TeamLeader != None) && !TeamLeader.bTeamSpeaking ) { phrase = 'Acquisition'; phrasesyllable = 0; Speak(); return; } Super.PlayAcquisitionSound(); } function PlayFearSound() { if ( bCanSpeak && (TeamLeader != None) && !TeamLeader.bTeamSpeaking ) { phrase = 'Fear'; phrasesyllable = 0; Speak(); return; } Super.PlayFearSound(); } function PlayRoamingSound() { if ( bCanSpeak && (TeamLeader != None) && !TeamLeader.bTeamSpeaking && (FRand() < 0.5) ) { phrase = ''; Speak(); return; } Super.PlayRoamingSound(); } function PlayThreateningSound() { if ( bCanSpeak && (FRand() < 0.6) && ((TeamLeader == None) || !TeamLeader.bTeamSpeaking) ) { phrase = 'Threaten'; phrasesyllable = 0; Speak(); return; } Super.PlayThreateningSound(); } //========================================================================================= //Azathoth deleted function eAttitude AttitudeToCreature(Pawn Other) function PushButtons() { local float decision, animspeed; SetAlertness(-0.7); animspeed = 0.4 + 0.6 * FRand(); decision = FRand(); if (decision < 0.2) LoopAnim('Breath2', animspeed, 1.0); else if (decision < 0.3) { SetAlertness(0.2); LoopAnim('Breath', animspeed, 1.0); } else if (decision < 0.4) LoopAnim('MButton1', animspeed); else if (decision < 0.5) LoopAnim('MButton2', animspeed); else if (decision < 0.6) LoopAnim('MButton3', animspeed); else if (decision < 0.7) LoopAnim('MButton4', animspeed); else if (decision < 0.76) LoopAnim('Button1', animspeed); else if (decision < 0.82) LoopAnim('Button2', animspeed); else if (decision < 0.88) LoopAnim('Button3', animspeed); else if (decision < 0.94) LoopAnim('Button4', animspeed); else LoopAnim('Button5', animspeed); return; } function PlayCock() { } function PlayWaiting() { local float decision; local float animspeed; if (Region.Zone.bWaterZone) { PlaySwimming(); return; } if ( bFakeDeath ) return; if ( bButtonPusher ) { PushButtons(); return; } animspeed = 0.3 + 0.6 * FRand(); //vary speed decision = FRand(); if (AnimSequence == 'Breath') { SetAlertness(0.0); if (decision < 0.15) { PlayAnim('gunfix', AnimSpeed, 0.7); if ( !bQuiet ) PlaySound(Roam, SLOT_Talk); } else if ( decision < 0.28 ) { if ( IsA('SkaarjWarrior') ) PlayAnim('Stretch', AnimSpeed); else PlayAnim('ShldTest', AnimSpeed); } else LoopAnim('Breath2', AnimSpeed); return; } else if ( AnimSequence == 'Breath2' ) { if (decision < 0.2) { SetAlertness(0.3); LoopAnim('Breath', 0.2 + 0.5 * FRand()); } else LoopAnim('Breath2', AnimSpeed); return; } else if ( AnimSequence == 'gunfix' ) { SetAlertness(-0.3); if (decision < 0.25) { PlayCock(); LoopAnim('guncheck', animspeed); } else if (decision < 0.37) PlayAnim('headup', animspeed); else LoopAnim('gunfix', animspeed); return; } else if ( AnimSequence == 'Looking' ) { if (decision < 0.7) { SetAlertness(-0.3); LoopAnim('gunfix', animspeed); } else if (decision < 0.85) { SetAlertness(0.0); PlayAnim('Breath2', AnimSpeed, 0.7); } else { SetAlertness(0.5); LoopAnim('Looking', AnimSpeed); } return; } else if ( AnimSequence == 'Headup' ) { if (decision < 0.1) { SetAlertness(0.0); PlayAnim('Breath2', AnimSpeed, 0.7); } else { SetAlertness(0.6); LoopAnim('Looking', AnimSpeed); if ( !bQuiet ) PlaySound(Roam, SLOT_Talk); } return; } else if ( AnimSequence == 'guncheck' ) { SetAlertness(-0.4); if (decision < 0.87) LoopAnim('gunfix', AnimSpeed); else { PlayCock(); LoopAnim('guncheck', AnimSpeed); } return; } else { SetAlertness(-0.3); PlayAnim('gunfix', animspeed, 0.6); return; } } function PlayWaitingAmbush() { if (Region.Zone.bWaterZone) { PlaySwimming(); return; } if ( bFakeDeath ) return; if ( bButtonPusher ) { PushButtons(); return; } if (FRand() < 0.8) LoopAnim('Breath2', 0.3 + 0.6 * FRand()); else LoopAnim('Breath', 0.3 + 0.6 * FRand()); } function PlayDive() { TweenToSwimming(0.2); } function TweenToWaiting(float tweentime) { if ( bFakeDeath ) return; if (Region.Zone.bWaterZone) { TweenToSwimming(tweentime); return; } TweenAnim('gunfix', tweentime); } function TweenToFighter(float tweentime) { bButtonPusher = false; bFakeDeath = false; if (Region.Zone.bWaterZone) { TweenToSwimming(tweentime); return; } if ( (AnimSequence == 'Death2') && (AnimFrame > 0.8) ) { SetFall(); GotoState('FallingState', 'RiseUp'); } else TweenAnim('Fighter', tweentime); } function TweenToRunning(float tweentime) { bButtonPusher = false; bFakeDeath = false; if (Region.Zone.bWaterZone) { TweenToSwimming(tweentime); return; } if ( (AnimSequence == 'Death2') && (AnimFrame > 0.8) ) { SetFall(); GotoState('FallingState', 'RiseUp'); } else if ( ((AnimSequence != 'Jog') && (AnimSequence != 'JogFire')) || !bAnimLoop ) TweenAnim('Jog', tweentime); } function TweenToWalking(float tweentime) { if (Region.Zone.bWaterZone) { TweenToSwimming(tweentime); return; } TweenAnim('Walk', tweentime); } function TweenToPatrolStop(float tweentime) { if ( bFakeDeath ) return; if (Region.Zone.bWaterZone) { TweenToSwimming(tweentime); return; } TweenAnim('Breath', tweentime); } function PlayWalking() { if (Region.Zone.bWaterZone) { PlaySwimming(); return; } LoopAnim('Walk', 0.88); } function TweenToSwimming(float tweentime) { if ( (AnimSequence != 'Swim') || !bAnimLoop ) TweenAnim('Swim', tweentime); } function PlaySwimming() { LoopAnim('Swim', -1.0/WaterSpeed,, 0.5); } function PlayTurning() { if (Region.Zone.bWaterZone) { PlaySwimming(); return; } if ( (AnimSequence == 'Death2') && (AnimFrame > 0.8) ) { SetFall(); GotoState('FallingState', 'RiseUp'); } else TweenAnim('Walk', 0.3); } function PlayBigDeath(name DamageType) { if ( FRand() < 0.35 ) PlayAnim('Death',0.7,0.1); else PlayAnim('Death2',0.7,0.1); PlaySound(Die2, SLOT_Talk, 4.5 * TransientSoundVolume); } function PlayHeadDeath(name DamageType) { local carcass carc; if ( ((DamageType == 'Decapitated') || ((Health < -20) && (FRand() < 0.5))) && !Level.Game.bVeryLowGore ) { carc = Spawn(class 'CreatureChunks',,, Location + CollisionHeight * vect(0,0,0.8), Rotation + rot(3000,0,16384) ); if (carc != None) { carc.Mesh = mesh'SkaarjHead'; carc.Initfor(self); carc.Velocity = Velocity + VSize(Velocity) * VRand(); carc.Velocity.Z = FMax(carc.Velocity.Z, Velocity.Z); } PlayAnim('Death5',0.7,0.1); if ( IsA('SkaarjWarrior') && (Velocity.Z < 120) ) { Velocity = GroundSpeed * vector(Rotation); Velocity.Z = 150; } } else if ( FRand() < 0.5 ) PlayAnim('Death',0.7,0.1); else PlayAnim('Death4',0.7,0.1); PlaySound(Die, SLOT_Talk, 4.5 * TransientSoundVolume); } function PlayLeftDeath(name DamageType) { if ( FRand() < 0.5 ) PlayAnim('Death',0.7,0.1); else PlayAnim('Death4',0.7,0.1); PlaySound(Die, SLOT_Talk, 4.5 * TransientSoundVolume); } function PlayRightDeath(name DamageType) { if ( FRand() < 0.3 ) PlayAnim('Death3',0.7,0.1); else PlayAnim('Death4',0.7,0.1); PlaySound(Die, SLOT_Talk, 4.5 * TransientSoundVolume); } function PlayGutDeath(name DamageType) { PlayAnim('Death3',0.7, 0.1); PlaySound(Die, SLOT_Talk, 4.5 * TransientSoundVolume); } function PlayTakeHitSound(int Damage, name damageType, int Mult) { local float decision; if ( Level.TimeSeconds - LastPainSound < 0.25 ) return; LastPainSound = Level.TimeSeconds; decision = FRand(); //FIXME - modify based on damage if (decision < 0.25) PlaySound(HitSound1, SLOT_Pain, 2.0 * Mult); else if (decision < 0.5) PlaySound(HitSound2, SLOT_Pain, 2.0 * Mult); else if (decision < 0.75) PlaySound(HitSound3, SLOT_Pain, 2.0 * Mult); else PlaySound(HitSound4, SLOT_Pain, 2.0 * Mult); } function TweenToFalling() { if ( FRand() < 0.5 ) TweenAnim('Jog', 0.2); else PlayAnim('Jump',0.7,0.1); } function PlayInAir() { if ( AnimSequence == 'Jog' ) PlayAnim('Jog', 0.4); else if ( AnimSequence == 'JogFire' ) PlayAnim('JogFire', 0.4); else TweenAnim('InAir',0.4); } function PlayOutOfWater() { TweenAnim('Landed', 0.8); } function PlayLanded(float impactVel) { if (impactVel > 1.7 * JumpZ) TweenAnim('Landed',0.1); else TweenAnim('Land', 0.1); } function PlayTakeHit(float tweentime, vector HitLoc, int damage) { if ( (Velocity.Z > 120) && (Health < 0.4 * Default.Health) && (FRand() < 0.33) ) PlayAnim('Death2',0.7); else if ( (AnimSequence != 'Spin') && (AnimSequence != 'Lunge') && (AnimSequence != 'Death2') ) Super.PlayTakeHit(tweentime, HitLoc, damage); } function SpinDamageTarget() { if (MeleeDamageTarget(SpinDamage, (SpinDamage * 1000 * Normal(Target.Location - Location))) ) PlaySound(slice, SLOT_Interact); } function ClawDamageTarget() { if ( MeleeDamageTarget(ClawDamage, (ClawDamage * 900 * Normal(Target.Location - Location))) ) PlaySound(slice, SLOT_Interact); } function PlayMeleeAttack() { local int hitdamage; local float TargetDist, decision; decision = FRand(); if (AnimSequence == 'Spin') decision += 0.2; else if (AnimSequence == 'Claw') decision -= 0.2; AttackSuccess = false; //log("Start Melee Attack"); if ( Region.Zone.bWaterZone || (decision < 0.5) ) { Acceleration = AccelRate * Normal(Target.Location - Location); PlayAnim('Spin'); PlaySound(Spin, SLOT_Interact); } else { PlayAnim('Claw'); PlaySound(Claw, SLOT_Interact); } } function PlayRangedAttack() { PlayAnim('Firing', 1.5); } state TakeHit { ignores seeplayer, hearnoise, bump, hitwall; function Landed(vector HitNormal) { local float landVol; if ( AnimSequence == 'Death2' ) { landVol = 0.75 + Velocity.Z * 0.004; LandVol = Mass * landVol * landVol * 0.01; PlaySound(sound'thump', SLOT_Interact, landVol); GotoState('FallingState', 'RiseUp'); } else Super.Landed(HitNormal); } function PlayTakeHit(float tweentime, vector HitLoc, int damage) { if ( AnimSequence != 'Death2' ) Global.PlayTakeHit(tweentime, HitLoc, damage); } function BeginState() { Super.BeginState(); If ( AnimSequence == 'Death2' ) GotoState('FallingState'); } } state FallingState { ignores Bump, Hitwall, HearNoise, WarnTarget; function Landed(vector HitNormal) { local float landVol; if ( AnimSequence == 'Death2' ) { landVol = 0.75 + Velocity.Z * 0.004; LandVol = Mass * landVol * landVol * 0.01; PlaySound(sound'Thump', SLOT_Interact, landVol); GotoState('FallingState', 'RiseUp'); } else if ( (AnimSequence == 'LeftDodge') || (AnimSequence == 'RightDodge') ) { landVol = Velocity.Z/JumpZ; landVol = 0.008 * Mass * landVol * landVol; if ( !FootRegion.Zone.bWaterZone ) PlaySound(Land, SLOT_Interact, FMin(20, landVol)); GotoState('FallingState', 'FinishDodge'); } else Super.Landed(HitNormal); } function PlayTakeHit(float tweentime, vector HitLoc, int damage) { if ( AnimSequence != 'Death2' ) Global.PlayTakeHit(tweentime, HitLoc, damage); } LongFall: if ( AnimSequence == 'Death2' ) { Sleep(1.5); Goto('RiseUp'); } if ( bCanFly ) { SetPhysics(PHYS_Flying); Goto('Done'); } Sleep(0.7); TweenToFighter(0.2); if ( bHasRangedAttack && (Enemy != None) ) { TurnToward(Enemy); FinishAnim(); if ( CanFireAtEnemy() ) { PlayRangedAttack(); FinishAnim(); } PlayChallenge(); FinishAnim(); } TweenToFalling(); if ( Velocity.Z > -150 ) //stuck { SetPhysics(PHYS_Falling); if ( Enemy != None ) Velocity = groundspeed * normal(Enemy.Location - Location); else Velocity = groundspeed * VRand(); Velocity.Z = FMax(JumpZ, 250); } Goto('LongFall'); RiseUp: FinishAnim(); bCanDuck = false; DesiredRotation = Rotation; Acceleration = vect(0,0,0); if ( !bFakeDeath ) Sleep(1.0 + 6 * FRand()); PlayAnim('GetUp', 0.7); FinishDodge: FinishAnim(); bCanDuck = true; Goto('Done'); } state Hunting { ignores EnemyNotVisible; function BeginState() { bCanSwim = true; Super.BeginState(); } function EndState() { if ( !Region.Zone.bWaterZone ) bCanSwim = false; Super.EndState(); } } state RangedAttack { ignores SeePlayer, HearNoise; function Bump (Actor Other) { if ( AttackSuccess || (AnimSequence != 'Lunge') ) { Disable('Bump'); return; } else LungeDamageTarget(); if (!AttackSuccess && Pawn(Other) != None) //always add momentum Pawn(Other).AddVelocity((60000.0 * (Normal(Other.Location - Location)))/Other.Mass); } function LungeDamageTarget() { If (MeleeDamageTarget(LungeDamage, (LungeDamage * 2000 * Normal(Target.Location - Location)))) { AttackSuccess = true; disable('Bump'); PlaySound(Slice, SLOT_Interact); } } function PlayRangedAttack() { local float dist; dist = VSize(Target.Location - Location + vect(0,0,1) * (CollisionHeight - Target.CollisionHeight)); if ( (FRand() < 0.7) && (dist < 180 + CollisionRadius + Target.CollisionRadius) && (Region.Zone.bWaterZone || !Target.Region.Zone.bWaterZone) ) { PlaySound(Lunge, SLOT_Interact); Velocity = 500 * (Target.Location - Location)/dist; //instant acceleration in that direction Velocity.Z += 1.5 * dist; if (Physics != PHYS_Swimming) SetPhysics(PHYS_Falling); Enable('Bump'); PlayAnim('Lunge'); } else { Disable('Bump'); PlayAnim('Firing', 1.5); } } } h 3w* 8hfebaK% z!!!q!w*q! & H DV**!v!->L> D'U Z: rKw.*.e.p/a0 U eoU 0 10 v&G'c,a>(a&!c333? +Xo$?,6*C?,6 6 KA']vU@]-H6H%a+Ho$q!SS::$o$ a N'B&}Y'}) r}*#w*}b<<w*}biw}*}} p* B'F'" o$6%a>( E'a!L333? W@'J'1c+)K a  bI' .aL>'b oH'V'%dCr*#}J?,  a?, >?,?,P $a q!P 4u!a?,  !v!H !M @C gMXdX:S8X\cb`,% Q!!%! i d"q!c"d S Z'M' }jUZd?PW 9-q (P W'i!  sL'HF-'Jr*)w.*.%q! fff?q!!Z ^R'1Q5 q! S'Voq!%!@ lT' [v!-' U'3a' -( Ae_ " : :$q!t!y O'hBaD|#/qB aa!z>?aa!z>aa!z>u!X lA\'_" R q!t Q j'aGok//============================================================================= // TeamQueen. //============================================================================= class TeamQueen extends TeamScriptedPawn; //Queen variables; var() int ClawDamage, StabDamage; var() name ScreamEvent; var byte row; var(Sounds) sound footstepSound; var(Sounds) sound ScreamSound; var(Sounds) sound stab; var(Sounds) sound shoot; var(Sounds) sound claw; var bool bJustScreamed; var bool bEndFootStep; var QueenShield Shield; var vector TelepDest; function PostBeginPlay() { Super.PostBeginPlay(); ProjectileSpeed = 1200 + 100 * Skill; GroundSpeed = GroundSpeed * (1 + 0.1 * Skill); } event bool EncroachingOn( actor Other ) { if ( (Other.Brush != None) || (Brush(Other) != None) ) return true; return false; } function TryToDuck(vector duckDir, bool bReversed) { if ( (Shield != None) || (AnimSequence == 'Shield') ) return; PlayAnim('Shield', 1.0, 0.1); bCrouching = true; GotoState('RangedAttack', 'Challenge'); } function SpawnShield() { Shield = Spawn(class'QueenShield',,,Location + 150 * Vector(Rotation)); Shield.SetBase(self); } //Azathoth deleted function eAttitude AttitudeToCreature(Pawn Other) function ThrowOther(Pawn Other) { local float dist, shake; local PlayerPawn aPlayer; local vector Momentum; if ( Other.mass > 500 ) return; aPlayer = PlayerPawn(Other); if (aPlayer == None) { if (Other.Physics != PHYS_Walking) return; dist = VSize(Location - Other.Location); if (dist > 500) return; } else { dist = VSize(Location - Other.Location); shake = FMax(500, 1500 - dist); if ( dist > 1500 ) return; aPlayer.ShakeView( FMax(0, 0.35 - dist/20000), shake, 0.015 * shake); if ( (Other.Physics != PHYS_Walking) || (dist > 1500) ) return; } Momentum = -0.5 * Other.Velocity + 100 * Normal(Other.Location - Location); Momentum.Z = 7000000.0/((0.5 * dist + 500) * Other.Mass); Other.AddVelocity(Momentum); } function FootStep() { bEndFootstep = false; PlaySound(FootstepSound, SLOT_Interact, 8); } function Scream() { local actor A; local pawn Thrown; if (ScreamEvent != '') foreach AllActors( class 'Actor', A, ScreamEvent ) A.Trigger( Self, Instigator ); PlaySound(ScreamSound, SLOT_Talk, 2 * TransientSoundVolume); PlaySound(ScreamSound, SLOT_None, 2 * TransientSoundVolume); PlaySound(ScreamSound, SLOT_None, 2 * TransientSoundVolume); PlaySound(ScreamSound, SLOT_None, 2 * TransientSoundVolume); PlayAnim('Scream'); bJustScreamed = true; } function PlayWaiting() { local float decision; local float animspeed; if (bEndFootStep) FootStep(); decision = FRand(); animspeed = 0.2 + 0.5 * FRand(); LoopAnim('Meditate', animspeed); } function PlayChallenge() { if (bEndFootStep) FootStep(); if ( IsAnimating() && (AnimSequence == 'Shield') ) return; Scream(); } function TweenToFighter(float tweentime) { bEndFootStep = ( ((AnimSequence == 'Walk') || (AnimSequence == 'Run')) && (AnimFrame > 0.1) ); TweenAnim('Fighter', tweentime); } function TweenToRunning(float tweentime) { if ( (AnimSequence != 'Run') || !bAnimLoop ) TweenAnim('Run', tweentime); } function TweenToWalking(float tweentime) { TweenAnim('Walk', tweentime); } function TweenToWaiting(float tweentime) { TweenAnim('Meditate', tweentime); } function TweenToPatrolStop(float tweentime) { TweenAnim('Meditate', tweentime); } function PlayRunning() { LoopAnim('Run', -1.0/GroundSpeed,, 0.8); } function PlayWalking() { LoopAnim('Walk', -1.0/GroundSpeed,, 0.8); } function PlayThreatening() { DesiredSpeed = 0.0; if ( FRand() < 0.75) PlayAnim('Meditate', 0.4 + 0.6 * FRand(), 0.3); else { TweenAnim('Fighter', 0.3); PlayThreateningSound(); } } function PlayTurning() { if (bEndFootStep) FootStep(); DesiredSpeed = 0.0; TweenAnim('Run', 0.4); } function PlayDying(name DamageType, vector HitLocation) { PlayAnim('OutCold', 0.7, 0.1); PlaySound(Die, SLOT_Talk); } function PlayTakeHit(float tweentime, vector HitLoc, int Damage) { TweenAnim('TakeHit', tweentime); } function SpawnShot() { local vector X,Y,Z, projStart; GetAxes(Rotation,X,Y,Z); if (row == 0) MakeNoise(1.0); projStart = Location + 1 * CollisionRadius * X + ( 0.7 - 0.2 * row) * CollisionHeight * Z + 0.2 * CollisionRadius * Y; spawn(RangedProjectile ,self,'',projStart,AdjustAim(ProjectileSpeed, projStart, 400 * (4 - row)/(3.5-skill), false, bWarnTarget)); projStart = Location + 1 * CollisionRadius * X + ( 0.7 - 0.2 * row) * CollisionHeight * Z - 0.2 * CollisionRadius * Y; spawn(RangedProjectile ,self,'',projStart,AdjustAim(ProjectileSpeed, projStart, 400 * (4 - row)/(3.5-skill), true, bWarnTarget)); row++; } function PlayVictoryDance() { if (bEndFootStep) FootStep(); DesiredSpeed = 0.0; PlayAnim('ThreeHit', 0.7, 0.15); //gib the enemy here! PlaySound(Threaten, SLOT_Talk); } function ClawDamageTarget() { if ( MeleeDamageTarget(ClawDamage, (50000.0 * (Normal(Target.Location - Location)))) ) PlaySound(Claw, SLOT_Interact); } function StabDamageTarget() { local vector X,Y,Z; GetAxes(Rotation,X,Y,Z); if ( MeleeDamageTarget(StabDamage, (15000.0 * ( Y + vect(0,0,1)))) ) PlaySound(Stab, SLOT_Interact); } function PlayMeleeAttack() { local float decision; if (bEndFootStep) FootStep(); decision = FRand(); if (decision < 0.4) { PlaySound(Stab, SLOT_Interact); PlayAnim('Stab'); } else if (decision < 0.7) { PlaySound(Claw, SLOT_Interact); PlayAnim('Claw'); } else { PlaySound(Claw, SLOT_Interact); PlayAnim('Gouge'); } } function TweenToFalling() { TweenAnim('Jump', 0.2); } function PlayInAir() { TweenAnim('Jump', 0.5); } function PlayLanded(float impactVel) { local Pawn Thrown; TweenAnim('Land', 0.1); //throw all nearby creatures, and play sound Thrown = Level.PawnList; While ( Thrown != None ) { ThrowOther(Thrown); Thrown = Thrown.nextPawn; } } function PlayRangedAttack() { if (bEndFootStep) FootStep(); if ( !bJustScreamed && (FRand() < 0.15) ) Scream(); else if ( (Shield != None) && (FRand() < 0.5) && (((Enemy.Location - Location) Dot (Shield.Location - Location)) > 0) ) Scream(); else { if ( Shield != None ) Shield.Destroy(); row = 0; bJustScreamed = false; PlayAnim('Shoot1'); PlaySound(Shoot, SLOT_Interact); } } state TacticalMove { ignores SeePlayer, HearNoise; function PickDestination(bool bNoCharge) { if ( FRand() < 0.26 ) GotoState('Teleporting'); else Super.PickDestination(bNoCharge); } } state Hunting { ignores EnemyNotVisible; function PickDestination() { GotoState('Teleporting'); } } State Teleporting { ignores TakeDamage, SeePlayer, EnemyNotVisible, HearNoise, KilledBy, Bump, HitWall, HeadZoneChange, FootZoneChange, ZoneChange, Falling, WarnTarget, Died; function Tick(float DeltaTime) { local int NewFatness; local rotator EnemyRot; if ( Style == STY_Translucent ) { ScaleGlow -= 3 * DeltaTime; if ( ScaleGlow < 0.3 ) { Spawn(class'QueenTeleportEffect',,, TelepDest); Spawn(class'QueenTeleportLight',,, TelepDest); EnemyRot = rotator(Enemy.Location - Location); EnemyRot.Pitch = 0; SetLocation(TelepDest); setRotation(EnemyRot); PlaySound(sound'Teleport1', SLOT_Interface); GotoState('Attacking'); } return; } else { NewFatness = fatness - 100 * DeltaTime; if ( NewFatness < 80 ) { bUnlit = true; ScaleGlow = 2.0; Style = STY_Translucent; } } fatness = Clamp(NewFatness, 0, 255); } function ChooseDestination() { local NavigationPoint N; local vector ViewPoint, HitLocation, HitNormal, Best; local actor HitActor; local float rating, newrating; N = Level.NavigationPointList; Best = Location; rating = 0; while ( N != None ) { if ( N.IsA('QueenDest') ) // rate it { newrating = 0; if ( Best == Location ) Best = N.Location; ViewPoint = N.Location + EyeHeight * vect(0,0,1); HitActor = Trace(HitLocation, HitNormal, Enemy.Location, ViewPoint, false); if ( HitActor == None ) newrating = 20000; newrating = newrating - VSize(N.Location - Enemy.Location) + 1000 * FRand() + 4 * VSize(N.Location - Location); if ( N.Location.Z > Enemy.Location.Z ) newrating += 1000; if ( newrating > rating ) { rating = newrating; Best = N.Location; } } N = N.nextNavigationPoint; } TelepDest = Best; } function BeginState() { Acceleration = Vect(0,0,0); ChooseDestination(); } function EndState() { bUnlit = false; Style = STY_Normal; ScaleGlow = 1.0; fatness = Default.fatness; } } ]'  ^'+ u! Va'kR [I-I:-| /D-$:`Dq!O!kY8RkD U ['maB6"`'Ew4w4w4tw4tw4w4tw4w4ttR+mR+mtԝXԝXtttt> YtttttR+mԝXt"2z "Ph W ` E ?$@`$>rm E|hgUKI$BM$Cq$Dj$HDp\$;E!"v} [$?pLVO ;$33s?]Queenu HO r$A7$ffB/$ffB<$zDP:Spab'_'x::$ kU a/!~.U C]?%#q!O!s bq!O!T !d','*!O!dq! J ^j X6A7-a {D<?,2j -a {,{::$?,j v>a  @a {D<?,dj {,P-'@$={%,  w8wsoml,%  o!!!q!w*q! dW~%#wT*aT$ 'aT$ ' ee'V%0%#ws*as$ 'as$ ' hf'w.~3w* >a$ 'a$ ' Y?a $ 'a $ ' |wt*at$ 'at$ ' gg':CpN r* 4?a$ 'a$ 'Las$ 'as$ ' h'Bq SDw.*"?!aJw.*6?pB.?"?!a "oL 4% FL #? L -l(!Ka!A??ao$ C':l#v! Dan$ CD>v!a!K> u!D ?a!c>D7DL?a!Y>Da!M> i'lRgl? v.lrv*\-l:l:$ hl h? *hl wCDhh? v2I33>h? Nwu<w*:l:$ Bl ?,d6BJ>h?^l-l6B@l uB AS//============================================================================= // TeamPupae. //============================================================================= class TeamPupae extends TeamScriptedPawn; //----------------------------------------------------------------------------- // Pupae variables. // Attack damage. var() byte BiteDamage; // Basic damage done by bite. var() byte LungeDamage; // Basic damage done by bite. var(Sounds) sound bite; var(Sounds) sound stab; var(Sounds) sound lunge; var(Sounds) sound chew; var(Sounds) sound tear; //----------------------------------------------------------------------------- // Pupae functions. function PostBeginPlay() { Super.PostBeginPlay(); MaxDesiredSpeed = 0.7 + 0.1 * skill; } function JumpOffPawn() { Super.JumpOffPawn(); PlayAnim('crawl', 1.0, 0.2); } function SetMovementPhysics() { SetPhysics(PHYS_Falling); } //Azathoth deleted function eAttitude AttitudeToCreature(Pawn Other) function PlayWaiting() { local float decision; local float animspeed; animspeed = 0.4 + 0.6 * FRand(); decision = FRand(); if ( !bool(NextAnim) || (decision < 0.4) ) //pick first waiting animation { if ( !bQuiet ) PlaySound(Chew, SLOT_Talk, 0.7,,800); NextAnim = 'Munch'; } else if (decision < 0.55) NextAnim = 'Pick'; else if (decision < 0.7) { if ( !bQuiet ) PlaySound(Stab, SLOT_Talk, 0.7,,800); NextAnim = 'Stab'; } else if (decision < 0.7) NextAnim = 'Bite'; else NextAnim = 'Tear'; LoopAnim(NextAnim, animspeed); } function PlayPatrolStop() { PlayWaiting(); } function PlayWaitingAmbush() { PlayWaiting(); } function PlayChallenge() { if ( FRand() < 0.3 ) PlayWaiting(); else PlayAnim('Fighter'); } function TweenToFighter(float tweentime) { TweenAnim('Fighter', tweentime); } function TweenToRunning(float tweentime) { if (AnimSequence != 'Crawl' || !bAnimLoop) TweenAnim('Crawl', tweentime); } function TweenToWalking(float tweentime) { TweenAnim('Crawl', tweentime); } function TweenToWaiting(float tweentime) { TweenAnim('Munch', tweentime); } function TweenToPatrolStop(float tweentime) { TweenAnim('Munch', tweentime); } function PlayRunning() { PlaySound(sound'scuttle1pp', SLOT_Interact); LoopAnim('Crawl', -4.0/GroundSpeed,,0.4); } function PlayWalking() { PlaySound(sound'scuttle1pp', SLOT_Interact); LoopAnim('Crawl', -4.0/GroundSpeed,,0.4); } function PlayThreatening() { PlayWaiting(); } function PlayTurning() { TweenAnim('Crawl', 0.3); } function PlayDying(name DamageType, vector HitLocation) { local carcass carc; PlaySound(Die, SLOT_Talk, 3.5 * TransientSoundVolume); if ( FRand() < 0.35 ) PlayAnim('Dead', 0.7, 0.1); else if ( FRand() < 0.5 ) { carc = Spawn(class 'CreatureChunks',,, Location + CollisionHeight * vect(0,0,0.8), Rotation + rot(3000,0,16384) ); if (carc != None) { carc.Mesh = mesh'PupaeHead'; carc.Initfor(self); carc.Velocity = Velocity + VSize(Velocity) * VRand(); carc.Velocity.Z = FMax(carc.Velocity.Z, Velocity.Z); } PlayAnim('Dead2', 0.7, 0.1); } else { carc = Spawn(class 'CreatureChunks',,, Location + CollisionHeight * vect(0,0,0.8), Rotation + rot(3000,0,16384) ); if (carc != None) { carc.Mesh = mesh'PupaeBody'; carc.Initfor(self); carc.Velocity = Velocity + VSize(Velocity) * VRand(); carc.Velocity.Z = FMax(carc.Velocity.Z, Velocity.Z); } PlayAnim('Dead3', 0.7, 0.1); } } function PlayTakeHit(float tweentime, vector HitLoc, int damage) { PlayAnim('TakeHit'); } function PlayVictoryDance() { PlayAnim('Stab', 1.0, 0.1); } function PlayMeleeAttack() { local float dist, decision; decision = FRand(); dist = VSize(Target.Location - Location); if (dist > CollisionRadius + Target.CollisionRadius + 45) decision = 0.0; if (Physics == PHYS_Falling) decision = 1.0; if (Target == None) decision = 1.0; if (decision < 0.15) { PlaySound(Lunge, SLOT_Interact); Enable('Bump'); PlayAnim('Lunge'); Velocity = 450 * Normal(Target.Location + Target.CollisionHeight * vect(0,0,0.75) - Location); if (dist > CollisionRadius + Target.CollisionRadius + 35) Velocity.Z += 0.7 * dist; SetPhysics(PHYS_Falling); } else { PlaySound(Stab, SLOT_Interact); PlayAnim('Stab'); MeleeRange = 50; MeleeDamageTarget(BiteDamage, vect(0,0,0)); MeleeRange = Default.MeleeRange; } } state MeleeAttack { ignores SeePlayer, HearNoise; singular function Bump(actor Other) { Disable('Bump'); if ( (Other == Target) && (AnimSequence == 'Lunge') ) if (MeleeDamageTarget(LungeDamage, vect(0,0,0))) { if (FRand() < 0.5) PlaySound(Tear, SLOT_Interact); else PlaySound(Bite, SLOT_Interact); } } } auto state StartUp { function SetMovementPhysics() { SetPhysics(PHYS_None); // don't fall at start } } state Waiting { TurnFromWall: if ( NearWall(70) ) { PlayTurning(); TurnTo(Focus); } Begin: TweenToWaiting(0.4); bReadyToAttack = false; if (Physics != PHYS_Falling) SetPhysics(PHYS_None); KeepWaiting: NextAnim = ''; } l'\bB6m'G<EԝXԝXԝXԝXԝX]H]H]H]H]H]H]H]H]H]HN ] WNl l X?$ AhgU K hI$CM$CE$Bj$Cpd\$;ET$̾!"ApL VO ;$?]PupaeH/$A<$BP:S o'~&OR aa !\Mw*aD !fS !ka=bZv!w.*- >w&>a6%baDmgw*5#>a&=a6aD^6, !\d !Tm !Te. .#L>a a. .!a&.>a.:..%.w.*a.a.aJ >au!!a.v!a !k#>au! V3Tfms\k[Sd&T@D p'E  r'k k'l A -l(-P(K~ !/a0 l ~ Jl R10LwL*RLLL_} aw $  v'o a//============================================================================= // TeamNaliPriest. //============================================================================= class TeamNaliPriest extends TeamNali; q'_ f }  t'c ] ;G !/a0 c G :c R10-l'XwX*RXXXWaw $A  y'm z s'x B6w'qz A[u'F dFPL>?--PA!I F{.>F=a $a!_ PF{.>a!JP>a!IP  L(J  e q!| x'"-PA  {'E"-PA  $|'k$|-PAkFkL>a!M?L>jk>a!J?L>k #?a!R?L>k@?ax$ax$a!m?L>a!p?L> @//============================================================================= // TeamNali. //============================================================================= class TeamNali extends TeamScriptedPawn; //==================================================================== // Nali Variables var() bool bNeverBow; var bool bCringing; var bool bGesture; var bool bFading; var bool bHasWandered; var(Sounds) sound syllable1; var(Sounds) sound syllable2; var(Sounds) sound syllable3; var(Sounds) sound syllable4; var(Sounds) sound syllable5; var(Sounds) sound syllable6; var(Sounds) sound urgefollow; var(Sounds) sound cringe; var(Sounds) sound cough; var(Sounds) sound sweat; var(Sounds) sound bowing; var(Sounds) sound backup; var(Sounds) sound pray; var(Sounds) sound breath; var() Weapon Tool; function PostBeginPlay() { Super.PostBeginPlay(); bCanSpeak = true; if ( Orders == 'Ambushing' ) AnimSequence = 'Levitate'; } function SpeakPrayer() { PlaySound(Pray); } function PlayFearSound() { if ( (Threaten != None) && (FRand() < 0.4) ) { PlaySound(Threaten, SLOT_Talk,, true); return; } if (Fear != None) PlaySound(Fear, SLOT_Talk,, true); } function bool AdjustHitLocation(out vector HitLocation, vector TraceDir) { local float adjZ, maxZ; TraceDir = Normal(TraceDir); HitLocation = HitLocation + 0.5 * CollisionRadius * TraceDir; if ( (GetAnimGroup(AnimSequence) == 'Ducking') && (AnimFrame > -0.03) ) { if ( AnimSequence == 'Bowing' ) maxZ = Location.Z - 0.2 * CollisionHeight; else maxZ = Location.Z + 0.25 * CollisionHeight; if ( HitLocation.Z > maxZ ) { if ( TraceDir.Z >= 0 ) return false; adjZ = (maxZ - HitLocation.Z)/TraceDir.Z; HitLocation.Z = maxZ; HitLocation.X = HitLocation.X + TraceDir.X * adjZ; HitLocation.Y = HitLocation.Y + TraceDir.Y * adjZ; if ( VSize(HitLocation - Location) > CollisionRadius ) return false; } } return true; } function Killed(pawn Killer, pawn Other, name damageType) { if ( (Nali(Other) != None) && Killer.bIsPlayer ) AttitudeToPlayer = ATTITUDE_Fear; Super.Killed(Killer, Other, damageType); } /* AttitudeWithFear() may fear other, unless near home */ function eAttitude AttitudeWithFear() { return ATTITUDE_Fear; } function damageAttitudeTo(pawn Other) { local eAttitude OldAttitude; if ( (Other == Self) || (Other == None) || (FlockPawn(Other) != None) ) return; if( Other.bIsPlayer ) //change attitude to player AttitudeToPlayer = ATTITUDE_Fear; else if ( TeamScriptedPawn(Other) == None ) Hated = Other; SetEnemy(Other); } function eAttitude AttitudeToCreature(Pawn Other) { if ( Other.IsA('TeamNali') ) return ATTITUDE_Friendly; else if ( Other.IsA('TeamScriptedPawn') && !Other.IsA('TeamCow')) //azathoth hack return ATTITUDE_Fear; else return ATTITUDE_Ignore; } function Step() { PlaySound(sound'WalkC', SLOT_Interact,0.5,,500); } function PlayWaiting() { local float decision; local float animspeed; if (Region.Zone.bWaterZone) { PlaySwimming(); return; } animspeed = 0.4 + 0.6 * FRand(); decision = FRand(); if ( AnimSequence == 'Breath' ) { if (!bQuiet && (decision < 0.12) ) { PlaySound(Cough,Slot_Talk,1.0,,800); LoopAnim('Cough', 0.85); return; } else if (decision < 0.24) { PlaySound(Sweat,Slot_Talk,0.3,,300); LoopAnim('Sweat', animspeed); return; } else if (!bQuiet && (decision < 0.34) ) { PlayAnim('Pray', animspeed, 0.3); return; } } else if ( AnimSequence == 'Pray' ) { if (decision < 0.3) PlayAnim('Breath', animspeed, 0.3); else { SpeakPrayer(); PlayAnim('Pray', animspeed); } return; } PlaySound(Breath,SLOT_Talk,0.5,true,500,animspeed * 1.5); LoopAnim('Breath', animspeed); } function PlayPatrolStop() { PlayWaiting(); } function PlayWaitingAmbush() { if (Region.Zone.bWaterZone) { PlaySwimming(); return; } LoopAnim('Levitate', 0.4 + 0.3 * FRand()); } function PlayDive() { TweenToSwimming(0.2); } function TweenToFighter(float tweentime) { if (Region.Zone.bWaterZone) TweenToSwimming(tweentime); else if (AnimSequence == 'Bowing') PlayAnim('GetUp', 0.4, 0.15); else TweenAnim('Fighter', tweentime); } function TweenToRunning(float tweentime) { if (Region.Zone.bWaterZone) TweenToSwimming(tweentime); else if ( ((AnimSequence != 'Run') && (AnimSequence != 'RunFire')) || !bAnimLoop) { if (AnimSequence == 'Bowing') PlayAnim('GetUp', 0.4, 0.15); else TweenAnim('Run', tweentime); } } function TweenToWalking(float tweentime) { if (Region.Zone.bWaterZone) TweenToSwimming(tweentime); else if (AnimSequence == 'Bowing') PlayAnim('GetUp', 0.4, 0.15); else if ( Weapon != None ) TweenAnim('WalkTool', tweentime); else TweenAnim('Walk', tweentime); } function TweenToWaiting(float tweentime) { if (Region.Zone.bWaterZone) TweenToSwimming(tweentime); else if (AnimSequence == 'Bowing') PlayAnim('GetUp', 0.4, 0.15); else TweenAnim('Breath', tweentime); } function TweenToPatrolStop(float tweentime) { if (Region.Zone.bWaterZone) TweenToSwimming(tweentime); else if (AnimSequence == 'Bowing') PlayAnim('GetUp', 0.4, 0.15); else if ( IsInState('Guarding')) TweenAnim('Pray', tweentime); else TweenAnim('Breath', tweentime); } function PlayRunning() { if (Region.Zone.bWaterZone) { PlaySwimming(); return; } LoopAnim('Run', -1.0/GroundSpeed,,0.4); } function PlayCombatMove() { if (Region.Zone.bWaterZone) { PlaySwimming(); return; } LoopAnim('Walk', -1.3/GroundSpeed,,0.4); } function PlayWalking() { if (Region.Zone.bWaterZone) { PlaySwimming(); return; } if ( Weapon != None ) LoopAnim('WalkTool', -3/GroundSpeed,,0.4); else LoopAnim('Walk', -3/GroundSpeed,,0.4); } function PlayThreatening() { if (Region.Zone.bWaterZone) { PlaySwimming(); return; } Acceleration = vect(0,0,0); if (AnimSequence == 'Backup') { PlaySound(Cringe, SLOT_Talk); LoopAnim('Cringe', 0.4 + 0.7 * FRand(), 0.4); } else if (AnimSequence == 'Cringe') { if ( FRand() < 0.6 ) PlaySound(Cringe, SLOT_Talk); LoopAnim('Cringe', 0.4 + 0.7 * FRand()); } else if (AnimSequence == 'Bowing') { PlaySound(Bowing, SLOT_Talk); LoopAnim('Bowing', 0.4 + 0.7 * FRand()); } else if (FRand() < 0.4) LoopAnim('Bowing', 0.4 + 0.7 * FRand(), 0.5); else PlayRetreating(); } function PlayRetreating() { if (Region.Zone.bWaterZone) { PlaySwimming(); return; } bAvoidLedges = true; PlaySound(Backup, SLOT_Talk); DesiredRotation = Rotator(Enemy.Location - Location); DesiredSpeed = WalkingSpeed; Acceleration = AccelRate * Normal(Location - Enemy.Location); LoopAnim('Backup'); } function PlayTurning() { TweenAnim('Walk', 0.3); } function PlayDying(name DamageType, vector HitLoc) { //first check for head hit if ( ((DamageType == 'Decapitated') || (HitLoc.Z - Location.Z > 0.5 * CollisionHeight)) && !Level.Game.bVeryLowGore ) { PlayHeadDeath(DamageType); return; } Super.PlayDying(DamageType, HitLoc); } function PlayHeadDeath(name DamageType) { local carcass carc; carc = Spawn(class 'CreatureChunks',,, Location + CollisionHeight * vect(0,0,0.8), Rotation + rot(3000,0,16384) ); if (carc != None) { carc.Mesh = mesh'NaliHead'; carc.Initfor(self); carc.Velocity = Velocity + VSize(Velocity) * VRand(); carc.Velocity.Z = FMax(carc.Velocity.Z, Velocity.Z); } PlaySound(sound'Death2n', SLOT_Talk, 4 * TransientSoundVolume); PlayAnim('Dead3',0.5, 0.1); } function PlayBigDeath(name DamageType) { PlaySound(Die, SLOT_Talk, 4 * TransientSoundVolume); PlayAnim('Dead4',0.7, 0.1); } function PlayLeftDeath(name DamageType) { PlaySound(sound'Death2n', SLOT_Talk, 4 * TransientSoundVolume); PlayAnim('Dead',0.7, 0.1); } function PlayRightDeath(name DamageType) { PlaySound(Die, SLOT_Talk, 4 * TransientSoundVolume); PlayAnim('Dead2',0.7, 0.1); } function PlayGutDeath(name DamageType) { PlaySound(Die, SLOT_Talk, 4 * TransientSoundVolume); if ( FRand() < 0.5 ) PlayAnim('Dead2',0.7, 0.1); else PlayAnim('Dead',0.7, 0.1); } function PlayLanded(float impactVel) { TweenAnim('Landed', 0.1); } function PlayVictoryDance() { PlaySound(Sweat, SLOT_Talk); PlayAnim('Sweat', 1.0, 0.1); } function PlayMeleeAttack() { if (Region.Zone.bWaterZone) { PlaySwimming(); return; } PlayThreatening(); } function PlayRangedAttack() { if (Region.Zone.bWaterZone) { PlaySwimming(); return; } PlayThreatening(); } function PlaySwimming() { Acceleration = WaterSpeed * VRand(); Velocity = Acceleration; SetPhysics(PHYS_Falling); LoopAnim('Drowning', 0.5 + 0.9 * FRand()); } function TweenToSwimming(float TweenTime) { TweenAnim('Drowning', TweenTime); } state Retreating { ignores HearNoise, Bump, AnimEnd; function EnemyNotVisible() { bCringing = False; Disable('EnemyNotVisible'); Enable('SeePlayer'); } function SeePlayer(actor SeenPlayer) { MakeNoise(1.0); Enable('EnemyNotVisible'); Disable('SeePlayer'); } function SetFall() { NextState = 'Retreating'; NextLabel = 'Moving'; NextAnim = AnimSequence; GotoState('FallingState'); } function ReachedHome() { if (LineOfSightTo(Enemy)) { if (Homebase(home) != None) { MoveTarget = None; health = Min(default.health, health+10); MakeNoise(1.0); } else ChangeDestination(); } else { health = Min(default.health, health+5); GotoState('FadeOut'); } } function Bump(actor Other) { local vector VelDir, OtherDir; //log(Other.class$" bumped "$class); if (Pawn(Other) != None) { if ( (Enemy == Other) || SetEnemy(Pawn(Other)) ) { bReadyToAttack = True; //can melee right away LastSeenPos = Enemy.Location; GotoState('Attacking'); return; } } setTimer(1.0, false); VelDir = Normal(Velocity); VelDir.Z = 0; OtherDir = Normal(Other.Location - Location); OtherDir.Z = 0; if ( (VelDir Dot OtherDir) > 0.9 ) { VelDir.X = Velocity.Y; VelDir.Y = -1 * Velocity.X; VelDir.Z = Velocity.Z; Velocity = VelDir; } Disable('Bump'); } function PickDestination() { //log("find retreat destination"); if (HomeBase(Home) == None) Home = FindRandomDest(); //find temporary home } function ChangeDestination() { local actor oldTarget; local Actor path; oldTarget = Home; PickDestination(); if ( (Home == oldTarget) || (Home == None) ) MoveTarget = None; else { path = FindPathToward(Home); if (path == None) MoveTarget = None; else { MoveTarget = path; Destination = path.Location; } } } Function BeginState() { bReadyToAttack = true; Disable('SeePlayer'); } function EndState() { bAvoidLedges = false; GroundSpeed = Default.GroundSpeed; Super.EndState(); } Begin: if (Region.Zone.bWaterZone) { TweenToSwimming(0.12); Goto('Drowning'); } bCringing = !bNeverBow; Target = None; TweenAnim('Backup',0.2); FinishAnim(); RunAway: WaitForLanding(); if ( Enemy == None ) GotoState('Attacking'); if (Region.Zone.bWaterZone) { TweenToSwimming(0.2); Goto('Drowning'); } if (Home == None) PickDestination(); bCringing = (bCringing && !bNeverBow && (FRand() < 0.8) && (VSize(Location - Enemy.Location) < 600) ); if (Home == None) MoveTarget = None; else { PickNextSpot(); if ( (MoveTarget != None) && (((MoveTarget.Location - Location) Dot (Enemy.Location - Location)) > 0) && LineOfSightTo(Enemy) ) { MoveTarget = None; if ( (Home == None) || !Home.IsA('HomeBase') ) Home = None; } } Moving: if (Region.Zone.bWaterZone) { TweenToSwimming(0.12); Goto('Drowning'); } If (MoveTarget == None) { GroundSpeed = Default.GroundSpeed; TweenAnim('Backup', 0.1); FinishAnim(); PlayRetreating(); Goto('Cringe'); } bAvoidLedges = false; if (bCringing) { TweenAnim('Backup', 0.1); FinishAnim(); if ( Enemy == None ) GotoState('Attacking'); GroundSpeed = GroundSpeed * WalkingSpeed; LoopAnim('Backup', -1.0/GroundSpeed,,0.4); Target = MoveTarget; StrafeFacing(MoveTarget.Location, Enemy); MoveTarget = Target; Cringe: FinishAnim(); Acceleration = vect(0,0,0); if (FRand() < 0.4) { PlayAnim('Cringe', 0.4 + 0.6 * FRand(), 0.4); if ( FRand() < 0.6 ) PlaySound(Cringe, SLOT_Talk); KeepCringeing: FinishAnim(); PlayAnim('Cringe', 0.4 + 0.6 * FRand()); FinishAnim(); If (FRand() < 0.15) { PlayAnim('Cringe', 0.4 + 0.6 * FRand()); Goto('KeepCringeing'); } } else if (FRand() < 0.6) { PlayAnim('GetDown', 0.5, 0.3); KeepBowing: FinishAnim(); PlayAnim('Bowing', 0.3 + 0.7 * FRand(), 0.1); FinishAnim(); If (FRand() < 0.25) { PlayAnim('Bowing', 0.3 + 0.7 * FRand()); Goto('KeepBowing'); } PlayAnim('GetUp', 0.5); } FinishAnim(); if ( AnimSequence != 'Backup' ) { TweenAnim('Backup',0.3); FinishAnim(); } } else { GroundSpeed = Default.GroundSpeed; if ( ((AnimSequence != 'Run') && (AnimSequence != 'RunFire')) || !bAnimLoop ) { TweenToRunning(0.1); FinishAnim(); LoopAnim('Run', -1.0/GroundSpeed,,0.5); } MoveToward(MoveTarget); } Goto('RunAway'); TakeHit: Goto('Moving'); Drowning: FinishAnim(); PlaySwimming(); } state TriggerAlarm { ignores HearNoise, SeePlayer; function Bump(actor Other) { local vector VelDir, OtherDir; local float speed; if ( (Pawn(Other) != None) && Pawn(Other).bIsPlayer && (AttitudeToPlayer == ATTITUDE_Friendly) ) return; Super.Bump(Other); } } state AlarmPaused { ignores HearNoise, Bump; function PlayWaiting() { if ( !bGesture || (FRand() < 0.3) ) //pick first waiting animation { bGesture = true; PlaySound(UrgeFollow, SLOT_Talk); NextAnim = 'Follow'; LoopAnim(NextAnim, 0.4 + 0.6 * FRand()); } else Global.PlayWaiting(); } function PlayWaitAround() { if ( (AnimSequence == 'Bowing') || (AnimSequence == 'GetDown') ) PlayAnim('Bowing', 0.75, 0.1); else PlayAnim('GetDown', 0.7, 0.25); } function BeginState() { bGesture = false; Super.BeginState(); } } state Guarding { function PlayPatrolStop() { local float decision; local float animspeed; animspeed = 0.2 + 0.6 * FRand(); decision = FRand(); if ( AnimSequence == 'Breath' ) { if (!bQuiet && (decision < 0.12) ) { PlaySound(Cough,Slot_Talk,1.0,,800); LoopAnim('Cough', 0.85); return; } else if (decision < 0.24) { PlaySound(Sweat,Slot_Talk,0.3,,300); LoopAnim('Sweat', animspeed); return; } else if (!bQuiet && (decision < 0.65) ) { PlayAnim('Pray', animspeed, 0.3); return; } else if ( decision < 0.8 ) { PlayAnim('GetDown', 0.4, 0.1); return; } } else if ( AnimSequence == 'Pray' ) { if (decision < 0.2) PlayAnim('Breath', animspeed, 0.3); else if ( decision < 0.35 ) PlayAnim('GetDown', 0.4, 0.1); else { SpeakPrayer(); PlayAnim('Pray', animspeed); } return; } else if ( AnimSequence == 'GetDown') { PlaySound(Bowing, SLOT_Talk); LoopAnim('Bowing', animspeed, 0.1); return; } else if ( AnimSequence == 'GetUp' ) PlayAnim('Pray', animspeed, 0.1); else if ( AnimSequence == 'Bowing' ) { if ( decision < 0.15 ) PlayAnim('GetUp', 0.4); else { PlaySound(Bowing, SLOT_Talk); LoopAnim('Bowing', animspeed); } return; } PlaySound(Breath,SLOT_Talk,0.5,true,500,animspeed * 1.5); LoopAnim('Breath', animspeed); } } state FadeOut { ignores HitWall, EnemyNotVisible, HearNoise, SeePlayer; function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType); if ( health <= 0 ) return; if (NextState == 'TakeHit') { NextState = 'Attacking'; NextLabel = 'Begin'; GotoState('TakeHit'); } else if ( Enemy != None ) GotoState('Attacking'); } function Tick(float DeltaTime) { local int NewFatness; if ( !bFading ) { NewFatness = fatness + 50 * DeltaTime; bFading = ( NewFatness > 160 ); } else if ( Style == STY_Translucent ) { ScaleGlow -= 3 * DeltaTime; if ( ScaleGlow < 0.3 ) { PlaySound(sound'Teleport1',, 2.0); Destroy(); } return; } else { NewFatness = fatness - 100 * DeltaTime; if ( NewFatness < 80 ) { bUnlit = true; ScaleGlow = 2.0; Style = STY_Translucent; } } fatness = Clamp(NewFatness, 0, 255); } function BeginState() { bFading = false; Disable('Tick'); } function EndState() { bUnlit = false; Style = STY_Normal; ScaleGlow = 1.0; fatness = Default.fatness; } Begin: Acceleration = Vect(0,0,0); if ( NearWall(100) ) { PlayTurning(); TurnTo(Focus); } PlayAnim('Levitate', 0.3, 1.0); FinishAnim(); PlayAnim('Levitate', 0.3); FinishAnim(); LoopAnim('Levitate', 0.3); Enable('Tick'); } state Roaming { ignores EnemyNotVisible; function PickDestination() { if ( bHasWandered && (FRand() < 0.1) ) GotoState('FadeOut'); else Super.PickDestination(); bHasWandered = true; } } state Wandering { ignores EnemyNotVisible; function PickDestination() { if ( bHasWandered && (FRand() < 0.1) ) GotoState('FadeOut'); else Super.PickDestination(); bHasWandered = true; } } }'Sl3-P!C =a&!RS pB(Fk a&!ML> '\  +)!C -a&!C\ A(Y& a&!CY bQ a&!cL> C(Z0a&!IZ  Ad8Alyjt,% w*X !~:X:$!^!!!q!q! E(WGa&!IW zEK  G( a!C L? I(.a!C L?,>w J(M5'MN>?BM?a!IN>zM333?a{$a{$a!MN>:Mfff?a!JN>a&!R> Jz'I R(3|T?%-' K( >J*-PAa!p > N(P(lGxn,n>a!H333?>bPn333?a!Y333?>ba!n333?>a$a$ Q(nT( r6*L>-(v!!-( O(l6VVUk'k>a&!HlSFk333?a&!YlSa&!nl aW(xbmK+?,xx  V(kb h S(>nի>o]zD>('w<*<o$ >nի>o]zD>('w<*<o$>n?,(zի>o]zD>''w<*<o$3L>>n?,(zի>o]zD>('3w<*<o$ ai//============================================================================= // TeamKrall. //============================================================================= class TeamKrall extends TeamScriptedPawn; //FIXME - also have look1a (for look anim) //FIXME- How to use strike3kr? var() byte StrikeDamage, ThrowDamage, PoundDamage; var bool AttackSuccess; var() bool bSpearToss; var() bool bDicePlayer; var() bool bSleeping; var bool bHasDice; var bool bHeldDice; var(Sounds) sound strike1; var(Sounds) sound strike2; var(Sounds) sound twirl; var(Sounds) sound syllable1; var(Sounds) sound syllable2; var(Sounds) sound syllable3; var(Sounds) sound syllable4; var(Sounds) sound syllable5; var(Sounds) sound syllable6; var(Sounds) sound die2; var(Sounds) sound spearHit; var(Sounds) sound spearThrow; var name phrase; var byte phrasesyllable; var float voicePitch; var Dice Toy1; var Dice Toy2; var() float MinDuckTime; var float LastDuckTime; function PreBeginPlay() { bCanSpeak = true; voicePitch = 0.25 + 0.5 * FRand(); if ( CombatStyle == Default.CombatStyle) CombatStyle = CombatStyle + 0.4 * FRand() - 0.2; bCanDuck = (FRand() < 0.5); Super.PreBeginPlay(); if ( bDicePlayer ) PeripheralVision = 1.0; if ( Skill == 0 ) ProjectileSpeed *= 0.85; else if ( Skill > 2 ) { bCanStrafe = true; ProjectileSpeed *= 1.1; } if ( !IsA('TeamKrallElite') ) bLeadTarget = false; } function Carcass SpawnCarcass() { local carcass carc; carc = Spawn(CarcassType); carc.Initfor(self); carc.bReducedHeight = true; carc.PrePivot = PrePivot; return carc; } function PlayTakeHit(float tweentime, vector HitLoc, int damage) { local carcass carc; local TeamLeglessKrall rep; local pawn OtherPawn; local Actor A; if ( (Health > 30) || (damage < 24) || (HitLoc.Z > Location.Z) || (FRand() < 0.6) || Level.Game.bVeryLowGore ) { Super.PlayTakeHit(tweentime, HitLoc, damage); return; } carc = Spawn(class 'CreatureChunks',,, Location - CollisionHeight * vect(0,0,0.5), Rotation + rot(3000,0,16384) ); if (carc != None) { carc.Mesh = mesh'KrallFoot'; carc.Initfor(self); carc.Velocity = Velocity + VSize(Velocity) * VRand(); carc.Velocity.Z = FMax(carc.Velocity.Z, Velocity.Z); } carc = Spawn(class 'CreatureChunks',,, Location - CollisionHeight * vect(0,0,0.5), Rotation + rot(3000,0,16384) ); if (carc != None) { carc.Mesh = mesh'KrallFoot'; carc.Initfor(self); carc.Velocity = Velocity + VSize(Velocity) * VRand(); carc.Velocity.Z = FMax(carc.Velocity.Z, Velocity.Z); } SetCollision(false, false, false); OtherPawn = Level.PawnList; while ( OtherPawn != None ) { OtherPawn.Killed(enemy, self, ''); OtherPawn = OtherPawn.nextPawn; } if ( CarriedDecoration != None ) DropDecoration(); if ( Event != '' ) foreach AllActors( class 'Actor', A, Event ) A.Trigger( self, enemy ); Level.Game.DiscardInventory(self); Velocity.Z *= 1.3; rep = Spawn(class'TeamLeglessKrall'); rep.InitFor(self); rep.Team = Team; //azathoth hack destroy(); } function ZoneChange(ZoneInfo newZone) { bCanSwim = newZone.bWaterZone; //only when it must if ( newZone.bWaterZone ) CombatStyle = 1.0; //always charges when in the water else if (Physics == PHYS_Swimming) CombatStyle = Default.CombatStyle; Super.ZoneChange(newZone); } function SetMovementPhysics() { if ( Region.Zone.bWaterZone ) SetPhysics(PHYS_Swimming); else if (Physics != PHYS_Walking) SetPhysics(PHYS_Walking); } function TryToDuck(vector duckDir, bool bReversed) { local vector HitLocation, HitNormal, Extent; local actor HitActor; //log("duck"); if ( Level.TimeSeconds - LastDuckTime < (0.25 + 0.5 * FRand()) * MinDuckTime ) return; duckDir.Z = 0; if ( (Skill == 0) && (FRand() < 0.5) ) DuckDir *= -1; Extent.X = CollisionRadius; Extent.Y = CollisionRadius; Extent.Z = CollisionHeight; HitActor = Trace(HitLocation, HitNormal, Location + 128 * duckDir, Location, false, Extent); if (HitActor != None) { duckDir *= -1; HitActor = Trace(HitLocation, HitNormal, Location + 128 * duckDir, Location, false, Extent); } if (HitActor != None) return; HitActor = Trace(HitLocation, HitNormal, Location + 128 * duckDir - MaxStepHeight * vect(0,0,1), Location + 128 * duckDir, false, Extent); if (HitActor == None) return; //log("good duck"); LastDuckTime = Level.TimeSeconds; SetFall(); TweenAnim('Jump', 0.3); Velocity = duckDir * 1.5 * GroundSpeed; Velocity.Z = 200; SetPhysics(PHYS_Falling); GotoState('FallingState','Ducking'); } //========================================================================================= // Speech function SpeechTimer() { //last syllable expired. Decide whether to keep the floor or quit if (FRand() < 0.3) { bIsSpeaking = false; if (TeamLeader != None) TeamLeader.bTeamSpeaking = false; } else Speak(); } function SpeakOrderTo(TeamScriptedPawn TeamMember) { phrase = ''; if ( !TeamMember.bCanSpeak || (FRand() < 0.5) ) Speak(); else { if (TeamSkaarjWarrior(TeamMember) != None) TeamSkaarjWarrior(TeamMember).phrase = ''; TeamMember.Speak(); } } function SpeakTo(TeamScriptedPawn Other) { if (Other.bIsSpeaking || ((TeamLeader != None) && TeamLeader.bTeamSpeaking) ) return; phrase = ''; Speak(); } function Speak() { local float decision; //if (phrase != '') // SpeakPhrase(); bIsSpeaking = true; decision = FRand(); if (TeamLeader != None) TeamLeader.bTeamSpeaking = true; if (decision < 0.167) PlaySound(Syllable1,SLOT_Talk,0.3 + FRand(),,, FRand() + voicePitch); else if (decision < 0.333) PlaySound(Syllable2,SLOT_Talk,0.3 + FRand(),,, FRand() + voicePitch); else if (decision < 0.5) PlaySound(Syllable3,SLOT_Talk,0.3 + FRand(),,, FRand() + voicePitch); else if (decision < 0.667) PlaySound(Syllable4,SLOT_Talk,0.3 + FRand(),,, FRand() + voicePitch); else if (decision < 0.833) PlaySound(Syllable5,SLOT_Talk,0.3 + FRand(),,, FRand() + voicePitch); else PlaySound(Syllable6,SLOT_Talk,0.3 + FRand(),,, FRand() + voicePitch); SpeechTime = 0.1 + 0.3 * FRand(); } function PlayAcquisitionSound() { if ( bCanSpeak && (TeamLeader != None) && !TeamLeader.bTeamSpeaking ) { phrase = 'Acquisition'; phrasesyllable = 0; Speak(); return; } Super.PlayAcquisitionSound(); } function PlayFearSound() { if ( bCanSpeak && (TeamLeader != None) && !TeamLeader.bTeamSpeaking ) { phrase = 'Fear'; phrasesyllable = 0; Speak(); return; } Super.PlayFearSound(); } function PlayRoamingSound() { if ( bCanSpeak && (TeamLeader != None) && !TeamLeader.bTeamSpeaking && (FRand() < 0.5) ) { phrase = ''; Speak(); return; } Super.PlayRoamingSound(); } function PlayThreateningSound() { if ( bCanSpeak && (FRand() < 0.6) && ((TeamLeader == None) || !TeamLeader.bTeamSpeaking) ) { phrase = 'Threaten'; phrasesyllable = 0; Speak(); return; } Super.PlayThreateningSound(); } //========================================================================================= //Azathoth deleted function eAttitude AttitudeToCreature(Pawn Other) function ThrowDice() { local Dice d1, d2; local vector X,Y,Z, ThrowLoc; d1 = TeamKrall(TeamLeader).Toy1; d2 = TeamKrall(TeamLeader).Toy2; GetAxes(Rotation, X,Y,Z); ThrowLoc = Location + X * CollisionRadius + Y * CollisionRadius - Z * 0.6 * CollisionHeight; d1.SetLocation(ThrowLoc); d2.SetLocation(ThrowLoc + vect(2,2,2)); d1.instigator = self; d1.Throw(Y); d2.instigator = self; d2.Throw(Y); } function GrabDice() { if ( TeamKrall(TeamLeader).Toy1 == None ) TeamKrall(TeamLeader).Toy1 = Spawn(class'Dice'); if ( TeamKrall(TeamLeader).Toy2 == None ) TeamKrall(TeamLeader).Toy2 = Spawn(class'Dice'); TeamKrall(TeamLeader).Toy1.bHidden = True; TeamKrall(TeamLeader).Toy2.bHidden = True; } function PlayWaiting() { local float decision; local float animspeed; if (Region.Zone.bWaterZone) { PlaySwimming(); return; } if ( bSleeping ) { animspeed = 0.5 + 0.5 * FRand(); SetAlertness(-1.0); LoopAnim('Sleep1', AnimSpeed ); PlaySound(sound'Snore1K',SLOT_Talk); return; } decision = FRand(); if ( bDicePlayer ) { animspeed = 0.4 + 0.6 * FRand(); SetAlertness(-1.0); if ( TeamLeader == None ) { if ( decision < 0.9 ) LoopAnim('Breath2', animspeed, 0.5); else LoopAnim('HeadRub', animspeed); return; } if ( !TeamLeader.bTeamSpeaking ) { phrase = ''; Speak(); } if ( bHasDice ) { if ( AnimSequence == 'Toss' ) { bHasDice = false; TeamKrall(TeamLeader).bHeldDice = false; } else if ( FRand() < 0.8 ) { PlayAnim('Toss', animspeed); return; } } if ( TeamKrall(TeamLeader).bHeldDice || ( FRand() < 0.65) ) { if ( decision < 0.8 ) LoopAnim('Breath2', animspeed, 0.5); else if ( decision < 0.9 ) LoopAnim('Laugh', animspeed); else LoopAnim('HeadRub', animspeed); return; } TeamKrall(TeamLeader).bHeldDice = True; bHasDice = True; PlayAnim('Grasp', animspeed); return; } if (AnimSequence == 'Look') { SetAlertness(0.0); if (!bQuiet && decision < 0.3) { LoopAnim('Twirl', 0.3 + 0.6 * FRand()); PlaySound(Twirl,SLOT_Interact,0.5,,500); } else LoopAnim('Breath', 0.2 + 0.7 * FRand()); return; } else if (AnimSequence == 'Twirl') { SetAlertness(0.0); if (decision < 0.5) { PlaySound(Twirl,SLOT_Interact,0.5,,500); LoopAnim('Twirl', 0.3 + 0.6 * FRand()); } else LoopAnim( 'Breath', 0.2 + 0.7 * FRand()); return; } if (decision < 0.2) { SetAlertness(0.5); LoopAnim('Look', 0.2 + 0.7 * FRand()); } else { SetAlertness(0.0); LoopAnim('Breath', 0.2 + 0.7 * FRand()); } } function PlayPatrolStop() { if (Region.Zone.bWaterZone) { PlaySwimming(); return; } if ( (AnimSequence == 'Breath') && (FRand() < 0.4) ) { SetAlertness(0.5); LoopAnim('Look', 0.2 + 0.7 * FRand()); return; } else if ( !bQuiet && (AnimSequence == 'Look') && (FRand() < 0.3) ) { SetAlertness(0.0); PlaySound(Twirl,SLOT_Interact,0.5,,500); LoopAnim('Twirl', 0.3 + 0.6 * FRand()); return; } else if ( (AnimSequence == 'Twirl') && (FRand() < 0.5) ) { SetAlertness(0.0); PlaySound(Twirl,SLOT_Interact,0.5,,500); LoopAnim('Twirl', 0.3 + 0.6 * FRand()); return; } SetAlertness(0.0); LoopAnim('Breath', 0.2 + 0.7 * FRand()); } function PlayWaitingAmbush() { if (Region.Zone.bWaterZone) { PlaySwimming(); return; } if (FRand() < 0.4) LoopAnim('Look', 0.3); else LoopAnim('Breath', 0.3 + 0.5 * FRand()); } function PlayChallenge() { if (Region.Zone.bWaterZone) { PlaySwimming(); return; } if ( TryToCrouch() ) { TweenAnim('Crouch', 0.12); return; } PlayThreateningSound(); PlayAnim('T3', 0.7, 0.15); } function PlayDive() { TweenToSwimming(0.2); } function TweenToFighter(float tweentime) { if ( bDicePlayer ) { PeripheralVision = Default.PeripheralVision; bDicePlayer = false; } bSleeping = false; if (Region.Zone.bWaterZone) { TweenToSwimming(tweentime); return; } TweenAnim('Fighter', tweentime); } function TweenToRunning(float tweentime) { if ( bDicePlayer ) { PeripheralVision = Default.PeripheralVision; bDicePlayer = false; } bSleeping = false; if (Region.Zone.bWaterZone) { TweenToSwimming(tweentime); return; } if ( (AnimSequence == 'Shoot2') && IsAnimating() ) return; if ( (AnimSequence != 'Run') || !bAnimLoop ) TweenAnim('Run', tweentime); } function TweenToWalking(float tweentime) { if (Region.Zone.bWaterZone) { TweenToSwimming(tweentime); return; } TweenAnim('Walk', tweentime); } function TweenToWaiting(float tweentime) { if (Region.Zone.bWaterZone) { TweenToSwimming(tweentime); return; } if ( bDicePlayer ) { TweenAnim('Breath2', tweentime); return; } TweenAnim('Breath', tweentime); } function TweenToPatrolStop(float tweentime) { if (Region.Zone.bWaterZone) { TweenToSwimming(tweentime); return; } TweenAnim('Breath', tweentime); } function TweenToFalling() { TweenAnim('Jump', 0.35); } function PlayInAir() { TweenAnim('Jump', 0.2); } function PlayOutOfWater() { TweenAnim('Land',0.8); } function PlayLanded(float impactVel) { TweenAnim('Land', 0.1); } function PlayMovingAttack() { if (Region.Zone.bWaterZone) { PlayAnim('SwimFire'); SpawnShot(); return; } DesiredSpeed = 0.4; MoveTimer += 0.2; PlayAnim('Shoot2'); } function PlayRunning() { if (Region.Zone.bWaterZone) { PlaySwimming(); return; } DesiredSpeed = 1.0; if (Focus == Destination) { LoopAnim('Run', -1.0/GroundSpeed,, 0.4); return; } LoopAnim('Run', StrafeAdjust(),,0.3); } function PlayWalking() { if (Region.Zone.bWaterZone) { PlaySwimming(); return; } LoopAnim('Walk', 0.88); } function TweenToSwimming(float tweentime) { if ( (AnimSequence != 'Swim') || !bAnimLoop ) TweenAnim('Swim', tweentime); } function PlaySwimming() { LoopAnim('Swim', -1.0/WaterSpeed,,0.3); } function PlayThreatening() { local float decision, animspeed; if (Region.Zone.bWaterZone) { PlaySwimming(); return; } decision = FRand(); animspeed = 0.4 + 0.6 * FRand(); if ( decision < 0.6 ) PlayAnim('Breath', animspeed, 0.3); else if ( decision < 0.7 ) { PlaySound(Twirl,SLOT_Interact,0.5,,500); PlayAnim('Twirl', animspeed, 0.3); } else { PlayThreateningSound(); if ( decision < 0.8 ) PlayAnim('T3', animspeed, 0.3); else if ( decision < 0.9 ) PlayAnim('ThreatShoot1', 0.3, 0.3); else TweenAnim('Fighter', 0.3); } } function PlayTurning() { if (Region.Zone.bWaterZone) { PlaySwimming(); return; } TweenAnim('Walk', 0.3); } function PlayBigDeath(name DamageType) { PlaySound(Die2, SLOT_Talk, 4 * TransientSoundVolume); PlayAnim('Die2',0.7,0.1); } function PlayHeadDeath(name DamageType) { local carcass carc; if ( ((DamageType == 'Decapitated') || ((Health < -20) && (FRand() < 0.5))) && !Level.Game.bVeryLowGore ) { carc = Spawn(class 'CreatureChunks',,, Location + CollisionHeight * vect(0,0,0.8), Rotation + rot(3000,0,16384) ); if (carc != None) { carc.Mesh = mesh'KrallHead'; carc.Initfor(self); carc.Velocity = Velocity + VSize(Velocity) * VRand(); carc.Velocity.Z = FMax(carc.Velocity.Z, Velocity.Z); } PlayAnim('Dead5',0.7,0.1); if ( Velocity.Z < 120 ) { Velocity = GroundSpeed * vector(Rotation); Velocity.Z = 150; } } else if ( FRand() < 0.5 ) PlayAnim('Die4',0.7,0.1); else PlayAnim('Die3',0.7,0.1); PlaySound(Die, SLOT_Talk, 4 * TransientSoundVolume); } function PlayLeftDeath(name DamageType) { PlayAnim('Die4',0.7, 0.1); PlaySound(Die,SLOT_Talk, 4 * TransientSoundVolume); } function PlayRightDeath(name DamageType) { PlayAnim('Die3',0.7,0.1); PlaySound(Die,SLOT_Talk, 4 * TransientSoundVolume); } function PlayGutDeath(name DamageType) { if ( Velocity.Z > 100 ) PlayAnim('Die3',0.7,0.1); else PlayAnim('Die1',0.7,0.1); PlaySound(Die,SLOT_Talk, 4 * TransientSoundVolume); } function PlayVictoryDance() { PlaySound(Twirl,SLOT_Interact,0.5,,500); PlayAnim('Twirl', 0.5, 0.1); } function bool CanFireAtEnemy() { local vector HitLocation, HitNormal,X,Y,Z, projStart, EnemyDir, EnemyUp; local actor HitActor; local float EnemyDist; EnemyDir = Enemy.Location - Location; EnemyDist = VSize(EnemyDir); EnemyUp = Enemy.CollisionHeight * vect(0,0,0.9); if ( EnemyDist > 300 ) { EnemyDir = 300 * EnemyDir/EnemyDist; EnemyUp = 300 * EnemyUp/EnemyDist; } GetAxes(Rotation,X,Y,Z); projStart = Location + 0.9 * CollisionRadius * X - 0.7 * CollisionRadius * Y; HitActor = Trace(HitLocation, HitNormal, projStart + EnemyDir + EnemyUp, projStart, true); if ( (HitActor == None) || (HitActor == Enemy) || ((Pawn(HitActor) != None) && (AttitudeTo(Pawn(HitActor)) <= ATTITUDE_Ignore)) ) return true; HitActor = Trace(HitLocation, HitNormal, projStart + EnemyDir, projStart , true); return ( (HitActor == None) || (HitActor == Enemy) || ((Pawn(HitActor) != None) && (AttitudeTo(Pawn(HitActor)) <= ATTITUDE_Ignore)) ); } function SpawnShot() { DesiredSpeed = 0.0; //For Kraal shoot2 (walking shoot, w/ pause) FireProjectile( vect(0.9, -0.5, 0), 500); } function ShotMove() { DesiredSpeed = 1.0; } function StrikeDamageTarget() { if (MeleeDamageTarget(StrikeDamage, StrikeDamage * 700 * Normal(Target.Location - Location))) PlaySound(SpearHit,SLOT_Interact); } function PoundDamageTarget() { if (MeleeDamageTarget(PoundDamage, PoundDamage * 500 * Normal(Target.Location - Location))) PlaySound(SpearHit,SLOT_Interact); } function ThrowDamageTarget() { AttackSuccess = MeleeDamageTarget(ThrowDamage, vect(0,0,0)); } function ThrowTarget() { local rotator newRot; if (AttackSuccess && (Vsize(Target.Location - Location) < CollisionRadius + Target.CollisionRadius + 1.5 * MeleeRange) ) { PlaySound(SpearThrow,SLOT_Interact); newRot = Target.Rotation; newRot.Pitch = 4096; Target.SetRotation(newRot); if (Pawn(Target) != None) { Pawn(Target).AddVelocity( (50000.0 * (Normal(Target.Location - Location) + vect(0,0,1)))/Target.Mass); if (PlayerPawn(Target) != None) PlayerPawn(Target).ShakeView(0.2, 2000, -10); } } } function PlayMeleeAttack() { local float decision; decision = FRand(); if (!bSpearToss) decision *= 0.7; if (decision < 0.2) { PlayAnim('Strike1'); PlaySound(Strike1,SLOT_Interact); } else if (decision < 0.4) { PlayAnim('Strike2'); PlaySound(Strike2,SLOT_Interact); } else if (decision < 0.7) { PlayAnim('Strike3'); PlaySound(Strike1,SLOT_Interact); } else { PlayAnim('Throw'); PlaySound(Strike2,SLOT_Interact); } } function PlayRangedAttack() { local float tweenin; if (Region.Zone.bWaterZone) { PlayAnim('SwimFire'); SpawnShot(); return; } if (AnimSequence == 'Shoot1') tweenin = 0.3 * FRand(); else tweenin = 0.35; PlayAnim('Shoot1', 1.0, tweenin); } state TacticalMove { ignores SeePlayer, HearNoise; function TweenToRunning(float tweentime) { if ( bDicePlayer ) { PeripheralVision = Default.PeripheralVision; bDicePlayer = false; } if (Region.Zone.bWaterZone) { TweenToSwimming(tweentime); return; } if ( bCanStrafe && (AnimSequence == 'Shoot2') && IsAnimating() ) return; if ( (AnimSequence != 'Run') || !bAnimLoop ) TweenAnim('Run', tweentime); } } g(oB%.dC@yod??, Yaabyի?o(wY*yabo?,Yaaby(wY*(yycy::$6ccd y//============================================================================= // TeamMercenary //============================================================================= class TeamMercenary extends TeamScriptedPawn; // FIXME - also have sound breathmr //====================================================================== // Mercenary Functions var() byte PunchDamage; var() byte OrdersGiven; var() bool bButtonPusher; var() bool bTalker; var() bool bSquatter; var bool bPatroling; var() bool bHasInvulnerableShield; var() bool bCanFireWhileInvulnerable; var bool bIsInvulnerable; var bool bAlertedTeam; var(Sounds) sound Punch; var(Sounds) sound PunchHit; var(Sounds) sound Flip; var(Sounds) sound CheckWeapon; var(Sounds) sound WeaponSpray; var(Sounds) sound syllable1; var(Sounds) sound syllable2; var(Sounds) sound syllable3; var(Sounds) sound syllable4; var(Sounds) sound syllable5; var(Sounds) sound syllable6; var(Sounds) sound breath; var(Sounds) sound footstep1; var name phrase; var byte phrasesyllable; var float voicePitch; var int sprayoffset; var float invulnerableTime; var() float invulnerableCharge; //====================================================================== // Mercenary Functions function PreBeginPlay() { bCanSpeak = true; voicePitch = 0.5 + 0.75 * FRand(); Super.PreBeginPlay(); if ( bHasInvulnerableShield ) bHasInvulnerableShield = ( Skill > 2.5 * FRand() - 1 ); bCanDuck = bHasInvulnerableShield; if ( bMovingRangedAttack ) bMovingRangedAttack = ( 0.2 * Skill + 0.3 > FRand() ); } function ZoneChange(ZoneInfo newZone) { bCanSwim = newZone.bWaterZone; //only when it must if ( newZone.bWaterZone ) CombatStyle = 1.0; //always charges when in the water else if (Physics == PHYS_Swimming) CombatStyle = Default.CombatStyle; Super.ZoneChange(newZone); } event FootZoneChange(ZoneInfo newFootZone) { local float OldPainTime; OldPainTime = PainTime; Super.FootZoneChange(newFootZone); if ( bIsInvulnerable && (PainTime <= 0) ) PainTime = FMax(OldPainTime, 0.1); } event HeadZoneChange(ZoneInfo newHeadZone) { local float OldPainTime; OldPainTime = PainTime; Super.HeadZoneChange(newHeadZone); if ( bIsInvulnerable && (PainTime <= 0) ) PainTime = FMax(OldPainTime, 0.1); } function SetMovementPhysics() { if ( Region.Zone.bWaterZone ) SetPhysics(PHYS_Swimming); else if (Physics != PHYS_Walking) SetPhysics(PHYS_Walking); } function TryToDuck(vector duckDir, bool bReversed) { BecomeInvulnerable(); } function BecomeInvulnerable() { if ( bIsInvulnerable ) return; if ( invulnerableTime > 0 ) { InvulnerableCharge += (Level.TimeSeconds - InvulnerableTime)/2; InvulnerableTime = Level.TimeSeconds; } if ( InvulnerableCharge > 4 ) GotoState('Invulnerable'); } function BecomeNormal() { AmbientGlow = 0; bUnlit = false; bMeshEnviroMap = false; LightType = LT_None; InvulnerableTime = Level.TimeSeconds; bIsInvulnerable = false; if ( !Region.Zone.bPainZone ) PainTime = -1.0; } function PainTimer() { if ( Health <= 0 ) return; if ( !bIsInvulnerable ) { if ( bHasInvulnerableShield && Region.Zone.bPainZone && (Region.Zone.DamagePerSec > 0) ) BecomeInvulnerable(); Super.PainTimer(); if ( bIsInvulnerable ) PainTime = 1.0; return; } InvulnerableCharge -= 1.0; if ( (InvulnerableCharge < 0) || (Level.TimeSeconds - InvulnerableTime > 4 + 5 * FRand()) ) BecomeNormal(); else PainTime = 1.0; } function WarnTarget(Pawn shooter, float projSpeed, vector FireDir) { if ( !bIsInvulnerable ) Super.WarnTarget(shooter, projSpeed, FireDir); } function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { if ( !bIsInvulnerable ) Super.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType); else if ( Damage > 0 ) { InvulnerableCharge = InvulnerableCharge - Damage/100; PainTime = 0.3; //change to take-damage invulnerable skin } } //Azathoth deleted - function eAttitude AttitudeToCreature(Pawn Other) //========================================================================================= // Speech function SpeechTimer() { //last syllable expired. Decide whether to keep the floor or quit if (FRand() < 0.3) { bIsSpeaking = false; if (TeamLeader != None) TeamLeader.bTeamSpeaking = false; } else Speak(); } function SpeakOrderTo(TeamScriptedPawn TeamMember) { phrase = ''; if ( !TeamMember.bCanSpeak || (FRand() < 0.5) ) Speak(); else { if (TeamMercenary(TeamMember) != None) TeamMercenary(TeamMember).phrase = ''; TeamMember.Speak(); } } function SpeakTo(TeamScriptedPawn Other) { if (Other.bIsSpeaking || ((TeamLeader != None) && TeamLeader.bTeamSpeaking) ) return; phrase = ''; Speak(); } function Speak() { local float decision; //if (phrase != '') // SpeakPhrase(); bIsSpeaking = true; decision = FRand(); if (TeamLeader != None) TeamLeader.bTeamSpeaking = true; if (decision < 0.167) PlaySound(Syllable1,SLOT_Talk,0.3 + 2 * FRand(),,, FRand() + voicePitch); else if (decision < 0.333) PlaySound(Syllable2,SLOT_Talk,0.3 + 2 * FRand(),,, FRand() + voicePitch); else if (decision < 0.5) PlaySound(Syllable3,SLOT_Talk,0.3 + 2 * FRand(),,, FRand() + voicePitch); else if (decision < 0.667) PlaySound(Syllable4,SLOT_Talk,0.3 + 2 * FRand(),,, FRand() + voicePitch); else if (decision < 0.833) PlaySound(Syllable5,SLOT_Talk,0.3 + 2 * FRand(),,, FRand() + voicePitch); else PlaySound(Syllable6,SLOT_Talk,0.3 + 2 * FRand(),,, FRand() + voicePitch); SpeechTime = 0.1 + 0.3 * FRand(); } //========================================================================================= function Step() { PlaySound(footstep1, SLOT_Interact,,,1500); } function WalkStep() { PlaySound(footstep1, SLOT_Interact,0.2,,500); } function PlayWaiting() { local float decision; local float animspeed; if (Region.Zone.bWaterZone) { PlaySwimming(); return; } animspeed = 0.4 + 0.6 * FRand(); decision = FRand(); if ( bButtonPusher ) { SetAlertness(-1.0); if (decision < 0.3) LoopAnim('Breath', animspeed, 1.0); else if (decision < 0.4) LoopAnim('MButton1', animspeed); else if (decision < 0.5) LoopAnim('MButton2', animspeed); else if (decision < 0.6) LoopAnim('MButton3', animspeed); else if (decision < 0.7) LoopAnim('MButton4', animspeed); else if (decision < 0.75) LoopAnim('Button1', animspeed); else if (decision < 0.80) LoopAnim('Button2', animspeed); else if (decision < 0.85) LoopAnim('Button3', animspeed); else if (decision < 0.90) LoopAnim('Button4', animspeed); else if (decision < 0.95) LoopAnim('Button5', animspeed); else LoopAnim('Button6', animspeed); return; } else if ( bTalker ) { SetAlertness(-0.5); if ( (TeamLeader == None) || TeamLeader.bTeamSpeaking ) { if ( FRand() < 0.1 ) LoopAnim('NeckCrak', animspeed, 0.5); else LoopAnim('Breath', animspeed, 0.5); return; } phrase = ''; Speak(); if (decision < 0.5) LoopAnim('Talk1', animspeed, 0.5); else if (decision < 0.75) LoopAnim('Talk2', animspeed, 0.5); else LoopAnim('Talk3', animspeed, 0.5); return; } else if ( bSquatter ) { SetAlertness(-0.5); if ( (TeamLeader == None) || TeamLeader.bTeamSpeaking ) { LoopAnim('Squat3', animspeed); return; } phrase = ''; Speak(); if (decision < 0.5) LoopAnim('Squat1', animspeed); else LoopAnim('Squat2', animspeed); return; } SetAlertness(0.0); if ( bPatroling ) decision *= 0.4; if ( (AnimSequence == 'Breath') && (decision < 0.15) ) { LoopAnim('Weapon', animspeed); PlaySound(CheckWeapon, SLOT_Interact); } else if ( (AnimSequence == 'Breath') && (decision < 0.25) ) LoopAnim('NeckCrak', animspeed); else LoopAnim('Breath', animspeed); bPatroling = false; } function PlayPatrolStop() { bPatroling = true; PlayWaiting(); } function PlayWaitingAmbush() { PlayWaiting(); } function PlayChallenge() { if (Region.Zone.bWaterZone) { PlaySwimming(); return; } if ( TryToCrouch() ) { TweenAnim('Duck', 0.12); return; } PlayThreateningSound(); if ( FRand() < 0.6 ) PlayAnim('Talk1', 0.7, 0.2); else PlayAnim('Talk2', 0.7, 0.2); } function PlayDive() { TweenToSwimming(0.2); } function TweenToFighter(float tweentime) { bButtonPusher = false; bTalker = false; bSquatter = false; if (Region.Zone.bWaterZone) { TweenToSwimming(tweentime); return; } TweenAnim('Fighter', tweentime); } function TweenToRunning(float tweentime) { bButtonPusher = false; bTalker = false; bSquatter = false; if (Region.Zone.bWaterZone) { TweenToSwimming(tweentime); return; } if (AnimSequence != 'Run' || !bAnimLoop) TweenAnim('Run', tweentime); } function TweenToWalking(float tweentime) { if (Region.Zone.bWaterZone) { TweenToSwimming(tweentime); return; } TweenAnim('Walk', tweentime); } function TweenToWaiting(float tweentime) { if (Region.Zone.bWaterZone) { TweenToSwimming(tweentime); return; } if ( bSquatter ) { TweenAnim('Squat3', tweentime); return; } TweenAnim('Breath', tweentime); } function TweenToPatrolStop(float tweentime) { if (Region.Zone.bWaterZone) { TweenToSwimming(tweentime); return; } TweenAnim('Breath', tweentime); } function PlayRunning() { DesiredSpeed = 1.0; if (Region.Zone.bWaterZone) { PlaySwimming(); return; } if (Focus == Destination) { LoopAnim('Run', -1.0/GroundSpeed,, 0.4); return; } LoopAnim('Run', StrafeAdjust(),,0.3); } function PlayWalking() { if (Region.Zone.bWaterZone) { PlaySwimming(); return; } LoopAnim('Walk', 0.8); } function TweenToSwimming(float tweentime) { if (AnimSequence != 'Swim' || !bAnimLoop) TweenAnim('Swim', tweentime); } function PlaySwimming() { LoopAnim('Swim', -1.0/GroundSpeed,,0.3); } function TweenToFalling() { TweenAnim('Jump2', 0.35); } function PlayInAir() { TweenAnim('Jump2', 0.2); } function PlayOutOfWater() { TweenAnim('Land', 0.8); } function PlayLanded(float impactVel) { TweenAnim('Land', 0.1); } function PlayMovingAttack() { if ( bIsInvulnerable && !bCanFireWhileInvulnerable ) { if ( Level.TimeSeconds - InvulnerableTime < 4 ) { PlayRunning(); return; } else BecomeNormal(); } if (Region.Zone.bWaterZone) { PlayAnim('SwimFire'); return; } DesiredSpeed = 0.4; MoveTimer += 0.2; if ( FRand() < 0.5 ) { if ( GetAnimGroup(AnimSequence) == 'MovingAttack' ) PlayAnim('WalkFire'); else PlayAnim('WalkFire', 1.0, 0.05); } else { sprayoffset = 0; PlaySound(WeaponSpray, SLOT_Interact); if ( GetAnimGroup(AnimSequence) == 'MovingAttack' ) PlayAnim('WalkSpray'); else PlayAnim('WalkSpray', 1.0, 0.05); } } function PlayThreatening() { local float decision, animspeed; if (Region.Zone.bWaterZone) { PlaySwimming(); return; } decision = FRand(); animspeed = 0.6 + 0.4 * FRand(); if ( decision < 0.3 ) PlayAnim('Breath', animspeed, 0.25); else if ( decision < 0.45 ) PlayAnim('Weapon', animspeed, 0.25); else { PlayThreateningSound(); if ( decision < 0.65 ) TweenAnim('Fighter', 0.3); else if ( decision < 0.85 ) PlayAnim('Talk1', animspeed, 0.25); else PlayAnim('Talk2', animspeed, 0.25); } } function PlayTurning() { if (Region.Zone.bWaterZone) { PlaySwimming(); return; } TweenAnim('Walk', 0.3); } function PlayBigDeath(name DamageType) { PlayAnim('Dead2',0.7,0.1); PlaySound(sound'Death3mr', SLOT_Talk, 4 * TransientSoundVolume); } function PlayHeadDeath(name DamageType) { local carcass carc; if ( ((DamageType == 'Decapitated') || ((Health < -20) && (FRand() < 0.5))) && !Level.Game.bVeryLowGore ) { carc = Spawn(class 'CreatureChunks',,, Location + CollisionHeight * vect(0,0,0.8), Rotation + rot(3000,0,16384) ); if (carc != None) { carc.Mesh = mesh'MercHead'; carc.Initfor(self); carc.Velocity = Velocity + VSize(Velocity) * VRand(); carc.Velocity.Z = FMax(carc.Velocity.Z, Velocity.Z); } PlayAnim('Dead5',0.7,0.1); SprayOffset = 0; } else PlayAnim('Death',0.7,0.1); PlaySound(Die, SLOT_Talk, 4 * TransientSoundVolume); } function PlayLeftDeath(name DamageType) { PlayAnim('Dead4',0.7,0.1); PlaySound(sound'Death2mr', SLOT_Talk, 4 * TransientSoundVolume); } function PlayRightDeath(name DamageType) { PlayAnim('Death',0.7,0.1); PlaySound(Die, SLOT_Talk, 4 * TransientSoundVolume); } function PlayGutDeath(name DamageType) { PlayAnim('Dead3',0.7,0.1); PlaySound(sound'Death2mr', SLOT_Talk, 4 * TransientSoundVolume); } function PlayVictoryDance() { //if ( FRand() < 0.5 ) //{ PlaySound(Flip, SLOT_Interact); PlayAnim('Jump', 1.0, 0.1); //} //else // PlayAnim('BigDance', 0.7, 0.25); } function PlayMeleeAttack() { local float decision; decision = FRand(); if (AnimSequence == 'Swat') decision -= 0.2; PlaySound(Punch, SLOT_Interact); If (decision < 0.3) PlayAnim('Punch'); else PlayAnim('Swat'); } function bool CanFireAtEnemy() { local vector HitLocation, HitNormal,X,Y,Z, projStart, EnemyDir, EnemyUp; local actor HitActor; local float EnemyDist; EnemyDir = Enemy.Location - Location; EnemyDist = VSize(EnemyDir); EnemyUp = Enemy.CollisionHeight * vect(0,0,0.9); if ( EnemyDist > 300 ) { EnemyDir = 300 * EnemyDir/EnemyDist; EnemyUp = 300 * EnemyUp/EnemyDist; } GetAxes(Rotation,X,Y,Z); projStart = Location + 0.9 * CollisionRadius * X - 0.6 * CollisionRadius * Y; HitActor = Trace(HitLocation, HitNormal, projStart + EnemyDir + EnemyUp, projStart, true); if ( (HitActor == None) || (HitActor == Enemy) || ((Pawn(HitActor) != None) && (AttitudeTo(Pawn(HitActor)) <= ATTITUDE_Ignore)) ) return true; HitActor = Trace(HitLocation, HitNormal, projStart + EnemyDir, projStart , true); return ( (HitActor == None) || (HitActor == Enemy) || ((Pawn(HitActor) != None) && (AttitudeTo(Pawn(HitActor)) <= ATTITUDE_Ignore)) ); } function SpawnRocket() { FireProjectile( vect(0.9, -0.4, 0), 400); } function SprayTarget() { local vector EndTrace, fireDir; local vector HitNormal, HitLocation; local actor HitActor; local rotator AdjRot; local vector X,Y,Z; AdjRot = Rotation; if ( AnimSequence == 'Dead5' ) AdjRot.Yaw += 3000 * (2 - sprayOffset); else AdjRot.Yaw += 1000 * (3 - sprayOffset); sprayoffset++; fireDir = vector(AdjRot); if ( (sprayoffset == 1) || (sprayoffset == 3) || (sprayoffset == 5) ) { GetAxes(Rotation,X,Y,Z); if ( AnimSequence == 'Spray' ) spawn(class'MercFlare', self, '', Location + 1.25 * CollisionRadius * X - CollisionRadius * (0.2 * sprayoffset - 0.3) * Y); else spawn(class'MercFlare', self, '', Location + 1.25 * CollisionRadius * X - CollisionRadius * (0.1 * sprayoffset - 0.1) * Y); } if ( AnimSequence == 'Dead5' ) sprayoffset++; EndTrace = Location + 2000 * fireDir; EndTrace.Z = Target.Location.Z + Target.CollisionHeight * 0.6; HitActor = TraceShot(HitLocation,HitNormal,EndTrace,Location); if (HitActor == Level) // Hit a wall { spawn(class'SmallSpark2',,,HitLocation+HitNormal*5,rotator(HitNormal*2+VRand())); spawn(class'SpriteSmokePuff',,,HitLocation+HitNormal*9); } else if ((HitActor != self) && (HitActor != Owner)) { HitActor.TakeDamage(10, self, HitLocation, 10000.0*fireDir, 'shot'); spawn(class'SpriteSmokePuff',,,HitLocation+HitNormal*9); } } function HitDamageTarget() { if (MeleeDamageTarget(PunchDamage, (PunchDamage * 1000 * Normal(Target.Location - Location)))) PlaySound(PunchHit, SLOT_Interact); } function PlayRangedAttack() { //FIXME - if going to ranged attack need to // TweenAnim('StillFire', 0.2); //What I need is a tween into time for the PlayAnim() if ( bIsInvulnerable && !bCanFireWhileInvulnerable ) { if ( Level.TimeSeconds - InvulnerableTime > 3 ) BecomeNormal(); else if ( FRand() < 0.75 ) { PlayChallenge(); return; } } if (Region.Zone.bWaterZone) { PlayAnim('SwimFire'); return; } MakeNoise(1.0); if (FRand() < 0.35) { PlayAnim('Shoot'); SpawnRocket(); } else { sprayoffset = 0; PlaySound(WeaponSpray, SLOT_Interact); PlayAnim('Spray'); } } function ChooseLeaderAttack() { if ( bReadyToAttack && bHasInvulnerableShield && !bIsInvulnerable && (InvulnerableCharge > 0) ) { BecomeInvulnerable(); if ( IsInState('Invulnerable') ) return; } if ( !bAlertedTeam && (OrdersGiven < 2) ) { OrdersGiven = OrdersGiven + 1; GotoState('SpeakOrders'); } else GotoState('TacticalMove', 'NoCharge'); } state SpeakOrders { ignores SeePlayer, HearNoise, Bump; function Killed(pawn Killer, pawn Other, name damageType) { Super.Killed(Killer, Other, damageType); if ( (Health > 0) && !bTeamLeader ) GotoState('Attacking'); } function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType); if ( health <= 0 ) return; if (NextState == 'TakeHit') { NextState = 'Attacking'; NextLabel = 'Begin'; GotoState('TakeHit'); } } function EnemyNotVisible() { } Begin: bAlertedTeam = true; Acceleration = vect(0,0,0); if (NeedToTurn(enemy.Location)) { PlayTurning(); TurnToward(Enemy); } TweenAnim('Talk2', 0.1); FinishAnim(); phrase = ''; Speak(); if (FRand() < 0.5) PlayAnim('Talk2', 0.6); else PlayAnim('Talk3', 0.6); FinishAnim(); if (FRand() < 0.3) Goto('Done'); if (FRand() < 0.5) PlayAnim('Talk2', 0.9); else PlayAnim('Talk3', 0.9); FinishAnim(); Done: bReadyToAttack = true; GotoState('Attacking'); } state Invulnerable { ignores SeePlayer, HearNoise, Bump; function TryToDuck(vector duckDir, bool bReversed) { } function AnimEnd() { if (AnimSequence == 'Stealth1') { bIsInvulnerable = true; bMeshEnviroMap = true; invulnerableTime = Level.TimeSeconds; PainTime = 1.0; AmbientGlow = 70; bUnlit = true; LightType=LT_Pulse; PlayAnim('Stealth2'); } else GotoState('Attacking'); } Begin: Acceleration = vect(0,0,0); PlayAnim('Stealth1', 1.4, 0.07); KeepTurning: TurnToward(Enemy); Sleep(0.0); Goto('KeepTurning'); } state RangedAttack { ignores SeePlayer, HearNoise; function TryToDuck(vector duckDir, bool bReversed) { if ( bCanFireWhileInvulnerable || (FRand() < 0.5) ) BecomeInvulnerable(); } function BeginState() { Super.BeginState(); if ( !bIsInvulnerable && bHasInvulnerableShield && bCanFireWhileInvulnerable && (InvulnerableCharge > 4) && (FRand() > 0.75) ) { bReadyToAttack = true; BecomeInvulnerable(); } } } AG//============================================================================= // TeamLeglessKrall. //============================================================================= class TeamLeglessKrall extends TeamKrall; var float startTime; function PreBeginPlay() { bCanSpeak = true; voicePitch = 0.25 + 0.5 * FRand(); if ( CombatStyle == Default.CombatStyle) CombatStyle = CombatStyle + 0.4 * FRand() - 0.2; bCanDuck = (FRand() < 0.5); Super.PreBeginPlay(); CombatStyle = 1.0; bCanDuck = false; bCanStrafe = false; startTime = Level.TimeSeconds; } function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { if ( Level.timeSeconds - startTime < 0.3 ) return; Health = Min(-1, Health - Damage); PlayDeathHit(Damage, hitLocation, damageType, Momentum); Enemy = instigatedBy; Died(instigatedBy, damageType, HitLocation); } function WhatToDoNext(name LikelyState, name LikelyLabel) { Health = -1; Died(self, '', Location); } function PlayTakeHit(float tweentime, vector HitLoc, int damage) { TweenAnim('Drag', tweentime); } function PlayWaiting() { TweenAnim('Drag', 0.3); } function PlayPatrolStop() { TweenAnim('Drag', 0.3); } function PlayWaitingAmbush() { TweenAnim('Drag', 0.3); } function PlayChallenge() { TweenAnim('Shoot3', 0.3); } function TweenToFighter(float tweentime) { TweenAnim('Shoot3', tweentime); } function TweenToRunning(float tweentime) { TweenAnim('Drag', tweentime); } function TweenToWalking(float tweentime) { TweenAnim('Drag', tweentime); } function TweenToWaiting(float tweentime) { TweenAnim('Drag', tweentime); } function TweenToPatrolStop(float tweentime) { TweenAnim('Drag', tweentime); } function TweenToFalling() { TweenAnim('Shoot3', 0.3); } function PlayInAir() { TweenAnim('Shoot3', 0.3); } function PlayOutOfWater() { TweenAnim('Shoot3', 0.3); } function PlayLanded(float impactVel) { TweenAnim('LeglessDeath', 0.1); } function PlayMovingAttack() { LoopAnim('Shoot3'); } function PlayRunning() { LoopAnim('Drag'); } function PlayWalking() { LoopAnim('Drag'); } function TweenToSwimming(float tweentime) { TweenAnim('Drag', tweentime); } function PlaySwimming() { LoopAnim('Drag'); } function PlayThreatening() { TweenAnim('Shoot3', 0.3); } function PlayTurning() { PlayAnim('Drag'); } function PlayDying(name DamageType, vector HitLoc) { PlaySound(Die, SLOT_Talk, 4 * TransientSoundVolume); TweenAnim('LeglessDeath', 0.4); } function PlayVictoryDance() { TweenAnim('Shoot3', 0.3); } function bool CanFireAtEnemy() { local vector HitLocation, HitNormal,X,Y,Z, projStart, EnemyDir, EnemyUp; local actor HitActor; local float EnemyDist; EnemyDir = Enemy.Location - Location; EnemyDist = VSize(EnemyDir); EnemyUp = Enemy.CollisionHeight * vect(0,0,0.9); if ( EnemyDist > 300 ) { EnemyDir = 300 * EnemyDir/EnemyDist; EnemyUp = 300 * EnemyUp/EnemyDist; } GetAxes(Rotation,X,Y,Z); projStart = Location + 0.9 * CollisionRadius * X - 0.9 * CollisionRadius * Y; HitActor = Trace(HitLocation, HitNormal, projStart + EnemyDir + EnemyUp, projStart, true); if ( (HitActor == None) || (HitActor == Enemy) || ((Pawn(HitActor) != None) && (AttitudeTo(Pawn(HitActor)) <= ATTITUDE_Ignore)) ) return true; HitActor = Trace(HitLocation, HitNormal, projStart + EnemyDir, projStart , true); return ( (HitActor == None) || (HitActor == Enemy) || ((Pawn(HitActor) != None) && (AttitudeTo(Pawn(HitActor)) <= ATTITUDE_Ignore)) ); } function SpawnShot() { FireProjectile( vect(0.9, -0.9, 0), 500); } function PlayMeleeAttack() { PlayAnim('Shoot3'); } function PlayRangedAttack() { PlayAnim('Shoot3'); } function Initfor(TeamKrall Other) { local rotator carcRotation; bMeshCurvy = Other.bMeshCurvy; bMeshEnviroMap = Other.bMeshEnviroMap; Mesh = Other.Mesh; Skin = Other.Skin; Texture = Other.Texture; Fatness = Other.Fatness; DrawScale = Other.DrawScale; Tag = Other.Tag; Event = ''; PlayAnim('LegLoss', 0.7); SetPhysics(PHYS_Falling); Velocity = other.Velocity; Enemy=Other.Enemy; OldEnemy=Other.OldEnemy; NextState='Attacking'; NextLabel='Begin'; GotoState('TakeHit'); } state TacticalMove { ignores SeePlayer, HearNoise; function TweenToRunning(float tweentime) { TweenAnim('Drag', tweentime); } } X(@ B-PAa!M?L>a{$a{$ ^(E!CA':EG au$au$ _(P[ "VPu QT':WGu #?au$au$ $H($P> a! w a(wXGa&!w W`(xJ#Px66K66{K@ K(' RKk(b(x::$ kw a/!~.w C]?%#q!b!v bq!b!T d(4$X-PA:ff>a $a $a!d Van $an $a!`  4h(#2&_-PAA!M 333?aV$a!a ]a!Ma{$a{$ 8i(Mv}'C6M-M!Xq!hA8M Au(_ 2 q!t j(v(Cn)-'a!g aao$?9a!Caaq!a&!E L=o$ b{@x n(A( o(p(q(r(Vm(t(R(:1x -$x q!C!{v!R x !@),*!b!Bq! s( R) -( l(A)g~,t-'o$?9a!Caa!Caq!a&!CL=o$ H@\ y(R+ z({(|(}(Vx((R+:1P -$P q!g!v!R P I)+b u! ~( b, -( w(C)h*-l!X#ax$a!maa!Ya-D'a&!H@q! \ D)(- E)F)G)H) H8HGA@,% Kw* z!!!q!q! b//============================================================================= // TeamLesserBrute. //============================================================================= class TeamLesserBrute extends TeamBrute; function PlayRunning() { if (Focus == Destination) { LoopAnim('Walk', -1.3/GroundSpeed,,0.4); return; } LoopAnim('Walk', StrafeAdjust(),,0.3); } function PlayWalking() { LoopAnim('Walk', -1.3/GroundSpeed,,0.4); } function PlayMovingAttack() { PlayAnim('WalkFire', 1.3); } function GoBerserk() { bLongBerserk = false; if ( bBerserk || ((Health < 0.75 * Default.Health) && (FRand() < 0.7)) ) bBerserk = true; else bBerserk = false; if ( bBerserk ) { AccelRate = 4 * AccelRate; GroundSpeed = (2.1 + 0.2 * skill) * Default.GroundSpeed; } } state TacticalMove { ignores SeePlayer, HearNoise; function AnimEnd() { If ( bBerserk ) LoopAnim('Charge', -1.1/GroundSpeed,,0.5); else PlayCombatMove(); } function BeginState() { GoBerserk(); Super.BeginState(); } function EndState() { if ( bBerserk ) { GroundSpeed = Default.GroundSpeed; AccelRate = Default.AccelRate; } Super.EndState(); } } f E6*-i(*L>-( SC4v@C TC?,-@m::$@?r*@?3@>aA$u!a!N? #@?+C?,#6333?Co$taR$a!WHB':[# .R Tr#.-5-5 ? mM)O)D-(q!G P) N)Du$2$::$#0D x W[|Q)c,/=-(-(-'-(-(-( wS)U)N;f@ I@J#fff?I?,@?,@IJ?,JIA#RaG C A@JA''rR* rR)w.R*: .R:$'RaG C A@A'rR* rR)w.R*: .R:$ G L dJ)nh B6X)ԂdZX`$L>M$Cq$C!"v[$] Lesser Brute[A$L?^n7$(B/$(B<$zCa$pCj//============================================================================= // TeamIceSkaarj. //============================================================================= class TeamIceSkaarj extends TeamSkaarjWarrior; \)W)xv::$ sL a/!~.L C-i'e?%#q!J!B bq!J!T Y)j B6[)|Lvn [$?= Ice Skaarj[Aa)_q q!t 9T)2T&6-o$$o$ Q])@^> +-'-{ Q@-(-{  _{ !E*,i*!J!hq! ^)R g  [b)[k, 2 "c) pd a&!m@ d)u a&!m@ e)Ez a&!m@ $f)$ E1a%!sak$a!N?L>Ca!b?= g)} @1a%!sak$a!N?L>>a&!b} k)AD A*L.!/a0 A.KK10erA*Aw.*. h)U \1a%!sak$a!N?L>ZZ!o -a&!oU m)+p "!q!} q! j)|& \1a%!sak$a!N?L>ZZ!n -a&!n| (c_  Nr_ q!%EEw._ *._ q!%v! l)o)00.a%!sak$a!o ?L> n)R@1a%!sak$a!N?L>>a&!bR  Qh-E- ::$8QAPNMR% !-E rA!!!!!}!nq! p) Fa!o? > r)a!n? > s)5+L?a!b>)a!j> t) >;1a%!sak$a!N?L>9a!b u)w)lVa$@@=6?,a!G333?=Ta!c333?=o$ x)v)n6a&!n q N a!oL? |)y)Qba&!bL> })Y a!b ~)@*F a!b )@aN $a!j?= A*4aN $a!j B*k @>'R ?R  aC$ 4C*e#gb?e#aY!e]&e-5-qa!` (P*Ka#<q!b!K y D*G*6}u_::$u vr*%mw * %  *vq!G bq!nq!( oF*I*nJ,$ab- -| ? ?,d}#a$a?=q!Ga!b !n niR?=Z8RmONP,% X!!!q! az)J*l QB6-a$@a!c333?=Oa&!M33> [kN*e)Fw`* !Y a!Y?=-S'q!(!h V*IH*t]0a aq! yR*+\j u! T*} a!oL > a[*MbV7?,xM q!b!B y cE-'-'-(-'-'-'-G' W x3 a!oL > M*A 3T1`a  ?,9`a* U*ZR?zZ? ~.Zr~*O:Z:$ zZ ~z? /zZ E CDzz? ~2I33>z? NE u<E /:Z:$z? ` Z ?,dZ 6` J?z?ZZ u`  [kBe-/r?= -z-y6|6|6|K::$ >xaiu#C(|Krx*333?a!)?=a!B o$#C#?rq!!o xaiu?,B(|-xrx*-x-z-zB?xaiu?,B(|-xrx*-x r0333?a!)?=LD-za!Q La!\ o$?,BBq!!o F//============================================================================= // TeamGiantManta. //============================================================================= class TeamGiantManta extends TeamManta; //FIXME - louder wingbeats, etc. w1W" : :$q!P!h  XBI8XSRPN,% w* z!!!q!q! [ #ݴ/*-(# cY*v B6]*'nssc1z(Z(T I$BK$Cq$TD\$D!";$?] Giant MantaA$= 7@7$B/$8Bn*M -' @[//============================================================================= // TeamGasbag. //============================================================================= class TeamGasbag extends TeamScriptedPawn; //----------------------------------------------------------------------------- // Gasbag variables. // Attack damage. var() byte PunchDamage, // Basic damage done by each punch. PoundDamage; // Basic damage done by pound. var(Sounds) sound Punch; var(Sounds) sound Pound; var(Sounds) sound PunchHit; var TeamGasBag ParentBag; var int numChildren; //----------------------------------------------------------------------------- // Gasbag functions. function Destroyed() { if ( ParentBag != None ) ParentBag.numChildren--; Super.Destroyed(); } function PreSetMovement() { bCanJump = true; bCanWalk = true; bCanSwim = false; bCanFly = true; bCanDuck = true; MinHitWall = -0.6; if (Intelligence > BRAINS_Reptile) bCanOpenDoors = true; if (Intelligence == BRAINS_Human) bCanDoSpecial = true; } function TryToDuck(vector duckDir, bool bReversed) { local vector HitLocation, HitNormal, Extent; local actor HitActor; //log("duck"); duckDir.Z = 0; if ( (Skill == 0) && (FRand() < 0.5) ) DuckDir *= -1; Extent.X = CollisionRadius; Extent.Y = CollisionRadius; Extent.Z = CollisionHeight; HitActor = Trace(HitLocation, HitNormal, Location + 100 * duckDir, Location, false, Extent); if (HitActor != None) { duckDir *= -1; HitActor = Trace(HitLocation, HitNormal, Location + 100 * duckDir, Location, false, Extent); } if (HitActor != None) return; //log("good duck"); Destination = Location + 150 * duckDir; Velocity = 400 * duckDir; AirSpeed *= 2.5; GotoState('TacticalMove', 'DoMove'); } function SetMovementPhysics() { SetPhysics(PHYS_Flying); } singular function Falling() { SetPhysics(PHYS_Flying); } function PlayWaiting() { local float decision; local float animspeed; animspeed = 0.3 + 0.5 * FRand(); decision = FRand(); if (!bool(NextAnim)) //pick first waiting animation NextAnim = 'Float'; LoopAnim(NextAnim, animspeed); ////log("Next brute waiting anim is "$nextanim); if (NextAnim == 'Float') { if (decision < 0.15) NextAnim = 'Fiddle'; } else if (NextAnim == 'Fiddle') { if (decision < 0.5) NextAnim = 'Float'; else if (decision < 0.65) NextAnim = 'Grab'; } else NextAnim = 'Float'; } function PlayPatrolStop() { PlayWaiting(); } function PlayWaitingAmbush() { PlayWaiting(); } function TweenToFighter(float tweentime) { TweenAnim('Fighter', tweentime); } function TweenToRunning(float tweentime) { if ( (AnimSequence == 'Belch') && IsAnimating() ) return; if ( (AnimSequence != 'Float') || !bAnimLoop ) TweenAnim('Float', tweentime); } function TweenToWalking(float tweentime) { if ( (AnimSequence != 'Float') || !bAnimLoop ) TweenAnim('Float', tweentime); } function TweenToWaiting(float tweentime) { TweenAnim('Float', tweentime); } function TweenToPatrolStop(float tweentime) { TweenAnim('Float', tweentime); } function PlayRunning() { if ( AnimSequence == 'Belch' ) LoopAnim('Float', -1.0/AirSpeed, 0.5, 0.4); else LoopAnim('Float', -1.0/AirSpeed,, 0.4); } function PlayWalking() { LoopAnim('Float', -1.0/AirSpeed,, 0.4); } function PlayThreatening() { local float decision; decision = FRand(); if ( decision < 0.7 ) PlayAnim('Float', 0.4, 0.4); else if ( decision < 0.8 ) PlayAnim('ThreatBelch', 0.4, 0.25); else { PlayThreateningSound(); TweenAnim('Fighter', 0.3); } } function PlayTurning() { LoopAnim('Float'); } function PlayDying(name DamageType, vector HitLocation) { PlaySound(Die, SLOT_Talk, 4 * TransientSoundVolume); if ( FRand() < 0.5 ) PlayAnim('Deflate', 0.7, 0.1); else PlayAnim('Dead2', 0.7, 0.1); } function PlayTakeHit(float tweentime, vector HitLoc, int damage) { if ( FRand() < 0.6 ) TweenAnim('TakeHit', tweentime); else TweenAnim('Hit2', 1.5 * tweentime); } function TweenToFalling() { TweenAnim('Float', 0.2); } function PlayInAir() { LoopAnim('Float'); } function PlayLanded(float impactVel) { PlayAnim('Float'); } function PlayVictoryDance() { PlayAnim('Pound', 0.6, 0.1); PlaySound(PunchHit, SLOT_Interact); } function PlayMeleeAttack() { local vector adjust; adjust = vect(0,0,0); adjust.Z = Target.CollisionHeight; Acceleration = AccelRate * Normal(Target.Location - Location + adjust); if (FRand() < 0.5) { PlaySound(Punch, SLOT_Interact); PlayAnim('TwoPunch'); } else { PlaySound(Pound, SLOT_Interact); PlayAnim('Pound'); }; } function PlayRangedAttack() { local vector adjust; adjust = vect(0,0,0); adjust.Z = Target.CollisionHeight + 20; Acceleration = AccelRate * Normal(Target.Location - Location + adjust); PlayAnim('Belch'); } function SpawnBelch() { spawn(RangedProjectile ,self,'',Location,AdjustAim(ProjectileSpeed, Location, 400, bLeadTarget, bWarnTarget)); } function PunchDamageTarget() { if (MeleeDamageTarget(PunchDamage, (PunchDamage * 1300 * Normal(Target.Location - Location)))) PlaySound(PunchHit, SLOT_Interact); } function PoundDamageTarget() { if (MeleeDamageTarget(PoundDamage, (PoundDamage * 800 * Normal(Target.Location - Location)))) PlaySound(PunchHit, SLOT_Interact); } function PlayMovingAttack() { if ( AnimSequence == 'Float' ) PlayAnim('Belch', 1.0, 0.2); else PlayAnim('Belch'); } State TacticalMove { ignores SeePlayer, HearNoise; function EndState() { AirSpeed = Default.AirSpeed; Super.EndState(); } } Bd&2 a&!d x]na a $ d*L s a $ 9e*2x ePw*!::$o$MM6- ::$o$cc::$o$ [f*[ o$ "g*i* k i!=a&!> a $Offf?a!L>333?ga!B?? h* &::$a!)333?$  j*E   $k*$(b#::$a!)333?=`N?a $a!P333?=`a!x333?= l*z +-::$a&!)z +a&!z  Ap*_q!t!y m*C *a!F !N x::$ua%!B !) -a&!)C !* -a&!*C  r*+̳ u! o*I &U-::$a&!)I +a&!I  (v*_۲U7w._*'r_-'._L?%a?(v! q*t*0a!=L>L?o$ s*E gN?::$/>o$a!=333?<a&!)E La&!E   b-8ba`_\,% Kw* z!!!q!w*q! u* [G+::$a!* >Ea!) > w*G+::$a!33 >Ea!)ٿ > x*5-::$a&!>+a!)? y* (::$a&!>&a!) z*|*l Aa$-::$a!` 333?=?a!c333?= }*{*e6za&!e Jla! L? A+~*Qa&!)L> B+Y a!) C+E+F"8 a!= D+@'qa!t?= F+4,_::$# a!t]':y ի<y zD a$ wG+I+N>cz _z`#fff?_?,z?,z_`?,`_uj qSի?j QaS h Sz`S'<rQ* rQ)w.Q*: .Q:$'QaS h SzS'rQ* rQ)w.Q*: .Q:$ S Y E\r/a0 EoF%Enn&E10 M+EFLGF?EwE*Ea/!].E.E!F?&?FGEEE&.G! *5L7@?a!}>?>Ja&!>: k KMn -H @&KwK*w.K* wK.K**.K-H-i '.K.K@@@.K@&KK- -i *! fB//============================================================================= // TeamFly. //============================================================================= class TeamFly extends TeamScriptedPawn; //----------------------------------------------------------------------------- // Fly variables. //----------------------------------------------------------------------------- // Fly functions. function PreSetMovement() { bCanJump = true; bCanWalk = true; bCanSwim = false; bCanFly = true; MinHitWall = -0.6; bCanOpenDoors = false; bCanDoSpecial = false; } function ZoneChange(ZoneInfo newZone) { local vector jumpDir; if ( newZone.bWaterZone ) { MoveTimer = -1.0; if ( (Enemy != None) && (Enemy.Location.Z < Location.Z) ) GotoState('TacticalMove', 'BackOff'); else Acceleration = Accelrate * vect(0,0,1); } } function SetMovementPhysics() { if (Enemy != None) SetPhysics(PHYS_Flying); else if (Physics != PHYS_Falling) SetPhysics(PHYS_Walking); } singular function Falling() { SetPhysics(PHYS_Flying); if (bIsPlayer) { PlayInAir(); return; } if (health > 0) SetFall(); } function PlayWaiting() { if ( Physics == PHYS_Walking ) TweenAnim('Waiting', 10.0); else LoopAnim('Flying', 0.75); } function PlayPatrolStop() { PlayWaiting(); } function PlayWaitingAmbush() { PlayWaiting(); } function PlayChallenge() { PlayAnim('Shoot1', 1.0, 0.1); } function TweenToFighter(float tweentime) { TweenAnim('Flying', tweentime); } function TweenToRunning(float tweentime) { if ( (AnimSequence != 'Flying') || !bAnimLoop ) TweenAnim('Flying', tweentime); } function TweenToWalking(float tweentime) { if (Physics == PHYS_Walking) TweenAnim('Walking', tweentime); else if ( (AnimSequence != 'Flying') || !bAnimLoop ) TweenAnim('Flying', tweentime); } function TweenToWaiting(float tweentime) { PlayAnim('Land', 0.2 + 0.5 * FRand()); SetPhysics(PHYS_Falling); } function TweenToPatrolStop(float tweentime) { TweenAnim('Flying', tweentime); } function PlayRunning() { LoopAnim('Flying'); } function PlayWalking() { if (Physics == PHYS_Walking) LoopAnim('Walking', -1.0/GroundSpeed,, 0.4); else LoopAnim('Flying'); } function PlayThreatening() { if ( FRand() < 0.8 ) LoopAnim('Flying'); else LoopAnim('Shoot1', 0.4); } function PlayTurning() { if (Physics == PHYS_Walking) LoopAnim('Walking'); else LoopAnim('Flying'); } function PlayDying(name DamageType, vector HitLocation) { PlaySound(Die, SLOT_Talk, 2.5 * TransientSoundVolume); PlayAnim('Dead', 0.7, 0.1); } function PlayTakeHit(float tweentime, vector HitLoc, int damage) { TweenAnim('TakeHit', tweentime); } function TweenToFalling() { TweenAnim('Flying', 0.2); } function PlayInAir() { LoopAnim('Flying'); } function PlayLanded(float impactVel) { PlayAnim('Land'); } function PlayVictoryDance() { if ( FRand() < 0.4 ) TweenToWaiting(0.25); else PlayAnim('Flying',1.0, 0.05); } function PlayMeleeAttack() { PlayAnim('Shoot1'); if ( MeleeDamageTarget(15, (15 * 1000.0 * Normal(Target.Location - Location))) ) PlaySound(Threaten, SLOT_Talk); //FIXME - stingdamage instead of projectile GotoState('TacticalMove', 'BackOff'); } function PlayRangedAttack() { local vector projStart; local vector adjust; PlayAnim('Shoot1'); /* adjust = vect(0,0,0); adjust.Z = Target.CollisionHeight + 20; Acceleration = AccelRate * Normal(Target.Location - Location + adjust); projStart = Location - 0.5 * CollisionHeight * vect(0,0,1); spawn(RangedProjectile ,self,'',projStart,AdjustAim(ProjectileSpeed, projStart, 400, false, false)); */ } function PlayMovingAttack() { PlayRangedAttack(); } state TacticalMove { ignores SeePlayer, HearNoise; BackOff: Acceleration = AccelRate * Normal(Location - Enemy.Location); Acceleration.Z *= 0.5; Destination = Location; Sleep(0.5); SetTimer(TimeBetweenAttacks, false); Goto('TacticalTick'); } state Roaming { function PickDestination() { GotoState('Wandering'); } Begin: GotoState('Wandering'); } O+~w B6P+P4xEtԝX1tX?$333?`$333?H$?hI$ BM$BK$pCq$Dj$ Apd\$zDT$!"L V=O;$>]FlyuH7$A/$@Aa$BP:Sp \//============================================================================= // TeamDevilFish. //============================================================================= class TeamDevilFish extends TeamScriptedPawn; //----------------------------------------------------------------------------- // RazorFish variables. // Attack damage. var() byte BiteDamage, // Basic damage done by bite. RipDamage; var bool bAttackBump; var(Sounds) sound bite; var(Sounds) sound rip; var float AirTime; //----------------------------------------------------------------------------- // RazorFish functions. function WhatToDoNext(name LikelyState, name LikelyLabel) { bStasis = true; Super.WhatToDoNext(LikelyState, LikelyLabel); } function ZoneChange(ZoneInfo newZone) { local vector start, checkpoint, HitNormal, HitLocation; local actor HitActor; if ( newZone.bWaterZone ) { AirTime = 0; setPhysics(PHYS_Swimming); } else { SetPhysics(PHYS_Falling); MoveTimer = -1.0; } } function Landed(vector HitNormal) { GotoState('Flopping'); Landed(HitNormal); } function PreSetMovement() { bCanJump = true; bCanWalk = false; bCanSwim = true; bCanFly = false; MinHitWall = -0.6; bCanOpenDoors = false; bCanDoSpecial = false; } function SetMovementPhysics() { if (Region.Zone.bWaterZone) SetPhysics(PHYS_Swimming); else { SetPhysics(PHYS_Falling); MoveTimer = -1.0; GotoState('Flopping'); } } //Azathoth - deleted AttiudeTo function PlayWaiting() { LoopAnim('Swimming', 0.1 + 0.3 * FRand()); } function PlayPatrolStop() { LoopAnim('Swimming', 0.1 + 0.3 * FRand()); } function PlayWaitingAmbush() { LoopAnim('Swimming', 0.1 + 0.3 * FRand()); } function TweenToFighter(float tweentime) { TweenAnim('Fighter', tweentime); } function TweenToRunning(float tweentime) { if ( (AnimSequence != 'Swimming') || !bAnimLoop ) TweenAnim('Swimming', tweentime); } function TweenToWalking(float tweentime) { if ( (AnimSequence != 'Swimming') || !bAnimLoop ) TweenAnim('Swimming', tweentime); } function TweenToWaiting(float tweentime) { PlayAnim('Swimming', 0.2 + 0.8 * FRand()); } function TweenToPatrolStop(float tweentime) { TweenAnim('Swimming', tweentime); } function PlayRunning() { LoopAnim('Swimming', -0.8/WaterSpeed,, 0.4); } function PlayWalking() { LoopAnim('Swimming', -0.8/WaterSpeed,, 0.4); } function PlayThreatening() { if ( FRand() < 0.5 ) PlayAnim('Swimming', 0.4); else PlayAnim('Fighter', 0.4); } function PlayTurning() { LoopAnim('Swimming', 0.8); } function PlayDying(name DamageType, vector HitLocation) { if ( Region.Zone.bWaterZone ) { PlaySound(Die, SLOT_Talk, 4 * TransientSoundVolume); PlayAnim('Dead1', 0.7, 0.1); } else TweenAnim('Breathing', 0.35); } function PlayTakeHit(float tweentime, vector HitLoc, int damage) { TweenAnim('TakeHit', tweentime); } function TweenToFalling() { TweenAnim('Flopping', 0.2); } function PlayInAir() { LoopAnim('Flopping', 0.7); } function PlayLanded(float impactVel) { TweenAnim('breathing', 0.2); } function PlayVictoryDance() { PlayAnim('ripper', 0.6, 0.1); } function PlayMeleeAttack() { local vector adjust; local float decision; adjust = vect(0,0,0.5) * FRand() * Target.CollisionHeight; Acceleration = AccelRate * Normal(Target.Location - Location + adjust); bAttackBump = false; if (AnimSequence == 'Grab1') { PlayAnim('ripper', 0.5 + 0.5 * FRand()); PlaySound(rip,SLOT_Interact,,,500); MeleeDamageTarget(RipDamage, vect(0,0,0)); Disable('Bump'); return; } decision = FRand(); PlaySound(bite,SLOT_Interact,,,500); if (decision < 0.3) { Disable('Bump'); PlayAnim('Grab1', 0.3); return; } Enable('Bump'); //log("Start Melee Attack"); if (decision < 0.55) { PlayAnim('Bite1', 0.3); } else if (decision < 0.8) { PlayAnim('Bite2', 0.3); } else { PlayAnim('Bite3', 0.3); } } state Waiting { function Landed(vector HitNormal) { GotoState('Flopping'); Landed(HitNormal); } } state TakeHit { ignores seeplayer, hearnoise, bump, hitwall; function Landed(vector HitNormal) { GotoState('Flopping'); Landed(HitNormal); } } state FallingState { ignores Bump, Hitwall, HearNoise, WarnTarget; function Landed(vector HitNormal) { GotoState('Flopping'); Landed(HitNormal); } } state Ambushing { function Landed(vector HitNormal) { GotoState('Flopping'); Landed(HitNormal); } } state MeleeAttack { ignores SeePlayer, HearNoise; singular function Bump(actor Other) { Disable('Bump'); if ( (AnimSequence == 'Bite1') || (AnimSequence == 'Bite2') || (AnimSequence == 'Bite3') ) MeleeDamageTarget(BiteDamage, (BiteDamage * 1000.0 * Normal(Target.Location - Location))); else return; bAttackBump = true; Velocity *= -0.5; Acceleration *= -1; if (Acceleration.Z < 0) Acceleration.Z *= -1; } function KeepAttacking() { if ( (Target == None) || ((Pawn(Target) != None) && (Pawn(Target).Health == 0)) ) GotoState('Attacking'); else if ( bAttackBump && (FRand() < 0.5) ) { SetTimer(TimeBetweenAttacks, false); GotoState('TacticalMove', 'NoCharge'); } } } State Flopping { ignores seeplayer, hearnoise, enemynotvisible, hitwall; function Timer() { AirTime += 1; if ( AirTime > 25 + 15 * FRand() ) { Health = -1; Died(None, 'suffocated', Location); return; } SetPhysics(PHYS_Falling); Velocity = 200 * VRand(); Velocity.Z = 170 + 200 * FRand(); DesiredRotation.Pitch = Rand(8192) - 4096; DesiredRotation.Yaw = Rand(65535); TweenAnim('Flopping', 0.1); } function ZoneChange( ZoneInfo NewZone ) { local rotator newRotation; if (NewZone.bWaterZone) { newRotation = Rotation; newRotation.Roll = 0; SetRotation(newRotation); SetPhysics(PHYS_Swimming); AirTime = 0; GotoState('Attacking'); } else SetPhysics(PHYS_Falling); } function Landed(vector HitNormal) { local rotator newRotation; SetPhysics(PHYS_None); SetTimer(0.3 + 0.3 * AirTime * FRand(), false); newRotation = Rotation; newRotation.Pitch = 0; newRotation.Roll = Rand(16384) - 8192; DesiredRotation.Pitch = 0; SetRotation(newRotation); PlaySound(land,SLOT_Interact,,,400); TweenAnim('Breathing', 0.3); } function AnimEnd() { if (Physics == PHYS_None) { if (AnimSequence == 'Breathing') { PlaySound(sound'breath1fs',SLOT_Interact,,,300); PlayAnim('Breathing'); } else TweenAnim('Breathing', 0.2); } else PlayAnim('Flopping', 0.7); } } state TacticalMove { function PickDestination(bool bNoCharge) { local vector pick, pickdir, enemydir,Y, minDest; local float Aggression, enemydist, minDist, strafeSize; local bool success; success = false; enemyDist = VSize(Location - Enemy.Location); Aggression = 2 * (CombatStyle + FRand()) - 1.0; if (enemyDist < CollisionRadius + Enemy.CollisionRadius + MeleeRange) Aggression -= 1; else if (enemyDist > FMax(VSize(OldLocation - Enemy.OldLocation), 240)) Aggression += 0.4 * FRand(); enemydir = (Enemy.Location - Location)/enemyDist; if ( !enemy.Region.Zone.bWaterZone ) enemydir.Z *= 0.5; minDist = FMin(160.0, 3*CollisionRadius); Y = (enemydir Cross vect(0,0,1)); strafeSize = FMin(1.0, (2 * Abs(Aggression) * FRand() - 0.2)); if (Aggression < 0) strafeSize *= -1; enemydir = enemydir * strafeSize; enemydir.Z = FMax(0,enemydir.Z); strafeSize = FMax(0.0, 1 - Abs(strafeSize)); pickdir = strafeSize * Y; pick = Location + (pickdir + enemydir) * (minDist + 500 * FRand()); minDest = Location + minDist * (pickdir + enemydir); if (pointReachable(minDest)) { success = true; Destination = pick; } if (!success) { pick = Location + (enemydir - pickdir) * (minDist + 500 * FRand()); pick.Z = Location.Z; minDest = Location + minDist * (enemydir - pickdir); if (pointReachable(minDest)) { success = true; Destination = pick; } } if (!success) { pick = Location - enemydir * (minDist + 500 * FRand()); pick.Z = Location.Z + 200 * FRand() - 100; } } function Bump(Actor Other) { Disable('Bump'); if (bAttackBump == true) bAttackBump = false; else if (Other == Enemy) { bReadyToAttack = true; Target = Enemy; GotoState('MeleeAttack'); } else if (Enemy.Health <= 0) GotoState('Attacking'); } } _Y+Q+BW 4H+p#[::$a!N!a!Bpq c\ի?q } ]&\%-5-qaY!\}  Nb6a&!b \+`|E]?/a0 `ba`-]]?&a?]`10w*.Y * VU+ayj::$a!N,>a!Fa `Wի? M]&WX-5-q??6M 6M aY!WM hZ+wV6VS6ST6T{ VSTS{ @ ZV0na!oL>L? AL@FE F D??LLD #::$w*D XN >->DL>wL*L>D>>wL*DL XN >D DD[+e+>#a J x =+::$6J 333?o$ a J I I g+`r*D!G!` r 6rvb rrw*`b`bw`*`` D!G!` Wb+H !O6 6 >6Co$6-X aHFի?,#?'rX o$W HpL C?U$]p\p-g-d An+_3 q!t W Wa+m+&qrxn#`6r333?o$ ;bq!!T^P q! U@v8-vAa!~ 333?>a$ bj+\ $k>C6 6?,6Co$6-_ a\Dի?,#?'r_ o$b  Qz8Q] {|E,% ] f!!!q!xx%q! bY?a&!D? Y i+E,S(8a$-'@u!X i( s+& t+u+v+w+r+y+x' rx+{+AP' |+}+kz++fV' @,A,J ~+YX'n?,Yl>a Ai!/a0 b hb R10a B, (-(o$v!X q+T,h-v! aa!x333?>aa $a!P333?aq!0L>-("66a+::$o$ KM H,) I,J,K,L,(G,i *;9i a/!\.i -q!h!M _+N 2hN-::N$__:N$r`N@NBf$*!w.N**.N*$SN AM,_*q!h!M O,N*N2!Pa!~>333?\NL>a!k >333?N>a!f >333?N?a!M >333?NL?a!N >333?a!P>333? R+A"OB6Q, Etttttt11tԝXԝXԝX111N] K XC$??$?I$ BE$zCpx\$@D!"F$pLV=O;$?] DevilfishuH7$ B/$A<$pBa$pBP:S a xP,S,",o$ R, '-2*# V, vZMr*w * b M b?c-x vr G' -        q!%'J -? @& a'( - - - - N -?, q!(' -  @& q!>U @, -{' q!!Z @, -{( q!!Z q!' ecu~Wpc-{ c- w* B>: c:$ L> `c ^U  W,dTSEw*a/!C w^/a0 h^%wh^&wh10/a0 r d,dd&10!!j  p @]//============================================================================= // TeamManta. //============================================================================= class TeamManta extends TeamScriptedPawn; //----------------------------------------------------------------------------- // Manta variables. // Attack damage. var() byte StingDamage, // Basic damage done by Sting. WhipDamage; // Basic damage done by whip. var bool bAttackBump; var bool bAvoidHit; var(Sounds) sound whip; var(Sounds) sound wingBeat; var(Sounds) sound sting; //----------------------------------------------------------------------------- // Manta functions. /* PreSetMovement() default for walking creature. Re-implement in subclass for swimming/flying capability */ function PreBeginPlay() { Super.PreBeginPlay(); if ( skill <= 1 ) Health = 0.6 * Health; if ( skill == 0 ) AttitudeToPlayer = ATTITUDE_Ignore; } function PreSetMovement() { MaxDesiredSpeed = 0.6 + 0.13 * skill; bCanJump = true; bCanWalk = true; bCanSwim = true; bCanFly = true; MinHitWall = -0.6; if (Intelligence > BRAINS_Reptile) bCanOpenDoors = true; if (Intelligence == BRAINS_Human) bCanDoSpecial = true; } function SetMovementPhysics() { if (Region.Zone.bWaterZone) SetPhysics(PHYS_Swimming); else SetPhysics(PHYS_Flying); } function PlayWaiting() { LoopAnim('Waiting', 0.1 + 0.5 * FRand()); } function PlayPatrolStop() { PlaySound(WingBeat, SLOT_Interact); LoopAnim('Fly', 0.4); } function PlayWaitingAmbush() { PlayWaiting(); } function PlayChallenge() { PlayAnim('Fly', 0.4, 0.1); } function TweenToFighter(float tweentime) { TweenAnim('Fly', tweentime); } function TweenToRunning(float tweentime) { if ( (AnimSequence != 'Fly') || !bAnimLoop ) TweenAnim('Fly', tweentime); } function TweenToWalking(float tweentime) { if ( (AnimSequence != 'Fly') || !bAnimLoop ) TweenAnim('Fly', tweentime); } function TweenToWaiting(float tweentime) { PlayAnim('Landing', 0.2 + 0.8 * FRand()); SetPhysics(PHYS_Falling); } function TweenToPatrolStop(float tweentime) { TweenAnim('Fly', tweentime); } function PlayRunning() { PlaySound(WingBeat, SLOT_Interact); LoopAnim('Fly', -1.0/AirSpeed,, 0.4); } function PlayWalking() { PlaySound(WingBeat, SLOT_Interact); LoopAnim('Fly', -1.0/AirSpeed,, 0.4); } function PlayThreatening() { if ( FRand() < 0.8 ) { PlaySound(WingBeat, SLOT_Interact); PlayAnim('Fly', 0.4); } else LoopAnim('ThreatSting', 0.4); } function PlayTurning() { if (FRand() < 0.5) TweenAnim('Fighter', 0.2); else { PlaySound(WingBeat, SLOT_Interact); LoopAnim('Fly', -1.0/AirSpeed,, 0.4); } } function PlayDying(name DamageType, vector HitLocation) { PlaySound(Die, SLOT_Talk, 4 * TransientSoundVolume); PlayAnim('Death', 0.7, 0.1); } function PlayTakeHit(float tweentime, vector HitLoc, int Damage) { TweenAnim('TakeHit', tweentime); } function TweenToFalling() { TweenAnim('Fly', 0.2); } function PlayInAir() { LoopAnim('Fly'); } function PlayLanded(float impactVel) { PlayAnim('Landing'); } function PlayVictoryDance() { PlayAnim('Whip', 0.6, 0.1); PlaySound(Threaten, SLOT_Talk); } function PlayMeleeAttack() { local vector adjust; adjust = vect(0,0,0.8) * Target.CollisionHeight; Acceleration = AccelRate * Normal(Target.Location - Location + adjust); Enable('Bump'); bAttackBump = false; //log("Start Melee Attack"); if (FRand() < 0.5) { PlayAnim('Sting'); PlaySound(Sting, SLOT_Interact); } else { PlayAnim('Whip'); PlaySound(Whip, SLOT_Interact); } } state MeleeAttack { ignores SeePlayer, HearNoise; singular function Bump(actor Other) { Disable('Bump'); if (AnimSequence == 'Whip') MeleeDamageTarget(WhipDamage, (WhipDamage * 1000.0 * Normal(Target.Location - Location))); else if (AnimSequence == 'Sting') MeleeDamageTarget(StingDamage, (StingDamage * 1000.0 * Normal(Target.Location - Location))); bAttackBump = true; Velocity *= -0.5; Acceleration *= -1; if (Acceleration.Z < 0) Acceleration.Z *= -1; } function KeepAttacking() { if (Target == None) GotoState('Attacking'); else if ( (Pawn(Target) != None) && (Pawn(Target).Health == 0) ) GotoState('Attacking'); else if (bAttackBump) { SetTimer(TimeBetweenAttacks, false); GotoState('TacticalMove', 'NoCharge'); } } } state Charging { ignores SeePlayer, HearNoise; function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType); if ( health <= 0 ) return; if (NextState == 'TakeHit') { if (AttitudeTo(Enemy) == ATTITUDE_Fear) { NextState = 'Retreating'; NextLabel = 'Begin'; } else if ( (FRand() < 3 * Damage/Default.Health) && ((Damage > 0.5 * Health) || (VSize(Location - Enemy.Location) > 150)) ) { bAvoidHit = true; NextState = 'TacticalMove'; NextLabel = 'NoCharge'; } else { NextState = 'Charging'; NextLabel = 'TakeHit'; } GotoState('TakeHit'); } } } state TacticalMove { ignores SeePlayer, HearNoise; function PickDestination(bool bNoCharge) { local vector pick, pickdir, enemydir,Y, minDest; local actor HitActor; local vector HitLocation, HitNormal, collSpec; local float Aggression, enemydist, minDist, strafeSize, MaxMove; if ( bAvoidHit && (FRand() < 0.7) ) MaxMove = 300; else MaxMove = 600; bAvoidHit = false; enemyDist = VSize(Location - Enemy.Location); Aggression = 2 * FRand() - 1.0; if (enemyDist < CollisionRadius + Enemy.CollisionRadius + 2 * MeleeRange) Aggression = FMin(0.0, Aggression); else if (enemyDist > FMax(VSize(OldLocation - Enemy.OldLocation), 240)) Aggression = FMax(0.0, Aggression); enemydir = (Enemy.Location - Location)/enemyDist; minDist = FMin(160.0, 5*CollisionRadius); Y = (enemydir Cross vect(0,0,1)); strafeSize = FMin(0.8, (2 * Abs(Aggression) * FRand() - 0.2)); if (Aggression <= 0) strafeSize *= -1; enemydir = enemydir * strafeSize; if (FRand() < 0.8) enemydir.Z = 1.5; else enemydir.Z = FMax(0,enemydir.Z); strafeSize = FMax(0.0, 1 - Abs(strafeSize)); pickdir = strafeSize * Y; pick = Location + (pickdir + enemydir) * (minDist + MaxMove * FRand()); pick.Z = Location.Z + 60 + 0.65 * MaxMove * FRand(); minDest = Location + minDist * Normal(pick - location); collSpec.X = CollisionRadius; collSpec.Y = CollisionRadius; collSpec.Z = CollisionHeight; HitActor = Trace(HitLocation, HitNormal, minDest, Location, false, collSpec); if ( HitActor == None ) { Destination = pick; return; } pick = Location + (enemydir - pickdir) * (minDist + MaxMove * FRand()); pick.Z = Location.Z + 60 + 0.5 * MaxMove * FRand(); minDest = Location + minDist * Normal(pick - location); HitActor = Trace(HitLocation, HitNormal, minDest, Location, false, collSpec); if ( HitActor == None ) { Destination = pick; return; } pick = Location - enemydir * (minDist + MaxMove * FRand()); pick.Z = Location.Z + 0.5 * MaxMove * FRand(); minDest = Location + Normal(pick - Location) * minDist; HitActor = Trace(HitLocation, HitNormal, minDest, Location, false, collSpec); if ( HitActor == None ) { Destination = pick; return; } if ( !bNoCharge && (enemyDist > 120) ) GotoState('Charging'); pick = MaxMove * FRand() * VRand(); pick.Z = FMin(Location.Z, pick.Z); Destination = pick; } function Bump(Actor Other) { Disable('Bump'); if (bAttackBump == true) bAttackBump = false; else if (Other == Enemy) { bReadyToAttack = true; Target = Enemy; GotoState('MeleeAttack'); } else if (Enemy.Health <= 0) GotoState('Attacking'); } } ],x-b(ba@rb*(a "6a 6ba+a bb-.b!/a0 || R10-bo$+r-*'~.lr~*Error - use Team creature factory to spawn Team monsters'#w-*-~-e~-~-~-~w6no newcreature?pw-*- - -2:-:$-o$' -//============================================================================= // TeamBrute. //============================================================================= class TeamBrute extends TeamScriptedPawn; //----------------------------------------------------------------------------- // Brute variables. // Attack damage. var() byte WhipDamage; // Basic damage done by pistol-whip. var bool bBerserk; var bool bLongBerserk; var() bool bTurret; // Doesn't move // Sounds var(Sounds) sound Footstep; var(Sounds) sound Footstep2; var(Sounds) sound PistolWhip; var(Sounds) sound GutShot; var(Sounds) sound PistolHit; var(Sounds) sound Die2; function PostBeginPlay() { Super.PostBeginPlay(); if (Skill > 1) bLeadTarget = true; if ( Skill == 0 ) ProjectileSpeed *= 0.85; else if ( Skill > 2 ) ProjectileSpeed *= 1.1; } //Azathoth deleted function eAttitude AttitudeToCreature(Pawn Other) function GoBerserk() { bLongBerserk = false; if ( (bBerserk || ((Health < 0.75 * Default.Health) && (FRand() < 0.65))) && (VSize(Location - Enemy.Location) < 500) ) bBerserk = true; else bBerserk = false; if ( bBerserk ) { AccelRate = 4 * AccelRate; GroundSpeed = 2.5 * Default.GroundSpeed; } } function PlayWaiting() { local float decision; local float animspeed; bReadyToAttack = true; animspeed = 0.3 + 0.5 * FRand(); //fixme - add to all creatures decision = FRand(); if ( AnimSequence == 'Sleep' ) { if ( decision < 0.07 ) { SetAlertness(0.0); PlayAnim('Breath2',animspeed, 0.4); return; } else { SetAlertness(-0.3); PlayAnim('Sleep', 0.3 + 0.3 * FRand()); return; } } else if ( AnimSequence == 'Breath2' ) { if ( decision < 0.2 ) { SetAlertness(-0.3); PlayAnim('Sleep',animspeed,0.4); return; } else if ( decision < 0.37 ) PlayAnim('StillLook', animspeed); else if ( decision < 0.55 ) PlayAnim('CockGun', animspeed); else PlayAnim('Breath2', 0.3 + 0.3 * FRand(), 0.4); } else if ( decision < 0.1 ) PlayAnim('StillLook', animspeed, 0.4); else PlayAnim('Breath2', 0.3 + 0.3 * FRand(), 0.4); if ( AnimSequence == 'StillLook' ) { SetAlertness(0.7); if ( !bQuiet && (FRand() < 0.7) ) PlayRoamingSound(); } else SetAlertness(0.0); } function PlayThreatening() { local float decision; decision = FRand(); if ( decision < 0.7 ) PlayAnim('Breath2', 0.4, 0.3); else if ( decision < 0.8 ) LoopAnim('PreCharg', 0.4, 0.25); else { PlayThreateningSound(); TweenAnim('Fighter', 0.3); } } function PlayPatrolStop() { local float decision; local float animspeed; animspeed = 0.5 + 0.4 * FRand(); //fixme - add to all creatures decision = FRand(); if ( AnimSequence == 'Breath2' ) { if ( decision < 0.4 ) PlayAnim('StillLook', animspeed); else if (decision < 0.6 ) PlayAnim('CockGun', animspeed); else PlayAnim('Breath2', animspeed); } else if ( decision < 0.2 ) PlayAnim('StillLook', animspeed); else PlayAnim('Breath2', animspeed); if ( AnimSequence == 'StillLook' ) { SetAlertness(0.7); if ( !bQuiet && (FRand() < 0.7) ) PlayRoamingSound(); } else SetAlertness(0.0); } function PlayWaitingAmbush() { bQuiet = true; PlayPatrolStop(); } function PlayChallenge() { PlayAnim('PreCharg', 0.7, 0.2); } function TweenToFighter(float tweentime) { TweenAnim('Fighter', tweentime); } function TweenToRunning(float tweentime) { if ( bBerserk ) TweenAnim('Charge', tweentime); if ( IsAnimating() && (AnimSequence == 'WalkFire') ) return; if (AnimSequence != 'Walk' || !bAnimLoop) TweenAnim('Walk', tweentime); } function TweenToWalking(float tweentime) { TweenAnim('Walk', tweentime); } function TweenToWaiting(float tweentime) { TweenAnim('Breath2', tweentime); } function TweenToPatrolStop(float tweentime) { TweenAnim('Breath2', tweentime); } function PlayRunning() { if (Focus == Destination) { LoopAnim('Walk', -1.1/GroundSpeed,,0.4); return; } LoopAnim('Walk', StrafeAdjust(),,0.3); } function PlayWalking() { LoopAnim('Walk', -1.1/GroundSpeed,,0.4); } function PlayTurning() { TweenAnim('Walk', 0.3); } function PlayBigDeath(name DamageType) { PlaySound(Die2, SLOT_Talk, 4 * TransientSoundVolume); PlayAnim('Dead2',0.7,0.1); } function PlayHeadDeath(name DamageType) { PlayAnim('Dead4',0.7,0.1); PlaySound(Die, SLOT_Talk, 4 * TransientSoundVolume); } function PlayLeftDeath(name DamageType) { PlayAnim('Dead2',0.7,0.1); PlaySound(Die,SLOT_Talk, 4 * TransientSoundVolume); } function PlayRightDeath(name DamageType) { PlayAnim('Dead3',0.7,0.1); PlaySound(Die,SLOT_Talk, 4 * TransientSoundVolume); } function PlayGutDeath(name DamageType) { PlayAnim('Dead1',0.7,0.1); PlaySound(Die,SLOT_Talk, 4 * TransientSoundVolume); } function PlayMovingAttack() { PlayAnim('WalkFire', 1.1); } function PlayVictoryDance() { PlayAnim('PreCharg', 0.7, 0.3); } function bool CanFireAtEnemy() { local vector HitLocation, HitNormal,X,Y,Z, projStart, EnemyDir, EnemyUp; local actor HitActor1, HitActor2; local float EnemyDist; EnemyDir = Enemy.Location - Location; EnemyDist = VSize(EnemyDir); EnemyUp = Enemy.CollisionHeight * vect(0,0,0.9); if ( EnemyDist > 300 ) { EnemyDir = 300 * EnemyDir/EnemyDist; EnemyUp = 300 * EnemyUp/EnemyDist; } GetAxes(Rotation,X,Y,Z); projStart = Location + 0.5 * CollisionRadius * X + 0.8 * CollisionRadius * Y + 0.4 * CollisionRadius * Z; HitActor1 = Trace(HitLocation, HitNormal, projStart + EnemyDir + EnemyUp, projStart, true); if ( (HitActor1 != Enemy) && (Pawn(HitActor1) != None) && (AttitudeTo(Pawn(HitActor1)) > ATTITUDE_Ignore) ) return false; projStart = Location + 0.5 * CollisionRadius * X - 0.8 * CollisionRadius * Y + 0.4 * CollisionRadius * Z; HitActor2 = Trace(HitLocation, HitNormal, projStart + EnemyDir + EnemyUp, projStart, true); if ( (HitActor2 == None) || (HitActor2 == Enemy) || ((Pawn(HitActor2) != None) && (AttitudeTo(Pawn(HitActor2)) <= ATTITUDE_Ignore)) ) return true; HitActor2 = Trace(HitLocation, HitNormal, projStart + EnemyDir, projStart , true); return ( (HitActor2 == None) || (HitActor2 == Enemy) || ((Pawn(HitActor2) != None) && (AttitudeTo(Pawn(HitActor2)) <= ATTITUDE_Ignore)) ); } function SpawnLeftShot() { FireProjectile( vect(1.2,0.7,0.4), 750); } function SpawnRightShot() { FireProjectile( vect(1.2,-0.7,0.4), 750); } function WhipDamageTarget() { if ( MeleeDamageTarget(WhipDamage, (WhipDamage * 1000.0 * Normal(Target.Location - Location))) ) PlaySound(PistolWhip, SLOT_Interact); } function Step() { if (FRand() < 0.6) PlaySound(FootStep, SLOT_Interact,,,2000); else PlaySound(FootStep2, SLOT_Interact,,,2000); } function GutShotTarget() { FireProjectile( vect(1.2,-0.55,0.0), 800); } function PlayMeleeAttack() { local float decision; decision = FRand(); If ( decision < 0.6 ) { PlaySound(PistolWhip, SLOT_Interact); PlayAnim('PistolWhip'); } else { PlaySound(PistolWhip, SLOT_Interact); PlayAnim('Punch'); } } function PlayRangedAttack() { //FIXME - if going to ranged attack need to // TweenAnim('StillFire', 0.2); //What I need is a tween into time for the PlayAnim() if ( (AnimSequence == 'T8') || (VSize(Target.Location - Location) > 230) ) { SpawnRightShot(); PlayAnim('StillFire'); } else PlayAnim('GutShot'); } state Attacking { ignores SeePlayer, HearNoise, Bump, HitWall; function ChooseAttackMode() { local eAttitude AttitudeToEnemy; local float Aggression; local pawn changeEn; if ( !bTurret ) { Super.ChooseAttackMode(); return; } if ((Enemy == None) || (Enemy.Health <= 0)) { if (Orders == 'Attacking') Orders = ''; GotoState('Waiting', 'TurnFromWall'); return; } if (AttitudeToEnemy == ATTITUDE_Threaten) { GotoState('Threatening'); return; } else if (!LineOfSightTo(Enemy)) { if ( (OldEnemy != None) && (AttitudeTo(OldEnemy) == ATTITUDE_Hate) && LineOfSightTo(OldEnemy) ) { changeEn = enemy; enemy = oldenemy; oldenemy = changeEn; } else { GotoState('StakeOut'); return; } } if (bReadyToAttack) { ////log("Attack!"); Target = Enemy; If (VSize(Enemy.Location - Location) <= (MeleeRange + Enemy.CollisionRadius + CollisionRadius)) GotoState('MeleeAttack'); else GotoState('RangedAttack'); return; } GotoState('RangedAttack', 'Challenge'); } } state Charging { ignores SeePlayer, HearNoise; function AnimEnd() { If ( bBerserk ) LoopAnim('Charge', -1.1/GroundSpeed,,0.5); else PlayCombatMove(); } function Timer() { if ( bBerserk && bLongBerserk && (FRand() < 0.3) ) { AccelRate = Default.AccelRate; GroundSpeed = Default.GroundSpeed; bBerserk = false; } bLongBerserk = bBerserk; Super.Timer(); } function BeginState() { GoBerserk(); Super.BeginState(); } function EndState() { if ( bBerserk ) { GroundSpeed = Default.GroundSpeed; AccelRate = Default.AccelRate; } Super.EndState(); } } state RangedAttack { ignores SeePlayer, HearNoise, Bump; function TweenToFighter(float TweenTime) { if ( AnimSequence == 'T8' ) return; if ( (GetAnimGroup(AnimSequence) == 'Hit') || (Skill > 3 * FRand()) || (VSize(Location - Target.Location) < 320) ) TweenAnim('Fighter', tweentime); else PlayAnim('T8', 1.0, 0.15); } } E//============================================================================= // TeamCow. //============================================================================= class TeamCow extends TeamScriptedPawn; var bool bForage; var() bool bHasBaby; var() bool bStayClose; var() float WanderRadius; var vector StartLocation; var TeamBabyCow baby; var Pawn ScaryGuy; var(Sounds) sound shake; var(Sounds) sound swish; var(Sounds) sound footstep; var float VoicePitch; function eAttitude AttitudeWithFear() { return ATTITUDE_Fear; } function eAttitude AttitudeToCreature(Pawn Other) { if ( Other.IsA('Cow') || Other.IsA('TeamCow') ) return ATTITUDE_Friendly; else if ( Other.IsA('Skaarj') || Other.IsA('TeamSkaarj') ) return ATTITUDE_Fear; else return ATTITUDE_Ignore; } function PostBeginPlay() { VoicePitch = 0.9 + 0.2 * FRand(); if ( TeamBabyCow(self) != None ) VoicePitch *= 1.4; if (bHasBaby) //add baby { Destination = Location; baby = Spawn(class 'TeamBabyCow',,, Location + vector(Rotation) * 1.5 * CollisionRadius); baby.mom = self; } Super.PostBeginPlay(); } function Step() { PlaySound(Footstep, SLOT_Interact, 0.012 * Mass,, 1000); } function PlayWaiting() { local float decision; local float animspeed; animspeed = 0.4 + 0.4 * FRand(); decision = FRand(); if (!bool(NextAnim)) //pick first waiting animation NextAnim = 'Breath'; if (decision < 0.3) NextAnim = 'Breath'; else if (decision < 0.6) { animspeed *= 0.6; NextAnim = 'Chew'; } else if (decision < 0.73) { NextAnim = 'Root'; } else if (decision < 0.8) { PlaySound(Roam, SLOT_Talk, 0.02 * Mass,,,VoicePitch); NextAnim = 'Poop'; } else if (decision < 0.9) { PlaySound(Shake, SLOT_Talk, 0.0083 * Mass); NextAnim = 'Shake'; } else { PlaySound(Swish, SLOT_Talk, 0.0083 * Mass); NextAnim = 'Swish'; } LoopAnim(NextAnim, animspeed); } function PlayPatrolStop() { PlayWaiting(); } function PlayWaitingAmbush() { PlayWaiting(); } function TweenToFighter(float tweentime) { TweenAnim('Breath', tweentime); } function TweenToRunning(float tweentime) { if (AnimSequence != 'Run' || !bAnimLoop) TweenAnim('Run', tweentime); } function TweenToWalking(float tweentime) { TweenAnim('Walk', tweentime); } function TweenToWaiting(float tweentime) { TweenAnim('Breath', tweentime); } function TweenToPatrolStop(float tweentime) { TweenAnim('Breath', tweentime); } function PlayRunning() { LoopAnim('Run', -1.0/GroundSpeed,,0.3); } function PlayWalking() { LoopAnim('Walk', -1.5/GroundSpeed,,0.3); } function PlayThreatening() { local float decision; local float animspeed; animspeed = 0.4 + 0.6 * FRand(); decision = FRand(); if (decision < 0.3) NextAnim = 'Breath'; else if (decision < 0.7) { PlaySound(Shake, SLOT_Talk, 0.0083 * Mass); NextAnim = 'Shake'; } else { PlaySound(Swish, SLOT_Talk, 0.0083 * Mass); NextAnim = 'Swish'; } LoopAnim(NextAnim, animspeed); } function PlayTurning() { TweenAnim('Walk', 0.3); } function PlayDying(name DamageType, vector HitLocation) { if ( FRand() < 0.6 ) PlaySound(Die, SLOT_Talk, 0.025 * Mass,,,VoicePitch); else PlaySound(sound'DeathC2c', SLOT_Talk, 0.025 * Mass,,,VoicePitch); if ( (Velocity.Z > 200) && (FRand() < 0.75) ) PlayAnim('Dead3', 0.7, 0.1); else if (FRand() < 0.5) PlayAnim('Dead', 0.7, 0.1); else PlayAnim('Dead2', 0.7, 0.1); } function TweenToFalling() { TweenAnim('BigHit', 0.5); } function PlayInAir() { TweenAnim('Run',0.5); } function PlayLanded(float impactVel) { TweenAnim('Landed', 0.1); } function PlayTakeHit(float tweentime, vector HitLoc, int damage) { if ( FRand() < 0.5 ) PlaySound(HitSound1, SLOT_Interact, 0.02 * Mass,,,VoicePitch); else PlaySound(HitSound2, SLOT_Interact, 0.02 * Mass,,,VoicePitch); if (Velocity.Z > 200 + 100 * FRand()) TweenAnim('BigHit', tweentime); else if ( FRand() < 0.5 ) TweenAnim('TakeHit2', tweentime); else TweenAnim('TakeHit', tweentime); } function PlayChallenge() { PlayAnim('Breath', 1.0, 0.12); } function PlayVictoryDance() { PlayAnim('Breath', 1.0, 0.12); } function PlayRangedAttack() { PlaySound(Roam, SLOT_Talk, 0.02 * Mass,,,VoicePitch); PlayAnim('Poop', 0.7); } /* Grazing - Cow version of wandering has longer pauses, and only starts when seeplayer Also - special support for moms and babies */ function Help(TeamCow Other) { //only used when grazing } state Grazing { function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType); if ( health <= 0 ) return; if ( NextState == 'TakeHit' ) { NextState = 'Attacking'; NextLabel = 'Begin'; GotoState('TakeHit'); } else EnemyAcquired(); } function Bump(actor Other) { if ( (Normal(Destination - Location) Dot Normal(Other.Location - Location)) > 0.8 ) MoveTimer = -1.0; if ( (Pawn(Other) != None) && SetEnemy(Pawn(Other)) ) EnemyAcquired(); Disable('Bump'); } function EnemyAcquired() { bReadyToAttack = True; PlayAcquisitionSound(); GotoState('Attacking'); } function Help(TeamCow Other) { if ( (Enemy != None) && (AttitudeTo(Enemy) < ATTITUDE_Ignore) ) return; Enemy = Other.Enemy; if (Enemy.bIsPlayer) AttitudeToPlayer = ATTITUDE_Hate; else Hated = Enemy; Aggressiveness = 1.0; GotoState('Attacking'); } function SetFall() { NextState = 'Grazing'; NextLabel = 'ContinueWander'; NextAnim = AnimSequence; GotoState('FallingState'); } function bool TestDirection(vector dir, out vector pick, bool bAlongWall) { local vector HitLocation, HitNormal; local float minDist, Dist; local actor HitActor; dir.Z = 0; dir = Normal(dir); minDist = FMin(180.0, 6*CollisionRadius); pick = Location + dir * (minDist + FRand() * 900); HitActor = Trace(HitLocation, HitNormal, pick, Location, false); Dist = VSize(HitLocation - Location); if ( (Dist < minDist) && (HitNormal.Z < 0.7) ) { if ( !bAlongWall ) return false; pick = HitLocation - dir + (HitNormal Cross vect(0,0,1)) * 5 * CollisionRadius; HitActor = Trace(HitLocation, HitNormal, pick , Location, false); if (HitActor != None) return false; } else pick = HitLocation - 4 * CollisionRadius * dir; return true; } function PickDestination() { local vector pickdir; local bool success; local float XY, dist; if ( (Baby != None) && (VSize(Baby.Location - Location) > 400) ) { Destination = Baby.Location; return; } // don't wander too far if ( bStayClose ) { pickDir = StartLocation - Location; dist = VSize(pickDir); if ( dist > WanderRadius ) { pickdir = pickDir/dist; if ( TestDirection(pickdir, Destination, true) ) { if (Baby != None) Baby.FollowMom(); return; } } } //Favor XY alignment pickdir.Z = 0; XY = FRand(); if (XY < 0.3) { pickdir.X = 1; pickdir.Y = 0; } else if (XY < 0.6) { pickdir.X = 0; pickdir.Y = 1; } else { pickdir.X = 2 * FRand() - 1; pickdir.Y = 2 * FRand() - 1; pickdir = Normal(pickdir); } success = TestDirection(pickdir, Destination, false); if (!success) success = TestDirection(-1 * pickdir, Destination, true); if (success) { if (Baby != None) Baby.FollowMom(); } else { Destination = Location; GotoState('Grazing', 'Turn'); } } function AnimEnd() { PlayPatrolStop(); } function SeePlayer(Actor SeenPlayer) { bForage = true; ScaryGuy = Pawn(SeenPlayer); if ( (Pawn(SeenPlayer).Health > 0) && SetEnemy(Pawn(SeenPlayer)) ) LastSeenPos = SeenPlayer.Location; Disable('SeePlayer'); SetTimer(7.0, false); } function timer() { Enable('SeePlayer'); bForage = false; } function SetTurn() { local float YawErr; if ( (Baby != None) && (FRand() < 0.35) ) Destination = Baby.Location; else if ( (ScaryGuy != None) && (FRand() < 0.5) ) Destination = ScaryGuy.Location; else Destination = Location + 20 * VRand(); DesiredRotation = rotator(Destination - Location); DesiredRotation.Yaw = DesiredRotation.Yaw & 65535; YawErr = (DesiredRotation.Yaw - (Rotation.Yaw & 65535)) & 65535; if ( (YawErr > 16384) && (YawErr < 49151) ) { if ( YawErr > 32768 ) DesiredRotation.Yaw = DesiredRotation.Yaw + 16384; else DesiredRotation.Yaw = DesiredRotation.Yaw - 16384; Destination = Location + 20 * vector(DesiredRotation); } } function BeginState() { MinHitWall = -0.2; StartLocation = Location; Enemy = None; SetAlertness(0.0); bReadyToAttack = false; bAvoidLedges = true; Disable('AnimEnd'); NextAnim = ''; JumpZ = -1; if (Enemy == None) { bForage = false; Disable('EnemyNotVisible'); Enable('SeePlayer'); } else { bForage = true; Enable('EnemyNotVisible'); Disable('SeePlayer'); } } function EndState() { if ( Enemy.bIsPlayer ) MakeNoise(1.0); JumpZ = Default.JumpZ; bAvoidLedges = false; MinHitWall = Default.MinHitWall; } Begin: //log(class$" Grazing"); Wander: if (!bForage) Goto('Graze'); WaitForLanding(); PickDestination(); TweenToWalking(0.2); FinishAnim(); PlayWalking(); Moving: Enable('Bump'); MoveTo(Destination, 0.4); Graze: Acceleration = vect(0,0,0); TweenAnim('Breath', 0.3); if (FRand() < 0.5) { FinishAnim(); PlayAnim('Root', 0.3 + 0.4*FRand()); } Enable('AnimEnd'); NextAnim = ''; Sleep(6 + 10 * FRand()); Disable('AnimEnd'); FinishAnim(); Goto('Wander'); ContinueWander: FinishAnim(); PlayWalking(); Goto('Wander'); Turn: Acceleration = vect(0,0,0); PlayTurning(); SetTurn(); TurnTo(Destination); Goto('Graze'); } b}//============================================================================= // TeamScriptedPawn. //============================================================================= class TeamScriptedPawn expands TeamCannon abstract; var(Pawn) class CarcassType; // Advanced AI attributes. var(AI) name TeamTag; var TeamScriptedPawn TeamLeader; var int Team; //this will be altered by MyTeam var int TeamID; var(Orders) name Orders; //orders a creature is carrying out // will be initial state, plus creature will attenmpt //to return to this state var(Orders) name OrderTag; // tag of object referred to by orders var actor OrderObject; // object referred to by orders (if applicable) var(Combat) float TimeBetweenAttacks; // seconds - modified by difficulty var name NextAnim; // used in states with multiple, sequenced animations var(Combat) float Aggressiveness; //0.0 to 1.0 (typically) var Pawn Hated; var(Combat) float ReFireRate; //chance of shooting multiple times in one attack var Pawn OldEnemy; var float RoamStartTime; var int numHuntPaths; var float HuntStartTime; var vector HidingSpot; var float WalkingSpeed; var(AI) name FirstHatePlayerEvent; // event when first hate player //AI flags var bool bReadyToAttack; // can attack again var(Combat) bool bHasRangedAttack; // can attack from beyond melee range var(Combat) bool bMovingRangedAttack; //can perform ranged attack while moving var bool bCanFire; //used by TacticalMove and Charging states var(AI) bool bQuiet; var bool bTeamSpeaking; var(AI) bool bTeamLeader; var(AI) bool bIgnoreFriends; //don't react to friend's noises (and make their enemy yours) var bool bCanSpeak; var bool bIsSpeaking; var bool bCanBePissed; var bool bCanDuck; var(AI) bool bHateWhenTriggered; var(Orders) bool bDelayedPatrol; var bool bStrafeDir; var(Combat) bool bIsWuss; // always takes hit var(Combat) bool bLeadTarget; // lead target with projectile attack var(Combat) bool bWarnTarget; // warn target when projectile attack var bool bFirstShot; var bool bCrouching; var bool bFirstHatePlayer; var bool bClearShot; var bool bSpecialGoal; var bool bChangeDir; // tactical move boolean var bool bMoraleBoosted; var bool bFiringPaused; var bool bSpecialPausing; var bool bGreenBlood; var bool bFrustrated; var bool bInitialFear; var(AI) bool bIsBoss; var(Orders) bool bNoWait; // Friendly creature no wait going to alarm var(Combat) class RangedProjectile; var(Combat) float ProjectileSpeed; var name LastPainAnim; var float LastPainTime; //Sounds var(Sounds) sound Acquire; var(Sounds) sound Fear; var(Sounds) sound Roam; var(Sounds) sound Threaten; function PreBeginPlay() { Super.PreBeginPlay(); if ( Level.Game.bVeryLowGore ) bGreenBlood = true; if ( Skill > 2 ) bLeadTarget = true; else if ( (Skill == 0) && (Health < 500) ) { bLeadTarget = false; ReFireRate = 0.75 * ReFireRate; } if ( bIsBoss ) Health = Health + 0.15 * Skill * Health; bInitialFear = (AttitudeToPlayer == ATTITUDE_Fear); } //Azathoth - needed to override Teamcannon shite function PostBeginPlay() { } simulated function Destroyed() { Super.Destroyed(); } simulated function Tick(float DeltaTime) { } function SetTeam(int TeamNum) { // MyTeam = TeamNum; } function bool SameTeamAs(int TeamNum) { return (Team == TeamNum); } function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { local int actualDamage; local bool bAlreadyDead; if ( Role < ROLE_Authority ) { log(self$" client damage type "$damageType$" by "$instigatedBy); return; } bAlreadyDead = (Health <= 0); if (Physics == PHYS_None) SetMovementPhysics(); if (Physics == PHYS_Walking) momentum.Z = FMax(momentum.Z, 0.4 * VSize(momentum)); if ( instigatedBy == self ) momentum *= 0.6; momentum = momentum/Mass; actualDamage = Level.Game.ReduceDamage(Damage, DamageType, self, instigatedBy); if ( bIsPlayer ) { if (ReducedDamageType == 'All') //God mode actualDamage = 0; else if (Inventory != None) //then check if carrying armor actualDamage = Inventory.ReduceDamage(actualDamage, DamageType, HitLocation); else actualDamage = Damage; } else if ( (InstigatedBy != None) && (InstigatedBy.IsA(Class.Name) || self.IsA(InstigatedBy.Class.Name)) ) ActualDamage = ActualDamage * FMin(1 - ReducedDamagePct, 0.35); else if ( (ReducedDamageType == 'All') || ((ReducedDamageType != '') && (ReducedDamageType == damageType)) ) actualDamage = float(actualDamage) * (1 - ReducedDamagePct); if ( Level.Game.DamageMutator != None ) Level.Game.DamageMutator.MutatorTakeDamage( ActualDamage, Self, InstigatedBy, HitLocation, Momentum, DamageType ); AddVelocity( momentum ); Health -= actualDamage; if (CarriedDecoration != None) DropDecoration(); if ( HitLocation == vect(0,0,0) ) HitLocation = Location; if (Health > 0) { if ( (instigatedBy != None) && (instigatedBy != Self) ) damageAttitudeTo(instigatedBy); PlayHit(actualDamage, hitLocation, damageType, Momentum); } else if ( !bAlreadyDead ) { //log(self$" died"); NextState = ''; PlayDeathHit(actualDamage, hitLocation, damageType, Momentum); if ( actualDamage > mass ) Health = -1 * actualDamage; if ( (instigatedBy != None) && (instigatedBy != Self) ) damageAttitudeTo(instigatedBy); Died(instigatedBy, damageType, HitLocation); } else { //Warn(self$" took regular damage "$damagetype$" from "$instigator$" while already dead"); // SpawnGibbedCarcass(); if ( bIsPlayer ) { HidePlayer(); GotoState('Dying'); } else Destroy(); } MakeNoise(1.0); } function StartDeactivate() { } function PlayDeactivate() { } function PlayActivate() { } function Name PickAnim() { } function Shoot() { } function string KillMessage( name damageType, pawn Other ) { local string message; message = Level.Game.CreatureKillMessage(damageType, Other); return (Other.PlayerReplicationInfo.PlayerName$message$namearticle$menuname); } //********************************************************************* /* Default TeamScriptedPawn location specific take hits - make sure pain frames are named right */ function PlayGutHit(float tweentime) { if ( (LastPainTime - Level.TimeSeconds < 0.3) && (LastPainAnim == 'GutHit') ) { if (FRand() < 0.5) TweenAnim('LeftHit', tweentime); else TweenAnim('RightHit', tweentime); } else TweenAnim('GutHit', tweentime); } function PlayHeadHit(float tweentime) { if ( (LastPainTime - Level.TimeSeconds < 0.3) && (LastPainAnim == 'HeadHit') ) { if (FRand() < 0.5) TweenAnim('LeftHit', tweentime); else TweenAnim('RightHit', tweentime); } else TweenAnim('HeadHit', tweentime); } function PlayLeftHit(float tweentime) { if ( (LastPainTime - Level.TimeSeconds < 0.3) && (LastPainAnim == 'LeftHit') ) TweenAnim('GutHit', tweentime); else TweenAnim('LeftHit', tweentime); } function PlayRightHit(float tweentime) { if ( (LastPainTime - Level.TimeSeconds < 0.3) && (LastPainAnim == 'RightHit') ) TweenAnim('GutHit', tweentime); else TweenAnim('RightHit', tweentime); } function bool StrafeFromDamage(vector momentum, float Damage,name DamageType, bool bFindDest); //********************************************************************** function PlayHit(float Damage, vector HitLocation, name damageType, vector Momentum) { local float rnd; local Bubble1 bub; local bool bOptionalTakeHit; local vector BloodOffset; local blood2 b; if (Damage > 1) //spawn some blood { if (damageType == 'Drowned') { bub = spawn(class 'Bubble1',,, Location + 0.7 * CollisionRadius * vector(ViewRotation) + 0.3 * EyeHeight * vect(0,0,1)); if (bub != None) bub.DrawScale = FRand()*0.06+0.04; } else if ( damageType != 'Corroded' ) { BloodOffset = 0.2 * CollisionRadius * Normal(HitLocation - Location); BloodOffset.Z = BloodOffset.Z * 0.5; b = spawn(class 'BloodBurst',,,hitLocation + BloodOffset, rotator(BloodOffset)); if ( bGreenBlood && (b != None) ) b.GreenBlood(); if ( Level.bHighDetailMode ) { if ( bGreenBlood ) spawn(class'GreenBloodPuff',,, hitLocation + BloodOffset); else spawn(class'BloodPuff',,, hitLocation + BloodOffset); } } } if ( (Weapon != None) && Weapon.bPointing && !bIsPlayer ) { bFire = 0; bAltFire = 0; } bOptionalTakeHit = bIsWuss || ( (Level.TimeSeconds - LastPainTime > 0.3 + 0.25 * skill) && (Damage * FRand() > 0.08 * Health) && (Skill < 3) && (GetAnimGroup(AnimSequence) != 'MovingAttack') && (GetAnimGroup(AnimSequence) != 'Attack') ); if ( (!bIsPlayer || (Weapon == None) || !Weapon.bPointing) && (bOptionalTakeHit || (Momentum.Z > 140) || (bFirstShot && (Damage > 0.015 * (skill + 6) * Health)) || (Damage * FRand() > (0.17 + 0.04 * skill) * Health)) ) { PlayTakeHitSound(Damage, damageType, 3); PlayHitAnim(HitLocation, Damage); } else if (NextState == 'TakeHit') { PlayTakeHitSound(Damage, damageType, 2); NextState = ''; } } function PlayHitAnim(vector HitLocation, float Damage) { bFirstShot = false; NextAnim = ''; NextState = 'TakeHit'; PlayTakeHit(0.08, hitLocation, Damage); } function PlayDeathHit(float Damage, vector HitLocation, name damageType, vector Momentum) { local Bubble1 bub; local BloodBurst b; if ( Region.Zone.bDestructive && (Region.Zone.ExitActor != None) ) Spawn(Region.Zone.ExitActor); if (HeadRegion.Zone.bWaterZone) { bub = spawn(class 'Bubble1',,, Location + 0.3 * CollisionRadius * vector(Rotation) + 0.8 * EyeHeight * vect(0,0,1)); if (bub != None) bub.DrawScale = FRand()*0.08+0.03; bub = spawn(class 'Bubble1',,, Location + 0.2 * CollisionRadius * VRand() + 0.7 * EyeHeight * vect(0,0,1)); if (bub != None) bub.DrawScale = FRand()*0.08+0.03; bub = spawn(class 'Bubble1',,, Location + 0.3 * CollisionRadius * VRand() + 0.6 * EyeHeight * vect(0,0,1)); if (bub != None) bub.DrawScale = FRand()*0.08+0.03; } if ( (damageType != 'Burned') && (damageType != 'Corroded') && (damageType != 'Drowned') && (damageType != 'Fell') ) { b = spawn(class 'BloodBurst',self,'', hitLocation); if ( bGreenBlood && (b != None) ) b.GreenBlood(); } } function PlayChallenge() { TweenToFighter(0.1); } function ZoneChange(ZoneInfo newZone) { local vector jumpDir; if ( newZone.bWaterZone ) { if (!bCanSwim) MoveTimer = -1.0; else if (Physics != PHYS_Swimming) { if (Physics != PHYS_Falling) PlayDive(); setPhysics(PHYS_Swimming); } } else if (Physics == PHYS_Swimming) { if ( bCanFly ) SetPhysics(PHYS_Flying); else { SetPhysics(PHYS_Falling); if ( bCanWalk && (Abs(Acceleration.X) + Abs(Acceleration.Y) > 0) && CheckWaterJump(jumpDir) ) JumpOutOfWater(jumpDir); } } } function JumpOutOfWater(vector jumpDir) { Falling(); Velocity = jumpDir * WaterSpeed; Acceleration = jumpDir * AccelRate; velocity.Z = 380; //set here so physics uses this for remainder of tick PlayOutOfWater(); bUpAndOut = true; } function bool Gibbed(name damageType) { if ( (damageType == 'decapitated') || (damageType == 'shot') ) return false; return ( !bIsBoss && (Mass < 500) && ((Health < -0.5 * (Default.Health + Mass)) || ((Health < -25 - 0.1 * (Default.Health + Mass) * (0.2 + FRand())) && (FRand() < 0.8))) ); } function SpawnGibbedCarcass() { local carcass carc; carc = Spawn(CarcassType); if ( carc != None ) { carc.Initfor(self); carc.ChunkUp(-1 * Health); } } function Carcass SpawnCarcass() { local carcass carc; carc = Spawn(CarcassType); if ( carc != None ) carc.Initfor(self); return carc; } function JumpOffPawn() { Velocity += (60 + CollisionRadius) * VRand(); Velocity.Z = 180 + CollisionHeight; SetPhysics(PHYS_Falling); bJumpOffPawn = true; SetFall(); } //----------------------------------------------------------------------------- // Sound functions function Speak() { //implemented in speaking subclasses } function SpeakTo(TeamScriptedPawn Other) { //implemented in speaking subclasses } function SpeakOrderTo(TeamScriptedPawn TeamMember) { //implemented in speaking subclasses } function PlayAcquisitionSound() { if (Acquire != None) PlaySound(Acquire, SLOT_Talk,, true); } function PlayFearSound() { if (Fear != None) PlaySound(Fear, SLOT_Talk,, true); } function PlayRoamingSound() { if ( (Threaten != None) && (FRand() < 0.4) ) PlaySound(Threaten, SLOT_Talk,, true); if (Roam != None) PlaySound(Roam, SLOT_Talk,, true); } function PlayThreateningSound() { if (Threaten == None) return; if (FRand() < 0.6) PlaySound(Threaten, SLOT_Talk,, true); else PlaySound(Acquire, SLOT_Talk,, true); } //============================================================================= // re-implement SetMovementPhysics() in subclass for flying and swimming creatures function SetMovementPhysics() { if (Physics == PHYS_Falling) return; SetPhysics(PHYS_Walking); } function FearThisSpot(Actor aSpot) { Acceleration = vect(0,0,0); MoveTimer = -1.0; } /* SetAlertness() Change creature's alertness, and appropriately modify attributes used by engine for determining seeing and hearing. SeePlayer() is affected by PeripheralVision, and also by SightRadius and the target's visibility HearNoise() is affected by HearingThreshold */ final function SetAlertness(float NewAlertness) { if ( Alertness != NewAlertness ) { PeripheralVision += 0.707 * (Alertness - NewAlertness); //Used by engine for SeePlayer() HearingThreshold += 0.5 * (Alertness - NewAlertness); //Used by engine for HearNoise() Alertness = NewAlertness; } } function WhatToDoNext(name LikelyState, name LikelyLabel) { bQuiet = false; Enemy = None; if ( OldEnemy != None ) { Enemy = OldEnemy; OldEnemy = None; GotoState('Attacking'); } else if (Orders == 'Patroling') GotoState('Patroling'); else if (Orders == 'Guarding') GotoState('Guarding'); else if ( Orders == 'Ambushing' ) GotoState('Ambushing','FindAmbushSpot'); else if ( (LikelyState != '') && (FRand() < 0.35) ) GotoState(LikelyState, LikelyLabel); else StartRoaming(); } // check who is roaming/wandering - turn off oldest if too many function StartRoaming() { local float oldestRoamTime; local pawn oldestRoamer, next; local int numRoamers; RoamStartTime = Level.TimeSeconds; oldestRoamTime = RoamStartTime; oldestRoamer = None; numRoamers = 0; next = Level.PawnList; while (next != None) { if ( (TeamScriptedPawn(next) != None) && !next.bIsPlayer && ((next.IsInState('Roaming')) || (next.IsInState('Wandering'))) ) { numRoamers++; if ( (TeamScriptedPawn(next).RoamStartTime < oldestRoamTime) || (oldestRoamer == None) ) { oldestRoamer = next; oldestRoamTime = TeamScriptedPawn(next).RoamStartTime; } } next = next.nextPawn; } if ( numRoamers > 4 ) oldestRoamer.GotoState('Waiting', 'TurnFromWall'); OrderObject = None; OrderTag = ''; GotoState('Roaming'); } function Bump(actor Other) { local vector VelDir, OtherDir; local float speed; if ( Enemy != None ) { if (Other == Enemy) { GotoState('MeleeAttack'); return; } else if ( (Pawn(Other) != None) && SetEnemy(Pawn(Other)) ) { GotoState('MeleeAttack'); return; } } else { if (Pawn(Other) != None) { AnnoyedBy(Pawn(Other)); if ( SetEnemy(Pawn(Other)) ) { bReadyToAttack = True; //can melee right away PlayAcquisitionSound(); GotoState('Attacking'); return; } } if ( TimerRate <= 0 ) setTimer(1.0, false); if ( bCanSpeak && (TeamScriptedPawn(Other) != None) && ((TeamLeader == None) || !TeamLeader.bTeamSpeaking) ) SpeakTo(TeamScriptedPawn(Other)); } speed = VSize(Velocity); if ( speed > 1 ) { VelDir = Velocity/speed; VelDir.Z = 0; OtherDir = Other.Location - Location; OtherDir.Z = 0; OtherDir = Normal(OtherDir); if ( (VelDir Dot OtherDir) > 0.8 ) { /*if ( Pawn(Other) == None ) { MoveTimer = -1.0; HitWall(-1 * OtherDir, Other); } */ Velocity.X = VelDir.Y; Velocity.Y = -1 * VelDir.X; Velocity *= FMax(speed, 280); } } Disable('Bump'); } singular function Falling() { if (bCanFly) { SetPhysics(PHYS_Flying); return; } //log(class$" Falling"); // SetPhysics(PHYS_Falling); //note - done by default in physics if (health > 0) SetFall(); } function SetFall() { if (Enemy != None) { NextState = 'Attacking'; //default NextLabel = 'Begin'; NextAnim = 'Fighter'; GotoState('FallingState'); } } function LongFall() { SetFall(); GotoState('FallingState', 'LongFall'); } function HearNoise(float Loudness, Actor NoiseMaker) { //log(class$" heard noise by "$NoiseMaker.class); if ( SetEnemy(NoiseMaker.instigator) ) LastSeenPos = 0.5 * (NoiseMaker.Location + VSize(NoiseMaker.Location - Location) * vector(Rotation)); } function SeePlayer(Actor SeenPlayer) { //log(class$" has line of sight to player"); if (SetEnemy(Pawn(SeenPlayer))) LastSeenPos = Enemy.Location; } /* FindBestPathToward() assumes the desired destination is not directly reachable, given the creature's intelligence, it tries to set Destination to the location of the best waypoint, and returns true if successful */ function bool FindBestPathToward(actor desired) { local Actor path; local bool success; if ( specialGoal != None) desired = specialGoal; path = None; if (Intelligence <= BRAINS_Reptile) path = FindPathToward(desired, true); else path = FindPathToward(desired); success = (path != None); if (success) { MoveTarget = path; Destination = path.Location; } return success; } function bool NeedToTurn(vector targ) { local int YawErr; DesiredRotation = Rotator(targ - location); DesiredRotation.Yaw = DesiredRotation.Yaw & 65535; YawErr = (DesiredRotation.Yaw - (Rotation.Yaw & 65535)) & 65535; if ( (YawErr < 4000) || (YawErr > 61535) ) return false; return true; } /* NearWall() returns true if there is a nearby barrier at eyeheight, and changes Focus to a suggested value */ function bool NearWall(float walldist) { local actor HitActor; local vector HitLocation, HitNormal, ViewSpot, ViewDist, LookDir; LookDir = vector(Rotation); ViewSpot = Location + BaseEyeHeight * vect(0,0,1); ViewDist = LookDir * walldist; HitActor = Trace(HitLocation, HitNormal, ViewSpot + ViewDist, ViewSpot, false); if ( HitActor == None ) return false; ViewDist = Normal(HitNormal Cross vect(0,0,1)) * walldist; if (FRand() < 0.5) ViewDist *= -1; HitActor = Trace(HitLocation, HitNormal, ViewSpot + ViewDist, ViewSpot, false); if ( HitActor == None ) { Focus = Location + ViewDist; return true; } ViewDist *= -1; HitActor = Trace(HitLocation, HitNormal, ViewSpot + ViewDist, ViewSpot, false); if ( HitActor == None ) { Focus = Location + ViewDist; return true; } Focus = Location - LookDir * 300; return true; } final function FireProjectile(vector StartOffset, float Accuracy) { local vector X,Y,Z, projStart; MakeNoise(1.0); GetAxes(Rotation,X,Y,Z); projStart = Location + StartOffset.X * CollisionRadius * X + StartOffset.Y * CollisionRadius * Y + StartOffset.Z * CollisionRadius * Z; spawn(RangedProjectile ,self,'',projStart,AdjustAim(ProjectileSpeed, projStart, Accuracy, bLeadTarget, bWarnTarget)); } function StopFiring() { bFire = 0; bAltFire = 0; SetTimer((0.75 + 0.5 * FRand()) * TimeBetweenAttacks, false); } function FireWeapon() { local float rating; local int bUseAltMode; if( Weapon!=None ) { Weapon.RateSelf(bUseAltMode); ViewRotation = Rotation; if ( bUseAltMode > 0 ) { bFire = 0; bAltFire = 1; Weapon.AltFire(1.0); } else { bFire = 1; bAltFire = 0; Weapon.Fire(1.0); } PlayFiring(); } } function PlayFiring(); /* Adjust the aim at target. - add aim error (base on skill - FIXME). - adjust up or down if barrier */ function rotator AdjustToss(float projSpeed, vector projStart, int aimerror, bool leadTarget, bool warnTarget) { //FIXME- implement return AdjustAim(projSpeed, projStart, aimerror, leadTarget, warnTarget); } function rotator AdjustAim(float projSpeed, vector projStart, int aimerror, bool leadTarget, bool warnTarget) { local rotator FireRotation; local vector FireSpot; local actor HitActor; local vector HitLocation, HitNormal; if ( Target == None ) Target = Enemy; if ( Target == None ) return Rotation; if ( !Target.IsA('Pawn') ) return rotator(Target.Location - Location); FireSpot = Target.Location; aimerror = aimerror * (1 - 10 * ((Normal(Target.Location - Location) Dot Normal((Target.Location + 0.5 * Target.Velocity) - (Location + 0.5 * Velocity))) - 1)); aimerror = aimerror * (2.4 - 0.5 * (skill + FRand())); if (leadTarget && (projSpeed > 0)) { FireSpot += FMin(1, 0.7 + 0.6 * FRand()) * (Target.Velocity * VSize(Target.Location - ProjStart)/projSpeed); HitActor = Trace(HitLocation, HitNormal, FireSpot, ProjStart, false); if (HitActor != None) FireSpot = 0.5 * (FireSpot + Target.Location); } HitActor = self; //so will fail first check unless shooting at feet if ( bIsPlayer && (Location.Z + 19 >= Target.Location.Z) && Target.IsA('Pawn') && (Weapon != None) && Weapon.bSplashDamage && (0.5 * (skill - 1) > FRand()) ) { // Try to aim at feet HitActor = Trace(HitLocation, HitNormal, FireSpot - vect(0,0,80), FireSpot, false); if ( HitActor != None ) { FireSpot = HitLocation + vect(0,0,3); HitActor = Trace(HitLocation, HitNormal, FireSpot, ProjStart, false); } else HitActor = self; } if ( HitActor != None ) { //try middle FireSpot.Z = Target.Location.Z; HitActor = Trace(HitLocation, HitNormal, FireSpot, ProjStart, false); } if( HitActor != None ) { ////try head FireSpot.Z = Target.Location.Z + 0.9 * Target.CollisionHeight; HitActor = Trace(HitLocation, HitNormal, FireSpot, ProjStart, false); } if ( (HitActor != None) && (Target == Enemy) ) { FireSpot = LastSeenPos; if ( Location.Z >= LastSeenPos.Z ) FireSpot.Z -= 0.5 * Enemy.CollisionHeight; if ( Weapon != None ) { HitActor = Trace(HitLocation, HitNormal, FireSpot, ProjStart, false); if ( HitActor != None ) { bFire = 0; bAltFire = 0; SetTimer(TimeBetweenAttacks, false); } } } FireRotation = Rotator(FireSpot - ProjStart); FireRotation.Yaw = FireRotation.Yaw + 0.5 * (Rand(2 * aimerror) - aimerror); if (warnTarget && Pawn(Target) != None) Pawn(Target).WarnTarget(self, projSpeed, vector(FireRotation)); FireRotation.Yaw = FireRotation.Yaw & 65535; if ( (Abs(FireRotation.Yaw - (Rotation.Yaw & 65535)) > 8192) && (Abs(FireRotation.Yaw - (Rotation.Yaw & 65535)) < 57343) ) { if ( (FireRotation.Yaw > Rotation.Yaw + 32768) || ((FireRotation.Yaw < Rotation.Yaw) && (FireRotation.Yaw > Rotation.Yaw - 32768)) ) FireRotation.Yaw = Rotation.Yaw - 8192; else FireRotation.Yaw = Rotation.Yaw + 8192; } viewRotation = FireRotation; return FireRotation; } function WarnTarget(Pawn shooter, float projSpeed, vector FireDir) { local float enemyDist; local eAttitude att; local vector X,Y,Z, enemyDir; if ( health <= 0 ) return; att = AttitudeTo(shooter); if ( (att == ATTITUDE_Ignore) || (att == ATTITUDE_Threaten) ) { if ( intelligence >= BRAINS_Mammal ) damageAttitudeTo(shooter); if (att == ATTITUDE_Ignore) return; } // AI controlled creatures may duck if not falling if ( !bCanDuck || (Enemy == None) || (Physics == PHYS_Falling) || (Physics == PHYS_Swimming) ) return; if ( bIsPlayer ) { if ( FRand() > 0.33 * skill ) return; } else if ( FRand() > 0.55 + 0.15 * skill ) return; // and projectile time is long enough enemyDist = VSize(shooter.Location - Location); if (enemyDist/projSpeed < 0.11 + 0.15 * FRand()) return; // only if tight FOV GetAxes(Rotation,X,Y,Z); enemyDir = (shooter.Location - Location)/enemyDist; if ((enemyDir Dot X) < 0.8) return; if ( (FireDir Dot Y) > 0 ) { Y *= -1; TryToDuck(Y, true); } else TryToDuck(Y, false); } function TryToDuck(vector DuckDir, bool bReversed) { //implemented in subclasses that can duck } /* TryToCrouch() See if far enough away, and geometry favorable for crouching */ function bool TryToCrouch() { local float ViewDist; local actor HitActor; local vector HitLocation, HitNormal, ViewSpot, StartSpot, ViewDir, Dir2D; bCrouching = false; if ( Enemy == None ) return false; ViewDist = VSize(Location - Enemy.Location); if ( ViewDist < 400 ) return false; if ( FRand() < 0.3 ) return true; ViewSpot = Enemy.Location + Enemy.BaseEyeHeight * vect(0,0,1); StartSpot = Location - CollisionHeight * vect(0,0,0.5); ViewDir = (ViewSpot - StartSpot)/ViewDist; Dir2D = ViewDir; Dir2D.Z = 0; if ( (Dir2D Dot Vector(Rotation)) < 0.8 ) return false; HitActor = Trace(HitLocation, HitNormal, StartSpot + 100 * ViewDir ,StartSpot, false); if ( HitActor == None ) return false; bCrouching = true; return true; } // Can Stake Out - check if I can see my current Destination point, and so can enemy function bool CanStakeOut() { local vector HitLocation, HitNormal; local actor HitActor; if ( (Physics == PHYS_Flying) && !bCanStrafe ) return false; if ( VSize(Enemy.Location - LastSeenPos) > 800 ) return false; HitActor = Trace(HitLocation, HitNormal, LastSeenPos, Location + EyeHeight * vect(0,0,1), false); if ( HitActor == None ) { HitActor = Trace(HitLocation, HitNormal, LastSeenPos , Enemy.Location + Enemy.BaseEyeHeight * vect(0,0,1), false); return (HitActor == None); } return false; } function TriggerFirstHate() { local actor A; bFirstHatePlayer = true; if ( FirstHatePlayerEvent != '' ) foreach allactors(class'Actor', A, FirstHatePlayerEvent) A.Trigger(self, enemy); } function bool SetEnemy( Pawn NewEnemy ) { local bool result; local eAttitude newAttitude, oldAttitude; local bool noOldEnemy; local float newStrength; if ( (NewEnemy == Self) || (NewEnemy == None) || (NewEnemy.Health <= 0) ) return false; if ( !bCanWalk && !bCanFly && !NewEnemy.FootRegion.Zone.bWaterZone ) return false; if ( !NewEnemy.bIsPlayer && (TeamScriptedPawn(NewEnemy) == None) && (ScriptedPawn(NewEnemy) == None) ) return false; //Azathoth - added this to stop monsters reacting to spectators if ( NewEnemy.bIsPlayer && NewEnemy.PlayerReplicationInfo.bIsSpectator ) return false; noOldEnemy = (Enemy == None); result = false; newAttitude = AttitudeTo(NewEnemy); //log ("Enemy is "$Enemy); if ( !noOldEnemy ) { if (Enemy == NewEnemy) return true; //Azathoth - edited for TSP else if ( NewEnemy.IsA('TeamScriptedPawn') && (TeamScriptedPawn(NewEnemy).Team != Team) ) { OldEnemy = Enemy; Enemy = NewEnemy; result = true; } else if ( newAttitude == ATTITUDE_Friendly ) { if ( bIgnoreFriends ) return false; if ( (NewEnemy.Enemy != None) && (NewEnemy.Enemy.Health > 0) ) { if ( NewEnemy.Enemy.bIsPlayer && (NewEnemy.AttitudeToPlayer < AttitudeToPlayer) ) AttitudeToPlayer = NewEnemy.AttitudeToPlayer; if ( AttitudeTo(NewEnemy.Enemy) < AttitudeTo(Enemy) ) { OldEnemy = Enemy; Enemy = NewEnemy.Enemy; result = true; } } } else { oldAttitude = AttitudeTo(Enemy); if ( (newAttitude < oldAttitude) || ( (newAttitude == oldAttitude) && ((VSize(NewEnemy.Location - Location) < VSize(Enemy.Location - Location)) || !LineOfSightTo(Enemy)) ) ) { if ( bIsPlayer && Enemy.IsA('PlayerPawn') && !NewEnemy.IsA('PlayerPawn') ) { newStrength = relativeStrength(NewEnemy); if ( (newStrength < 0.2) && (relativeStrength(Enemy) < FMin(0, newStrength)) && (IsInState('Hunting')) && (Level.TimeSeconds - HuntStartTime < 5) ) result = false; else { result = true; OldEnemy = Enemy; Enemy = NewEnemy; } } else { result = true; OldEnemy = Enemy; Enemy = NewEnemy; } } } } else if ( newAttitude < ATTITUDE_Ignore ) { result = true; Enemy = NewEnemy; } else if ( newAttitude == ATTITUDE_Friendly ) //your enemy is my enemy { //log("noticed a friend"); if ( NewEnemy.IsA('TeamScriptedPawn') && (TeamScriptedPawn(NewEnemy).Team != Team) ) { Enemy = NewEnemy; result = true; } if (bIgnoreFriends) return false; //Azathoth hopefully stop scriptwarning if ( NewEnemy.bIsPlayer ) return false; if ( (NewEnemy.Enemy != None) && (NewEnemy.Enemy.Health > 0) ) { result = true; //log("his enemy is my enemy"); Enemy = NewEnemy.Enemy; if (Enemy.bIsPlayer) AttitudeToPlayer = TeamScriptedPawn(NewEnemy).AttitudeToPlayer; else if ( (TeamScriptedPawn(NewEnemy) != None) && (TeamScriptedPawn(NewEnemy).Hated == Enemy) ) Hated = Enemy; } } if ( result ) { //log(class$" has new enemy - "$enemy.class); LastSeenPos = Enemy.Location; LastSeeingPos = Location; EnemyAcquired(); if ( !bFirstHatePlayer && Enemy.bIsPlayer && (FirstHatePlayerEvent != '') ) TriggerFirstHate(); } else if ( NewEnemy.bIsPlayer && (NewAttitude < ATTITUDE_Threaten) ) OldEnemy = NewEnemy; return result; } function Killed(pawn Killer, pawn Other, name damageType) { local Pawn aPawn; local TeamScriptedPawn ScriptedOther; local bool bFoundTeam; if ( Health <= 0 ) return; if (Other.bIsPlayer) bCanBePissed = true; ScriptedOther = TeamScriptedPawn(Other); if ( (TeamTag != '') && (ScriptedOther != None) && (ScriptedOther.TeamTag == TeamTag) ) { if ( ScriptedOther.bTeamLeader ) TeamTag = ''; else if ( ScriptedOther.TeamID < TeamID ) TeamID--; else if ( bTeamLeader ) { aPawn = Level.PawnList; while ( aPawn != None ) { if ( (TeamScriptedPawn(aPawn) != None) && (TeamScriptedPawn(aPawn) != self) && (TeamScriptedPawn(aPawn).TeamTag == TeamTag) ) { bFoundTeam = true; break; } aPawn = aPawn.nextPawn; } if ( !bFoundTeam ) { bTeamLeader = false; TeamTag = ''; } } } if ( OldEnemy == Other ) OldEnemy = None; if ( Enemy == Other ) { Enemy = None; if ( (Killer == self) && (OldEnemy == None) ) { aPawn = Level.PawnList; while ( aPawn != None ) { if ( (aPawn.IsA('PlayerPawn') || aPawn.IsA('TeamScriptedPawn')) && (VSize(Location - aPawn.Location) < 500) && CanSee(aPawn) ) { if ( SetEnemy(aPawn) ) { GotoState('Attacking'); return; } } aPawn = aPawn.nextPawn; } Target = Other; GotoState('VictoryDance'); } else GotoState('Attacking'); } } function damageAttitudeTo(pawn Other) { local eAttitude OldAttitude; if ( (Other == Self) || (Other == None) || (FlockPawn(Other) != None) ) return; if( Other.bIsPlayer ) //change attitude to player { //FIXME - also frenzy or run away against non-players if ( (Health < 30) && (Aggressiveness * FRand() > 0.5) ) { AttitudeToPlayer = ATTITUDE_Frenzy; Aggressiveness = 1.0; } else if (AttitudeToPlayer == ATTITUDE_Ignore) AttitudeToPlayer = ATTITUDE_Hate; else if (AttitudeToPlayer == ATTITUDE_Threaten) AttitudeToPlayer = ATTITUDE_Hate; else if (AttitudeToPlayer == ATTITUDE_Friendly) AttitudeToPlayer = ATTITUDE_Threaten; } else { OldAttitude = AttitudeToCreature(Other); if (OldAttitude > ATTITUDE_Ignore ) return; else if ( OldAttitude > ATTITUDE_Frenzy ) { //log(class$" hates "$Other.class); Hated = Other; } } SetEnemy(Other); } function EnemyAcquired() { //log(Class$" just acquired an enemy - no action"); } /* RelativeStrength() returns a value indicating the relative strength of other 0.0 = equal to self > 0 stronger than self < 0 weaker than self Since the result will be compared to the creature's aggressiveness, it should be on the same order of magnitude (-1 to 1) Assess based on health and weapon */ function float RelativeStrength(Pawn Other) { local float compare; local int adjustedStrength, adjustedOther; local int bTemp; adjustedStrength = health; adjustedOther = 0.5 * (Other.health + Other.Default.Health); compare = 0.01 * float(adjustedOther - adjustedStrength); if ( Intelligence == BRAINS_Human ) { if ( Weapon != None ) { compare -= (Weapon.RateSelf(bTemp) - 0.3); if ( bIsPlayer && (Weapon.AIRating < 0.3) ) { compare += 0.2; if ( (Other.Weapon != None) && (Other.Weapon.AIRating >= 0.3) ) compare += 0.3; } } if ( Other.Weapon != None ) compare += (Other.Weapon.RateSelf(bTemp) - 0.3); } //log(other.class$" relative strength to "$class$" is "$compare); return compare; } /* AttitudeTo() Returns the creature's attitude towards another Pawn */ function eAttitude AttitudeTo(Pawn Other) { if (Other.bIsPlayer) { if (Team == Other.PlayerReplicationInfo.Team) //Azathoth - HACKHACK return ATTITUDE_Friendly; else if (Team != Other.PlayerReplicationInfo.Team) return ATTITUDE_Hate;//Azathoth - yet another hack return AttitudeToPlayer; } else if (Hated == Other) { if (RelativeStrength(Other) >= Aggressiveness) return AttitudeWithFear(); else return ATTITUDE_Hate; } else if ( (TeamTag != '') && (TeamScriptedPawn(Other) != None) && (TeamTag == TeamScriptedPawn(Other).TeamTag) ) return ATTITUDE_Friendly; else return AttitudeToCreature(Other); } /* AttitudeWithFear() may fear other, unless near home */ function eAttitude AttitudeWithFear() { local vector HitLocation, HitNormal; local actor HitActor; if ( Homebase(home) == None ) { CombatStyle -= 1.0; return ATTITUDE_Hate; } else if ( VSize(home.Location - Location) < Homebase(home).extent ) { HitActor = Trace( HitLocation, HitNormal, home.Location, Location, false); if (HitActor == None) return ATTITUDE_Hate; } return ATTITUDE_Fear; } /* AttitudeToCreature Typically implemented in subclass */ function eAttitude AttitudeToCreature(Pawn Other) { local TeamScriptedPawn TSPawn; if(Other.IsA('TeamScriptedPawn')) { TSPawn=TeamScriptedPawn(Other); if (TSPawn.Team==Team) { return ATTITUDE_Friendly; } else { return ATTITUDE_Hate; } } else return ATTITUDE_Ignore; } /* Annoyed by another pawn, typically after bumping into it (only when not already fighting) */ function AnnoyedBy(Pawn Other) { if ( !bCanBePissed || Other.bIsPlayer || (Enemy != None) || (Aggressiveness < 0.4) || (AttitudeTo(Other) != ATTITUDE_Ignore) || (FRand() > 0.2) ) return; Hated = Other; } function bool ChooseTeamAttackFor(TeamScriptedPawn TeamMember) { if ( (Enemy == None) && (TeamMember.Enemy != None) && LineOfSightTo(TeamMember) ) { if (SetEnemy(TeamMember.Enemy)) MakeNoise(1.0); } // speak order if ( !bTeamSpeaking ) SpeakOrderTo(TeamMember); // set CombatStyle and Aggressiveness of TeamMember if ( TeamMember == Self ) { ChooseLeaderAttack(); return true; } if ( TeamMember.bReadyToAttack ) { ////log("Attack!"); TeamMember.Target = TeamMember.Enemy; If (VSize(Enemy.Location - Location) <= (TeamMember.MeleeRange + TeamMember.Enemy.CollisionRadius + TeamMember.CollisionRadius)) { TeamMember.GotoState('MeleeAttack'); return true; } else if (TeamMember.bMovingRangedAttack || (TeamMember.TeamID == 1) ) TeamMember.SetTimer(TimeBetweenAttacks, False); else if (TeamMember.bHasRangedAttack && (TeamMember.bIsPlayer || TeamMember.Enemy.bIsPlayer) && TeamMember.CanFireAtEnemy() ) { if ( !TeamMember.bIsPlayer || (3 * FRand() > Skill) ) { TeamMember.GotoState('RangedAttack'); return true; } } } if ( !TeamMember.bHasRangedAttack || (TeamMember.TeamID == 1) ) TeamMember.GotoState('Charging'); else if ( TeamMember.TeamID == 2 ) { TeamMember.bStrafeDir = true; TeamMember.GotoState('TacticalMove', 'NoCharge'); } else if ( TeamMember.TeamID == 3 ) { TeamMember.bStrafeDir = false; TeamMember.GotoState('TacticalMove', 'NoCharge'); } else TeamMember.GotoState('TacticalMove'); return true; } function ChooseLeaderAttack() { if (bReadyToAttack && !bMovingRangedAttack) GotoState('RangedAttack'); else GotoState('TacticalMove', 'NoCharge'); } function bool MeleeDamageTarget(int hitdamage, vector pushdir) { local vector HitLocation, HitNormal, TargetPoint; local actor HitActor; // check if still in melee range If ( (VSize(Target.Location - Location) <= MeleeRange * 1.4 + Target.CollisionRadius + CollisionRadius) && ((Physics == PHYS_Flying) || (Physics == PHYS_Swimming) || (Abs(Location.Z - Enemy.Location.Z) <= FMax(CollisionHeight, Enemy.CollisionHeight) + 0.5 * FMin(CollisionHeight, Enemy.CollisionHeight))) ) { HitActor = Trace(HitLocation, HitNormal, Enemy.Location, Location, false); if ( HitActor != None ) return false; Target.TakeDamage(hitdamage, Self,HitLocation, pushdir, 'hacked'); return true; } return false; } function bool CanFireAtEnemy() { local vector HitLocation, HitNormal, EnemyDir, EnemyUp; local actor HitActor; local float EnemyDist; EnemyDir = Enemy.Location - Location; EnemyDist = VSize(EnemyDir); EnemyUp = Enemy.CollisionHeight * vect(0,0,0.9); if ( EnemyDist > 300 ) { EnemyDir = 300 * EnemyDir/EnemyDist; EnemyUp = 300 * EnemyUp/EnemyDist; } HitActor = Trace(HitLocation, HitNormal, Location + EnemyDir + EnemyUp, Location, true); if ( (HitActor == None) || (HitActor == Enemy) || ((Pawn(HitActor) != None) && (AttitudeTo(Pawn(HitActor)) <= ATTITUDE_Ignore)) ) return true; HitActor = Trace(HitLocation, HitNormal, Location + EnemyDir, Location, true); return ( (HitActor == None) || (HitActor == Enemy) || ((Pawn(HitActor) != None) && (AttitudeTo(Pawn(HitActor)) <= ATTITUDE_Ignore)) ); } function PlayMeleeAttack() { log(self$" Error - PlayMeleeAttack should be implemented in subclass"); } function PlayRangedAttack() { log(self$" Error - PlayRangedAttack should be implemented in subclass"); } function PlayCombatMove() { if ( bMovingRangedAttack && bReadyToAttack && bCanFire && !NeedToTurn(Enemy.Location) ) { Target = Enemy; PlayMovingAttack(); if ( FRand() > 0.5 * (0.5 + skill * 0.25 + ReFireRate) ) { bReadyToAttack = false; SetTimer(TimeBetweenAttacks * (1.0 + FRand()),false); } } else { if ( !bReadyToAttack && (TimerRate == 0.0) ) SetTimer(0.7, false); PlayRunning(); } } function float StrafeAdjust() { local vector Focus2D, Loc2D, Dest2D; local float strafemag; Focus2D = Focus; Focus2D.Z = 0; Loc2D = Location; Loc2D.Z = 0; Dest2D = Destination; Dest2D.Z = 0; strafeMag = Abs( Normal(Focus2D - Loc2D) dot Normal(Dest2D - Loc2D) ); return ((strafeMag - 2.0)/GroundSpeed); } function Trigger( actor Other, pawn EventInstigator ) { local Pawn currentEnemy; if ( (Other == Self) || (Health <= 0) ) return; if ( bHateWhenTriggered ) { if ( EventInstigator.bIsPlayer) AttitudeToPlayer = ATTITUDE_Hate; else Hated = EventInstigator; } currentEnemy = Enemy; SetEnemy(EventInstigator); if (Enemy != currentEnemy) { PlayAcquisitionSound(); GotoState('Attacking'); } } //********************************************************************************** //Base Monster AI auto state StartUp { function InitAmbushLoc() { local Ambushpoint newspot; local float i; local rotator newRot; i = 1.0; foreach AllActors( class 'Ambushpoint', newspot, tag ) { if ( !newspot.taken ) { i = i + 1; if (FRand() < 1.0/i) OrderObject = newspot; } } if (OrderObject != None) Ambushpoint(OrderObject).Accept(self,None); } function InitPatrolLoc() { local Patrolpoint newspot; /* IMPLEMENT by Walking throught patrol */ } function SetHome() { local NavigationPoint aNode; aNode = Level.NavigationPointList; while ( aNode != None ) { if ( aNode.IsA('HomeBase') && (aNode.tag == tag) ) { home = HomeBase(aNode); return; } aNode = aNode.nextNavigationPoint; } } function SetTeamTSP() { local Pawn aPawn; local bool bFoundTeam; if (bTeamLeader) { TeamLeader = self; return; } TeamID = 1; aPawn = Level.PawnList; while ( aPawn != None ) { if ( (TeamScriptedPawn(aPawn) != None) && (aPawn != self) && (TeamScriptedPawn(aPawn).TeamTag == TeamTag) ) { if ( TeamScriptedPawn(aPawn).bTeamLeader ) { bFoundTeam = true; TeamLeader = TeamScriptedPawn(aPawn); } if ( TeamScriptedPawn(aPawn).TeamID >= TeamID ) TeamID = TeamScriptedPawn(aPawn).TeamID + 1; } aPawn = aPawn.nextPawn; } if ( !bFoundTeam ) TeamTag = ''; //didn't find a team leader, so no team } function SetAlarm() { local Pawn aPawn, currentWinner; local float i; currentWinner = self; i = 1.0; aPawn = Level.PawnList; while ( aPawn != None ) { if ( aPawn.IsA('TeamScriptedPawn') && (TeamScriptedPawn(aPawn).SharedAlarmTag == SharedAlarmTag) ) { TeamScriptedPawn(aPawn).SharedAlarmTag = ''; i += 1; if (FRand() < 1.0/i) currentWinner = aPawn; } aPawn = aPawn.nextPawn; } TeamScriptedPawn(currentWinner).AlarmTag = SharedAlarmTag; SharedAlarmTag = ''; } function BeginState() { SetMovementPhysics(); if (Physics == PHYS_Walking) SetPhysics(PHYS_Falling); } function TeamToggle() { //Azathoth - Toggle Team for Assault (Hopefully) local Assault Test; //variable definition Team=MyTeam; foreach AllActors(class'Assault', Test) { if (MyTeam==0) { //log("TeamChangeDefend"); Team=Test.Defender.TeamIndex; } else if (MyTeam==1) { //log("TeamChangeAttack"); Team=Test.Attacker.TeamIndex; } } } Begin: SetHome(); if (SharedAlarmTag != '') SetAlarm(); if (TeamTag != '') SetTeamTSP(); TeamToggle(); //Azathoth - my function if (Orders == 'Guarding') { OrderObject = Spawn(class 'GuardPoint'); if (OrderTag != '') Tag = OrderTag; //so will be triggered if guarded object is touched } else if (!bFixedStart) { if (Orders == 'Patroling') InitPatrolLoc(); else if (Orders == 'Ambushing') InitAmbushLoc(); } if (Orders != '') { if (Orders == 'Attacking') { Orders = ''; if (enemy != None) GotoState('Attacking'); else StartRoaming(); } else if ( bDelayedPatrol && (Orders == 'Patroling') ) GotoState('Patroling', 'DelayedPatrol'); else GotoState(Orders); if ( Physics == PHYS_Falling ) SetFall(); else SetMovementPhysics(); } else GotoState('Waiting'); } state Waiting { function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType); if ( health <= 0 ) return; if ( Enemy != None ) LastSeenPos = Enemy.Location; if (NextState == 'TakeHit') { NextState = 'Attacking'; NextLabel = 'Begin'; GotoState('TakeHit'); } else if ( Enemy != None ) GotoState('Attacking'); } function Bump(actor Other) { //log(Other.class$" bumped "$class); if (Pawn(Other) != None) { if (Enemy == Other) bReadyToAttack = True; //can melee right away SetEnemy(Pawn(Other)); } if ( TimerRate <= 0 ) setTimer(1.5, false); Disable('Bump'); } function Timer() { Enable('Bump'); } function EnemyAcquired() { GotoState('Acquisition', 'PlayOut'); } function AnimEnd() { PlayWaiting(); bStasis = true; } function Landed(vector HitNormal) { SetPhysics(PHYS_None); } function BeginState() { Enemy = None; bStasis = false; Acceleration = vect(0,0,0); SetAlertness(0.0); } TurnFromWall: if ( NearWall(2 * CollisionRadius + 50) ) { PlayTurning(); TurnTo(Focus); } Begin: TweenToWaiting(0.4); bReadyToAttack = false; DesiredRotation = rot(0,0,0); DesiredRotation.Yaw = Rotation.Yaw; SetRotation(DesiredRotation); if (Physics != PHYS_Falling) SetPhysics(PHYS_None); KeepWaiting: NextAnim = ''; } state Roaming { ignores EnemyNotVisible; function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType); if ( health <= 0 ) return; if ( Enemy != None ) { LastSeenPos = Enemy.Location; if ( NextState == 'TakeHit' ) { NextState = 'Attacking'; //default NextLabel = 'Begin'; GotoState('TakeHit'); } else GotoState('Attacking'); } } function FearThisSpot(Actor aSpot) { Destination = Location + 120 * Normal(Location - aSpot.Location); GotoState('Wandering', 'Moving'); } function Timer() { Enable('Bump'); } function Bump(Actor Other) { if ( FRand() < 0.03) GotoState('Wandering'); else Super.Bump(Other); } function SetFall() { NextState = 'Roaming'; NextLabel = 'ContinueRoam'; NextAnim = AnimSequence; GotoState('FallingState'); } function EnemyAcquired() { GotoState('Acquisition'); } function HitWall(vector HitNormal, actor Wall) { if (Physics == PHYS_Falling) return; if ( Wall.IsA('Mover') && Mover(Wall).HandleDoor(self) ) { bSpecialGoal = true; if ( SpecialPause > 0 ) Acceleration = vect(0,0,0); GotoState('Roaming', 'Moving'); return; } Focus = Destination; if (PickWallAdjust()) GotoState('Roaming', 'AdjustFromWall'); else MoveTimer = -1.0; } function PickDestination() { local Actor path; if ((OrderObject == None) || actorReachable(OrderObject)) { numHuntPaths = 0; OrderObject = FindRandomDest(); if ( OrderObject != None ) GotoState('Roaming', 'Pausing'); else GotoState('Wandering'); return; } numHuntPaths++; if ( numHuntPaths > 80 ) GotoState('Wandering'); if (SpecialGoal != None) path = FindPathToward(SpecialGoal); else if (OrderObject != None) path = FindPathToward(OrderObject); else path = None; if (path != None) { MoveTarget = path; Destination = path.Location; } else GotoState('Wandering'); } function BeginState() { SpecialGoal = None; bSpecialGoal = false; SpecialPause = 0.0; Enemy = None; SetAlertness(0.2); bReadyToAttack = false; } Begin: //log(class$" Roaming"); Roam: TweenToWalking(0.15); NextAnim = ''; WaitForLanding(); PickDestination(); FinishAnim(); PlayWalking(); Moving: if (SpecialPause > 0.0) { Acceleration = vect(0,0,0); TweenToPatrolStop(0.3); Sleep(SpecialPause); SpecialPause = 0.0; TweenToWalking(0.1); FinishAnim(); PlayWalking(); } MoveToward(MoveTarget, WalkingSpeed); if ( bSpecialGoal ) { bSpecialGoal = false; Goto('Roam'); } Acceleration = vect(0,0,0); TweenToPatrolStop(0.3); FinishAnim(); NextAnim = ''; Pausing: Acceleration = vect(0,0,0); PlayPatrolStop(); FinishAnim(); if ( !bQuiet && (FRand() < 0.3) ) PlayRoamingSound(); Goto('Roam'); ContinueRoam: FinishAnim(); PlayWalking(); Goto('Roam'); AdjustFromWall: StrafeTo(Destination, Focus); Destination = Focus; Goto('Moving'); } state Wandering { ignores EnemyNotVisible; function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType); if ( health <= 0 ) return; if ( Enemy != None ) LastSeenPos = Enemy.Location; if ( NextState == 'TakeHit' ) { NextState = 'Attacking'; NextLabel = 'Begin'; GotoState('TakeHit'); } else GotoState('Attacking'); } function Timer() { Enable('Bump'); } function SetFall() { NextState = 'Wandering'; NextLabel = 'ContinueWander'; NextAnim = AnimSequence; GotoState('FallingState'); } function EnemyAcquired() { GotoState('Acquisition'); } function HitWall(vector HitNormal, actor Wall) { if (Physics == PHYS_Falling) return; if ( Wall.IsA('Mover') && Mover(Wall).HandleDoor(self) ) { if ( SpecialPause > 0 ) Acceleration = vect(0,0,0); GotoState('Wandering', 'Pausing'); return; } Focus = Destination; if (PickWallAdjust()) GotoState('Wandering', 'AdjustFromWall'); else MoveTimer = -1.0; } function bool TestDirection(vector dir, out vector pick) { local vector HitLocation, HitNormal, dist; local float minDist; local actor HitActor; minDist = FMin(150.0, 4*CollisionRadius); pick = dir * (minDist + (450 + 12 * CollisionRadius) * FRand()); HitActor = Trace(HitLocation, HitNormal, Location + pick + 1.5 * CollisionRadius * dir , Location, false); if (HitActor != None) { pick = HitLocation + (HitNormal - dir) * 2 * CollisionRadius; HitActor = Trace(HitLocation, HitNormal, pick , Location, false); if (HitActor != None) return false; } else pick = Location + pick; dist = pick - Location; if (Physics == PHYS_Walking) dist.Z = 0; return (VSize(dist) > minDist); } function PickDestination() { local vector pick, pickdir; local bool success; local float XY; //Favor XY alignment XY = FRand(); if (XY < 0.3) { pickdir.X = 1; pickdir.Y = 0; } else if (XY < 0.6) { pickdir.X = 0; pickdir.Y = 1; } else { pickdir.X = 2 * FRand() - 1; pickdir.Y = 2 * FRand() - 1; } if (Physics != PHYS_Walking) { pickdir.Z = 2 * FRand() - 1; pickdir = Normal(pickdir); } else { pickdir.Z = 0; if (XY >= 0.6) pickdir = Normal(pickdir); } success = TestDirection(pickdir, pick); if (!success) success = TestDirection(-1 * pickdir, pick); if (success) Destination = pick; else GotoState('Wandering', 'Turn'); } function AnimEnd() { PlayPatrolStop(); } function FearThisSpot(Actor aSpot) { Destination = Location + 120 * Normal(Location - aSpot.Location); } function BeginState() { Enemy = None; SetAlertness(0.2); bReadyToAttack = false; Disable('AnimEnd'); NextAnim = ''; bCanJump = false; } function EndState() { if (JumpZ > 0) bCanJump = true; } Begin: //log(class$" Wandering"); Wander: TweenToWalking(0.15); WaitForLanding(); PickDestination(); FinishAnim(); PlayWalking(); Moving: Enable('HitWall'); MoveTo(Destination, WalkingSpeed); Pausing: Acceleration = vect(0,0,0); if ( NearWall(2 * CollisionRadius + 50) ) { PlayTurning(); TurnTo(Focus); } if (FRand() < 0.3) PlayRoamingSound(); Enable('AnimEnd'); NextAnim = ''; TweenToPatrolStop(0.2); Sleep(1.0); Disable('AnimEnd'); FinishAnim(); Goto('Wander'); ContinueWander: FinishAnim(); PlayWalking(); if ( !bQuiet && (FRand() < 0.3) ) PlayRoamingSound(); if (FRand() < 0.2) Goto('Turn'); Goto('Wander'); Turn: Acceleration = vect(0,0,0); PlayTurning(); TurnTo(Location + 20 * VRand()); Goto('Pausing'); AdjustFromWall: StrafeTo(Destination, Focus); Destination = Focus; Goto('Moving'); } //Azathoth- ?TeamCannonStates auto state Idle { function BeginState() { GotoState('StartUp'); } } state DeActivated { } state DamagedState { } state ActiveCannon { } state TrackWarhead { } state GameEnded { } //end Teamcannon stuff State Patroling { function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType); if ( health <= 0 ) return; LastSeenPos = Enemy.Location; if (NextState == 'TakeHit') { NextState = 'Attacking'; NextLabel = 'Begin'; GotoState('TakeHit'); } else if ( Enemy != None ) GotoState('Attacking'); } function SetFall() { NextState = 'Patroling'; NextLabel = 'ResumePatrol'; NextAnim = AnimSequence; GotoState('FallingState'); } function HitWall(vector HitNormal, actor Wall) { if (Physics == PHYS_Falling) return; if ( Wall.IsA('Mover') && Mover(Wall).HandleDoor(self) ) { if ( SpecialPause > 0 ) Acceleration = vect(0,0,0); GotoState('Patroling', 'SpecialNavig'); return; } Focus = Destination; if (PickWallAdjust()) GotoState('Patroling', 'AdjustFromWall'); else MoveTimer = -1.0; } function Trigger( actor Other, pawn EventInstigator ) { if ( bDelayedPatrol ) { if ( bHateWhenTriggered ) { if ( EventInstigator.bIsPlayer) AttitudeToPlayer = ATTITUDE_Hate; else Hated = EventInstigator; } GotoState('Patroling', 'Patrol'); } else Global.Trigger(Other, EventInstigator); } function Timer() { Enable('Bump'); } function AnimEnd() { PlayPatrolStop(); } function EnemyAcquired() { //log(Class$" just acquired an enemy"); GotoState('Acquisition'); } function PickDestination() { local Actor path; path = None; if (SpecialGoal != None) path = FindPathToward(SpecialGoal); else if ( OrderObject != None ) path = FindPathToward(OrderObject); if (path != None) { MoveTarget = path; Destination = path.Location; } else OrderObject = None; } function FindNextPatrol() { local PatrolPoint pat; if ( (PatrolPoint(OrderObject) != None) && (PatrolPoint(OrderObject).nextPatrol == OrderTag) ) OrderObject = PatrolPoint(OrderObject).NextPatrolPoint; else { foreach AllActors( class 'Patrolpoint', pat, OrderTag ) { OrderObject = pat; return; } } } function BeginState() { SpecialGoal = None; SpecialPause = 0.0; Enemy = None; NextAnim = ''; Disable('AnimEnd'); SetAlertness(0.0); bReadyToAttack = (FRand() < 0.3 + 0.2 * skill); } AdjustFromWall: StrafeTo(Destination, Focus); Destination = Focus; MoveTo(Destination); Goto('MoveToPatrol'); ResumePatrol: if (MoveTarget != None) { PlayWalking(); MoveToward(MoveTarget, WalkingSpeed); Goto('ReachedPatrol'); } else Goto('Patrol'); Begin: sleep(0.1); Patrol: //FIXME -add stasis mode? - also set random start point in roam area WaitForLanding(); FindNextPatrol(); Disable('AnimEnd'); if (PatrolPoint(OrderObject) != None) { ////log("Move to next patrol point"); if ( !bQuiet && (FRand() < 0.4) ) PlayRoamingSound(); TweenToWalking(0.3); FinishAnim(); PlayWalking(); numHuntPaths = 0; MoveToPatrol: if (actorReachable(OrderObject)) MoveToward(OrderObject, WalkingSpeed); else { PickDestination(); if (OrderObject != None) { SpecialNavig: if (SpecialPause > 0.0) { Acceleration = vect(0,0,0); TweenToPatrolStop(0.3); Sleep(SpecialPause); SpecialPause = 0.0; TweenToWalking(0.1); FinishAnim(); PlayWalking(); } numHuntPaths++; MoveToward(MoveTarget, WalkingSpeed); if ( numHuntPaths < 30 ) Goto('MoveToPatrol'); else Goto('GiveUp'); } else Goto('GiveUp'); } ReachedPatrol: ////log("Got to patrol point "$OrderTag); OrderTag = Patrolpoint(OrderObject).Nextpatrol; ////log("Next patrol point "$OrderTag); if ( Patrolpoint(OrderObject).pausetime > 0.0 ) { ////log("Pause patrol"); Acceleration = vect(0,0,0); TweenToFighter(0.2); FinishAnim(); PlayTurning(); TurnTo(Location + (Patrolpoint(OrderObject)).lookdir); if ( Patrolpoint(OrderObject).PatrolAnim != '') { TweenAnim( Patrolpoint(OrderObject).PatrolAnim, 0.3); FinishAnim(); Patrolpoint(OrderObject).AnimCount = Patrolpoint(OrderObject).numAnims; While ( Patrolpoint(OrderObject).AnimCount > 0 ) { Patrolpoint(OrderObject).AnimCount--; if (Patrolpoint(OrderObject).PatrolSound != None ) PlaySound( Patrolpoint(OrderObject).PatrolSound ); PlayAnim(Patrolpoint(OrderObject).PatrolAnim); FinishAnim(); } } else { TweenToPatrolStop(0.3); FinishAnim(); Enable('AnimEnd'); NextAnim = ''; PlayPatrolStop(); ////log("stop here for "$(Patrolpoint(OrderObject)).pausetime); Sleep((Patrolpoint(OrderObject)).pausetime); Disable('AnimEnd'); FinishAnim(); } } Goto('Patrol'); } GiveUp: //log(self$" gave up patrol"); Acceleration = vect(0,0,0); TweenToPatrolStop(0.3); FinishAnim(); DelayedPatrol: Enable('AnimEnd'); PlayPatrolStop(); } state Guarding { function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { //Azathoth if (Enemy != None) LastSeenPos = Enemy.Location; Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType); if ( health <= 0 ) return; if (NextState == 'TakeHit') { NextState = 'Attacking'; NextLabel = 'Begin'; GotoState('TakeHit'); } else if ( Enemy != None ) GotoState('Attacking'); } function Timer() { Enable('Bump'); } function EnemyAcquired() { GotoState('Acquisition'); } function AnimEnd() { PlayPatrolStop(); } function HitWall(vector HitNormal, actor Wall) { if (Physics == PHYS_Falling) return; if ( Wall.IsA('Mover') && Mover(Wall).HandleDoor(self) ) { if ( SpecialPause > 0 ) Acceleration = vect(0,0,0); GotoState('Guarding', 'SpecialNavig'); return; } Focus = Destination; if (PickWallAdjust()) GotoState('Guarding', 'AdjustFromWall'); else MoveTimer = -1.0; } function PickDestination() { local Actor path; path = None; if (SpecialGoal != None) path = FindPathToward(SpecialGoal); else if ( OrderObject != None ) path = FindPathTo(OrderObject.Location); //log("Next path is "$path); if (path != None) { MoveTarget = path; Destination = path.Location; } else StartRoaming(); } function SetFall() { NextState = 'Guarding'; NextLabel = 'Begin'; NextAnim = AnimSequence; GotoState('FallingState'); } function BeginState() { SpecialGoal = None; SpecialPause = 0.0; Enemy = None; NextAnim = ''; SetAlertness(0.0); } AdjustFromWall: StrafeTo(Destination, Focus); Destination = Focus; MoveTo(Destination); Goto('GoToGuard'); Begin: //log(class$" guarding "$OrderObject); Disable('AnimEnd'); GoToGuard: if ( VSize(Location - OrderObject.Location) < 2 * CollisionRadius) Goto('Turn'); TweenToRunning(0.2); FinishAnim(); PlayRunning(); WaitForLanding(); if (actorReachable(OrderObject)) MoveToward(OrderObject, FMax(0.75, WalkingSpeed)); else { PickDestination(); SpecialNavig: if (SpecialPause > 0.0) { Acceleration = vect(0,0,0); TweenToPatrolStop(0.3); Sleep(SpecialPause); SpecialPause = 0.0; TweenToRunning(0.1); FinishAnim(); PlayRunning(); } MoveToward(MoveTarget); } Goto('GoToGuard'); Turn: //log(class$" got to guardpoint"); Acceleration = vect(0,0,0); TweenToFighter(0.3); FinishAnim(); PlayTurning(); TurnTo( Location + 1000 * vector(OrderObject.Rotation) ); NextAnim = ''; bReadyToAttack = false; TweenToPatrolStop(0.2); FinishAnim(); Enable('AnimEnd'); NextAnim = ''; PlayPatrolStop(); DesiredRotation = rot(0,0,0); DesiredRotation.Yaw = Rotation.Yaw; setRotation(DesiredRotation); if (Physics != PHYS_Falling) SetPhysics(PHYS_None); } state Ambushing { function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType); if ( health <= 0 ) return; if ( Enemy != None ) LastSeenPos = Enemy.Location; if (NextState == 'TakeHit') { NextState = 'Attacking'; NextLabel = 'Begin'; GotoState('TakeHit'); } else if ( Enemy != None ) GotoState('Attacking'); } function Landed(vector HitNormal) { SetPhysics(PHYS_None); } function SetFall() { NextState = 'Ambushing'; NextLabel = 'Begin'; NextAnim = AnimSequence; GotoState('FallingState'); } function Timer() { Enable('Bump'); } function AnimEnd() { PlayWaitingAmbush(); } function EnemyAcquired() { local Ambushpoint oldspot; //log(Class$" just acquired an enemy"); MakeNoise(1.0); oldspot = Ambushpoint(OrderObject); if (oldspot != None) oldspot.taken = false; SetMovementPhysics(); GotoState('Attacking'); } function FindAmbush() { local Ambushpoint newspot; local float count; count = 0; //FIXME- instead of looking for pawn's spots, look for any nearby spot foreach AllActors( class 'Ambushpoint', newspot, tag ) { if ( !newspot.taken ) { count += 1; if (FRand() < 1/count) OrderObject = newspot; } } } function BeginState() { Disable('AnimEnd'); SpecialGoal = None; SpecialPause = 0.0; OldEnemy = Enemy; Enemy = None; SetAlertness(0.3); } FindAmbushSpot: if ((OldEnemy == None) || (FRand() < 0.7)) { FindAmbush(); if (Ambushpoint(OrderObject) != None) { //log("move to ambush spot"); Disable('Landed'); OldEnemy = None; Ambushpoint(OrderObject).taken = true; SetMovementPhysics(); TweenToRunning(0.2); FinishAnim(); PlayRunning(); MoveToAmbush: WaitForLanding(); if (actorReachable(OrderObject)) MoveToward(OrderObject); else { if (SpecialGoal != None) MoveTarget = FindPathToward(SpecialGoal); else MoveTarget = FindPathToward(OrderObject); if (MoveTarget != None) { SpecialNavig: if (SpecialPause > 0.0) { Acceleration = vect(0,0,0); TweenToPatrolStop(0.3); Sleep(SpecialPause); SpecialPause = 0.0; TweenToRunning(0.1); FinishAnim(); PlayRunning(); } MoveToward(MoveTarget); Goto('MoveToAmbush'); } else StartRoaming(); } if (Physics != PHYS_Falling) Acceleration = vect(0,0,0); DesiredSpeed = 0.0; TweenToFighter(0.2); FinishAnim(); PlayTurning(); TurnTo(Location + (Ambushpoint(OrderObject)).lookdir); } } Begin: NextAnim = ''; Enable('Landed'); Disable('AnimEnd'); if (OldEnemy != None) { ////log("turn toward probably enemy dir"); OldEnemy = None; if (Physics != PHYS_Falling) Acceleration = vect(0,0,0); SetMovementPhysics(); DesiredSpeed = 0.0; TweenToFighter(0.2); FinishAnim(); PlayTurning(); TurnTo(LastSeenPos); //FIXME - turn to a nearby pathnode? } DesiredSpeed = 0.0; bReadyToAttack = true; //log(class$" waiting in ambush"); DesiredRotation = rot(0,0,0); DesiredRotation.Yaw = Rotation.Yaw; Acceleration = vect(0,0,0); TweenToPatrolStop(0.3); FinishAnim(); Enable('AnimEnd'); NextAnim = ''; PlayWaitingAmbush(); setRotation(DesiredRotation); if (Physics != PHYS_Falling) SetPhysics(PHYS_None); } /* Acquisition - Creature has just reacted to stimulus, and set an enemy - depending on strength of stimulus, and ongoing stimulii, vary time to focus on target and start attacking (or whatever. FIXME - need some acquisition specific animation HearNoise and SeePlayer used to improve/change stimulus */ state Acquisition { ignores falling, landed; //fixme function WarnTarget(Pawn shooter, float projSpeed, vector FireDir) { local eAttitude att; if ( intelligence < BRAINS_Mammal ) return; att = AttitudeTo(shooter); if ( ((att == ATTITUDE_Ignore) || (att == ATTITUDE_Threaten)) ) damageAttitudeTo(shooter); } function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { LastSeenPos = Enemy.Location; Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType); if ( health <= 0 ) return; if (NextState == 'TakeHit') { NextState = 'Attacking'; NextLabel = 'Begin'; GotoState('TakeHit'); } else GotoState('Attacking'); } function HearNoise(float Loudness, Actor NoiseMaker) { local vector OldLastSeenPos; if ( SetEnemy(NoiseMaker.instigator) ) { OldLastSeenPos = LastSeenPos; if ( Enemy == NoiseMaker.instigator ) LastSeenPos = 0.5 * (NoiseMaker.Location + VSize(NoiseMaker.Location - Location) * vector(Rotation)); else if ( (Pawn(NoiseMaker) != None) && (Enemy == Pawn(NoiseMaker).Enemy) ) LastSeenPos = 0.5 * (Pawn(NoiseMaker).Enemy.Location + VSize(Pawn(NoiseMaker).Enemy.Location - Location) * vector(Rotation)); if ( VSize(OldLastSeenPos - Enemy.Location) < VSize(LastSeenPos - Enemy.Location) ) LastSeenPos = OldLastSeenPos; } } function SeePlayer(Actor SeenPlayer) { if ( SetEnemy(Pawn(SeenPlayer)) ) { PlayAcquisitionSound(); //log("Enemy Acquired!"); MakeNoise(1.0); NextAnim = ''; LastSeenPos = Enemy.Location; GotoState('Attacking'); } } function BeginState() { Disable('Tick'); //only used for bounding anim time SetAlertness(-0.5); } PlayOut: Acceleration = vect(0,0,0); if ( (AnimFrame < 0.6) && IsAnimating() ) { Sleep(0.05); Goto('PlayOut'); } Begin: SetMovementPhysics(); //log("Acquiring enemy"); ////log("Enemy position = "$Enemy.Location); ////log("Last seen position = "$LastSeenPos); AcquTurn: Acceleration = vect(0,0,0); if (NeedToTurn(LastSeenPos)) { PlayTurning(); TurnTo(LastSeenPos); } DesiredRotation = Rotator(LastSeenPos - Location); TweenToFighter(0.2); FinishAnim(); ////log("Stimulus = "$Stimulus); if ( AttitudeTo(Enemy) == ATTITUDE_Fear ) //will run away from noise { ////log("Run away from noise"); PlayFearSound(); LastSeenPos = Enemy.Location; MakeNoise(1.0); NextAnim = ''; GotoState('Attacking'); } else //investigate noise { ////log("investigate noise"); if ( pointReachable((Location + LastSeenPos) * 0.5) ) { TweenToWalking(0.3); FinishAnim(); PlayWalking(); MoveTo((Location + LastSeenPos) * 0.5, WalkingSpeed); Acceleration = vect(0,0,0); } WhatToDoNext('',''); } } /* Attacking Master attacking state - choose which type of attack to do from here */ state Attacking { ignores SeePlayer, HearNoise, Bump, HitWall; function ChooseAttackMode() { local eAttitude AttitudeToEnemy; local float Aggression; local pawn changeEn; if ((Enemy == None) || (Enemy.Health <= 0)) { if (Orders == 'Attacking') Orders = ''; WhatToDoNext('',''); return; } if ( (AlarmTag != '') && Enemy.bIsPlayer ) { if (AttitudeToPlayer > ATTITUDE_Ignore) { GotoState('AlarmPaused', 'WaitForPlayer'); return; } else if ( (AttitudeToPlayer != ATTITUDE_Fear) || bInitialFear ) { GotoState('TriggerAlarm'); return; } } AttitudeToEnemy = AttitudeTo(Enemy); if (AttitudeToEnemy == ATTITUDE_Fear) { GotoState('Retreating'); return; } else if (AttitudeToEnemy == ATTITUDE_Threaten) { GotoState('Threatening'); return; } else if (AttitudeToEnemy == ATTITUDE_Friendly) { if (Enemy.bIsPlayer) GotoState('Greeting'); else WhatToDoNext('',''); return; } else if (!LineOfSightTo(Enemy)) { if ( (OldEnemy != None) && (AttitudeTo(OldEnemy) == ATTITUDE_Hate) && LineOfSightTo(OldEnemy) ) { changeEn = enemy; enemy = oldenemy; oldenemy = changeEn; } else { if ( (Orders == 'Guarding') && !LineOfSightTo(OrderObject) ) GotoState('Guarding'); else if ( !bHasRangedAttack || VSize(Enemy.Location - Location) > 600 + (FRand() * RelativeStrength(Enemy) - CombatStyle) * 600 ) GotoState('Hunting'); else if ( bIsBoss || (Intelligence > BRAINS_None) ) { HuntStartTime = Level.TimeSeconds; NumHuntPaths = 0; GotoState('StakeOut'); } else WhatToDoNext('Waiting', 'TurnFromWall'); return; } } else if ( (TeamLeader != None) && TeamLeader.ChooseTeamAttackFor(self) ) return; if (bReadyToAttack) { ////log("Attack!"); Target = Enemy; If (VSize(Enemy.Location - Location) <= (MeleeRange + Enemy.CollisionRadius + CollisionRadius)) { GotoState('MeleeAttack'); return; } else if (bMovingRangedAttack) SetTimer(TimeBetweenAttacks, False); else if (bHasRangedAttack && (bIsPlayer || enemy.bIsPlayer) && CanFireAtEnemy() ) { if (!bIsPlayer || (2.5 * FRand() > Skill) ) { GotoState('RangedAttack'); return; } } } //decide whether to charge or make a tactical move if ( !bHasRangedAttack ) GotoState('Charging'); else GotoState('TacticalMove'); //log("Next state is "$state); } //EnemyNotVisible implemented so engine will update LastSeenPos function EnemyNotVisible() { ////log("enemy not visible"); } function Timer() { bReadyToAttack = True; } function BeginState() { if ( TimerRate <= 0.0 ) SetTimer(TimeBetweenAttacks * (1.0 + FRand()),false); if (Physics == PHYS_None) SetMovementPhysics(); } Begin: //log(class$" choose Attack"); ChooseAttackMode(); } state Threatening { ignores falling, landed; //fixme //ignores SeePlayer if enemy is a player //but not hear noise function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType); if ( health <= 0 ) return; if (NextState == 'TakeHit') { bReadyToAttack = true; NextState = 'Attacking'; NextLabel = 'Begin'; GotoState('TakeHit'); } else { bReadyToAttack = true; GotoState('Attacking'); } } function Trigger( actor Other, pawn EventInstigator ) { if (EventInstigator.bIsPlayer) { Enemy = EventInstigator; AttitudeToPlayer = ATTITUDE_Hate; GotoState('Attacking'); } } function EnemyNotVisible() { ////log("enemy not visible"); GotoState('Ambushing'); } function EnemyAcquired() { if (AttitudeTo(Enemy) < ATTITUDE_Threaten) GotoState('Attacking'); } function PickGuardDestination() { local vector desiredDest; local Actor path; desiredDest = OrderObject.Location + (OrderObject.CollisionRadius + 2.5 * CollisionRadius) * Normal(Enemy.Location - OrderObject.Location); if ( VSize(desiredDest - Location) < 60 ) { Destination = Location; return; } if (pointReachable(desiredDest)) Destination = desiredDest; else { path = FindPathTo(desiredDest, true); if (path != None) { MoveTarget = path; Destination = path.Location; } else Destination = Location; } } function PickThreatenDestination() { local vector desiredDest; local Actor path; desiredDest = Location + 0.4 * (VSize(Enemy.Location - Location) - CollisionRadius - Enemy.CollisionRadius - MeleeRange) * Normal(Enemy.Location - Location); if (pointReachable(desiredDest)) Destination = desiredDest; else { path = FindPathTo(desiredDest, true); if (path != None) { MoveTarget = path; Destination = path.Location; } else Destination = Location; } } function BeginState() { bCanJump = false; } function EndState() { if (JumpZ > 0) bCanJump = true; } Begin: Acceleration = vect(0,0,0); bReadyToAttack = true; if (Enemy.bIsPlayer) Disable('SeePlayer'); //but not hear noise TweenToPatrolStop(0.2); FinishAnim(); NextAnim = ''; FaceEnemy: Acceleration = vect(0,0,0); if (NeedToTurn(enemy.Location)) { PlayTurning(); TurnToward(Enemy); TweenToPatrolStop(0.2); FinishAnim(); NextAnim = ''; } Threaten: if (AttitudeTo(Enemy) < ATTITUDE_Threaten) GotoState('Attacking'); PlayThreatening(); FinishAnim(); if (AttitudeTo(Enemy) < ATTITUDE_Threaten) GotoState('Attacking'); if (Orders == 'Guarding') { //stay between enemy and guard object If (Enemy.bIsPlayer && (VSize(Enemy.Location - OrderObject.Location) < OrderObject.CollisionRadius + 2 * CollisionRadius + MeleeRange)) { AttitudeToPlayer = ATTITUDE_Hate; GotoState('Attacking'); } } else if (FRand() < 0.9 - Aggressiveness) //mostly just turn Goto('FaceEnemy'); else if (VSize(Enemy.Location - Location) < 2.5 * (CollisionRadius + Enemy.CollisionRadius + MeleeRange)) Goto('FaceEnemy'); WaitForLanding(); if (Orders == 'Guarding') //stay between enemy and guard object PickGuardDestination(); else PickThreatenDestination(); if (Destination != Location) { TweenToWalking(0.2); FinishAnim(); PlayWalking(); MoveTo(Destination, WalkingSpeed); Acceleration = vect(0,0,0); TweenToPatrolStop(0.2); FinishAnim(); NextAnim = ''; } Goto('FaceEnemy'); } state Retreating { ignores SeePlayer, EnemyNotVisible, HearNoise; function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType); if ( health <= 0 ) return; if (NextState == 'TakeHit') { NextState = 'Retreating'; NextLabel = 'TakeHit'; GotoState('TakeHit'); } } function Timer() { bReadyToAttack = True; Enable('Bump'); } function SetFall() { NextState = 'Retreating'; NextLabel = 'Landed'; NextAnim = AnimSequence; GotoState('FallingState'); } function HitWall(vector HitNormal, actor Wall) { bSpecialPausing = false; if (Physics == PHYS_Falling) return; if ( Wall.IsA('Mover') && Mover(Wall).HandleDoor(self) ) { if ( SpecialPause > 0 ) Acceleration = vect(0,0,0); GotoState('Retreating', 'SpecialNavig'); return; } Focus = Destination; if (PickWallAdjust()) GotoState('Retreating', 'AdjustFromWall'); else { Home = None; MoveTimer = -1.0; } } /* if has a base then run toward it if its not visible to player. (FIXME) adjusts attitude based on proximity to base Else pick a random pathnode not visible to player and run toward it. Also - modify weights of paths visible and near to player up. */ function PickDestination() { //log("find retreat destination"); if (HomeBase(Home) == None) { Home = FindRandomDest(); //find temporary home if (Home == None) { if (bReadyToAttack) { setTimer(3.0, false); Target = Enemy; GotoState('RangedAttack'); } else { Aggressiveness += 0.3; GotoState('TacticalMove', 'NoCharge'); } } } } function ChangeDestination() { local actor oldTarget; local Actor path; oldTarget = Home; PickDestination(); if (Home == oldTarget) { Aggressiveness += 0.3; //log("same old target"); GotoState('TacticalMove', 'TacticalTick'); } else { path = FindPathToward(Home); if (path == None) { //log("no new target"); Aggressiveness += 0.3; GotoState('TacticalMove', 'TacticalTick'); } else { MoveTarget = path; Destination = path.Location; } } } function Bump(actor Other) { local vector VelDir, OtherDir; local float speed; //log(Other.class$" bumped "$class); if (Pawn(Other) != None) { if ( (Other == Enemy) || SetEnemy(Pawn(Other)) ) GotoState('MeleeAttack'); else if ( (HomeBase(Home) != None) && (VSize(Location - Home.Location) < HomeBase(Home).Extent) ) ReachedHome(); return; } if ( TimerRate <= 0 ) setTimer(1.0, false); speed = VSize(Velocity); if ( speed > 1 ) { VelDir = Velocity/speed; VelDir.Z = 0; OtherDir = Other.Location - Location; OtherDir.Z = 0; OtherDir = Normal(OtherDir); if ( (VelDir Dot OtherDir) > 0.9 ) { Velocity.X = VelDir.Y; Velocity.Y = -1 * VelDir.X; Velocity *= FMax(speed, 200); } } Disable('Bump'); } function ReachedHome() { if (LineOfSightTo(Enemy)) { if (Homebase(home) != None) { //log(class$" reached home base - turn and fight"); Aggressiveness += 0.2; if ( !bMoraleBoosted ) health = Min(default.health, health+20); MakeNoise(1.0); GotoState('Attacking'); } else ChangeDestination(); } else { if (Homebase(home) != None) MakeNoise(1.0); aggressiveness += 0.2; if ( !bMoraleBoosted ) health = Min(default.health, health+5); GotoState('Retreating', 'TurnAtHome'); } bMoraleBoosted = true; } function PickNextSpot() { local Actor path; local vector dist2d; local float zdiff; if ( Home == None ) { PickDestination(); if ( Home == None ) return; } //log("find retreat spot"); dist2d = Home.Location - Location; zdiff = dist2d.Z; dist2d.Z = 0.0; if ((VSize(dist2d) < 2 * CollisionRadius) && (Abs(zdiff) < CollisionHeight)) ReachedHome(); else { if (ActorReachable(Home)) { //log("almost there"); path = Home; if (HomeBase(Home) == None) Home = None; } else { if (SpecialGoal != None) path = FindPathToward(SpecialGoal); else path = FindPathToward(Home); } if (path == None) ChangeDestination(); else { MoveTarget = path; Destination = path.Location; } } } function AnimEnd() { if ( bSpecialPausing ) PlayPatrolStop(); else if ( bCanFire && LineOfSightTo(Enemy) ) PlayCombatMove(); else PlayRunning(); } function BeginState() { bCanFire = false; bSpecialPausing = false; SpecialGoal = None; SpecialPause = 0.0; } Begin: //log(class$" retreating"); if ( bReadyToAttack && (FRand() < 0.6) ) { SetTimer(TimeBetweenAttacks, false); bReadyToAttack = false; } TweenToRunning(0.1); WaitForLanding(); PickDestination(); Landed: TweenToRunning(0.1); RunAway: PickNextSpot(); SpecialNavig: if (SpecialPause > 0.0) { if ( LineOfSightTo(Enemy) ) { bFiringPaused = true; NextState = 'Retreating'; NextLabel = 'Moving'; GotoState('RangedAttack'); } bSpecialPausing = true; Acceleration = vect(0,0,0); TweenToPatrolStop(0.25); Sleep(SpecialPause); SpecialPause = 0.0; bSpecialPausing = false; TweenToRunning(0.1); } Moving: if ( MoveTarget == None ) { Sleep(0.0); Goto('RunAway'); } if ( !bCanStrafe || !LineOfSightTo(Enemy) || (Skill - 2 * FRand() + (Normal(Enemy.Location - Location - vect(0,0,1) * (Enemy.Location.Z - Location.Z)) Dot Normal(MoveTarget.Location - Location - vect(0,0,1) * (MoveTarget.Location.Z - Location.Z))) < 0) ) { bCanFire = false; MoveToward(MoveTarget); } else { bCanFire = true; StrafeFacing(MoveTarget.Location, Enemy); } Goto('RunAway'); TakeHit: TweenToRunning(0.12); Goto('Moving'); AdjustFromWall: StrafeTo(Destination, Focus); Destination = Focus; MoveTo(Destination); Goto('Moving'); TurnAtHome: Acceleration = vect(0,0,0); TurnTo(Homebase(Home).lookdir); GotoState('Ambushing', 'FindAmbushSpot'); } state Charging { ignores SeePlayer, HearNoise; /* MayFall() called by engine physics if walking and bCanJump, and is about to go off a ledge. Pawn has opportunity (by setting bCanJump to false) to avoid fall */ function MayFall() { if ( MoveTarget != Enemy ) return; if ( intelligence == BRAINS_None ) return; bCanJump = ActorReachable(Enemy); if ( !bCanJump ) GotoState('TacticalMove', 'NoCharge'); } function HitWall(vector HitNormal, actor Wall) { if (Physics == PHYS_Falling) return; if ( Wall.IsA('Mover') && Mover(Wall).HandleDoor(self) ) { if ( SpecialPause > 0 ) Acceleration = vect(0,0,0); GotoState('Charging', 'SpecialNavig'); return; } Focus = Destination; if (PickWallAdjust()) GotoState('Charging', 'AdjustFromWall'); else MoveTimer = -1.0; } function SetFall() { NextState = 'Charging'; NextLabel = 'ResumeCharge'; NextAnim = AnimSequence; GotoState('FallingState'); } function FearThisSpot(Actor aSpot) { Destination = Location + 120 * Normal(Location - aSpot.Location); GotoState('TacticalMove', 'DoStrafeMove'); } function bool StrafeFromDamage(vector momentum, float Damage, name DamageType, bool bFindDest) { local vector sideDir, extent, HitLocation, HitNormal; local actor HitActor; local float healthpct; if ( (damageType == 'shot') || (damageType == 'jolted') ) healthpct = 0.17; else healthpct = 0.25; healthpct *= CombatStyle; if ( FRand() * Damage < healthpct * Health ) return false; if ( !bFindDest ) return true; sideDir = Normal( Normal(Enemy.Location - Location) Cross vect(0,0,1) ); if ( (momentum Dot sidedir) > 0 ) sidedir *= -1; Extent.X = CollisionRadius; Extent.Y = CollisionRadius; Extent.Z = CollisionHeight; HitActor = Trace(HitLocation, HitNormal, Location + 100 * sideDir, Location, false, Extent); if (HitActor != None) { sideDir *= -1; HitActor = Trace(HitLocation, HitNormal, Location + 100 * sideDir, Location, false, Extent); } if (HitActor != None) return false; if ( Physics == PHYS_Walking ) { HitActor = Trace(HitLocation, HitNormal, Location + 100 * sideDir - MaxStepHeight * vect(0,0,1), Location + 100 * sideDir, false, Extent); if ( HitActor == None ) return false; } Destination = Location + 250 * sideDir; GotoState('TacticalMove', 'DoStrafeMove'); return true; } function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { local float pick; local vector sideDir, extent; local bool bWasOnGround; bWasOnGround = (Physics == PHYS_Walking); Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType); if ( health <= 0 ) return; if (NextState == 'TakeHit') { if (AttitudeTo(Enemy) == ATTITUDE_Fear) { NextState = 'Retreating'; NextLabel = 'Begin'; } else if ( (Intelligence > BRAINS_Mammal) && bHasRangedAttack && bCanStrafe && StrafeFromDamage(momentum, Damage, damageType, false) ) { NextState = 'TacticalMove'; NextLabel = 'NoCharge'; } else { NextState = 'Charging'; NextLabel = 'TakeHit'; } GotoState('TakeHit'); } else if ( (Intelligence > BRAINS_Mammal) && bHasRangedAttack && bCanStrafe && StrafeFromDamage(momentum, Damage, damageType, true) ) return; else if ( bWasOnGround && (MoveTarget == Enemy) && (Physics == PHYS_Falling) && (Intelligence == BRAINS_Human) ) //weave { pick = 1.0; if ( bStrafeDir ) pick = -1.0; sideDir = Normal( Normal(Enemy.Location - Location) Cross vect(0,0,1) ); sideDir.Z = 0; Velocity += pick * GroundSpeed * 0.7 * sideDir; if ( FRand() < 0.2 ) bStrafeDir = !bStrafeDir; } } function AnimEnd() { PlayCombatMove(); } function Timer() { bReadyToAttack = True; Target = Enemy; if (VSize(Enemy.Location - Location) <= (MeleeRange + Enemy.CollisionRadius + CollisionRadius)) GotoState('MeleeAttack'); else if ( bHasRangedAttack && (FRand() > 0.7 + 0.1 * skill) ) GotoState('RangedAttack'); else if ( bHasRangedAttack && !bMovingRangedAttack) { if ( FRand() < CombatStyle * 0.8 ) //then keep charging SetTimer(1.0,false); else GotoState('Attacking'); } } function EnemyNotVisible() { GotoState('Hunting'); } function BeginState() { bCanFire = false; SpecialGoal = None; SpecialPause = 0.0; } function EndState() { if ( JumpZ > 0 ) bCanJump = true; } AdjustFromWall: StrafeTo(Destination, Focus); Goto('CloseIn'); ResumeCharge: PlayRunning(); Goto('Charge'); Begin: TweenToRunning(0.15); Charge: bFromWall = false; CloseIn: if ( (Enemy == None) || (Enemy.Health <=0) ) GotoState('Attacking'); if ( Enemy.Region.Zone.bWaterZone ) { if (!bCanSwim) GotoState('TacticalMove', 'NoCharge'); } else if (!bCanFly && !bCanWalk) GotoState('TacticalMove', 'NoCharge'); if (Physics == PHYS_Falling) { DesiredRotation = Rotator(Enemy.Location - Location); Focus = Enemy.Location; Destination = Enemy.Location; WaitForLanding(); } if( (Intelligence <= BRAINS_Reptile) || actorReachable(Enemy) ) { bCanFire = true; if ( FRand() < 0.3 ) PlayThreateningSound(); MoveToward(Enemy); if (bFromWall) { bFromWall = false; if (PickWallAdjust()) StrafeFacing(Destination, Enemy); else GotoState('TacticalMove', 'NoCharge'); } } else { NoReach: bCanFire = false; bFromWall = false; //log("route to enemy "$Enemy); if (!FindBestPathToward(Enemy)) { Sleep(0.0); GotoState('TacticalMove', 'NoCharge'); } SpecialNavig: if ( SpecialPause > 0.0 ) { bFiringPaused = true; NextState = 'Charging'; NextLabel = 'Moving'; GotoState('RangedAttack'); } Moving: if (VSize(MoveTarget.Location - Location) < 2.5 * CollisionRadius) { bCanFire = true; StrafeFacing(MoveTarget.Location, Enemy); } else { if ( !bCanStrafe || !LineOfSightTo(Enemy) || (Skill - 2 * FRand() + (Normal(Enemy.Location - Location - vect(0,0,1) * (Enemy.Location.Z - Location.Z)) Dot Normal(MoveTarget.Location - Location - vect(0,0,1) * (MoveTarget.Location.Z - Location.Z))) < 0) ) { if ( GetAnimGroup(AnimSequence) == 'MovingAttack' ) { AnimSequence = ''; TweenToRunning(0.12); } MoveToward(MoveTarget); } else { bCanFire = true; StrafeFacing(MoveTarget.Location, Enemy); } if ( !bFromWall && (FRand() < 0.5) ) PlayThreateningSound(); } } //log("finished move"); if (VSize(Location - Enemy.Location) < CollisionRadius + Enemy.CollisionRadius + MeleeRange) Goto('GotThere'); if ( bIsPlayer || (!bFromWall && bHasRangedAttack && (FRand() > CombatStyle + 0.1)) ) GotoState('Attacking'); MoveTimer = 0.0; bFromWall = false; Goto('CloseIn'); GotThere: ////log("Got to enemy"); Target = Enemy; GotoState('MeleeAttack'); TakeHit: TweenToRunning(0.12); if (MoveTarget == Enemy) { bCanFire = true; MoveToward(MoveTarget); } Goto('Charge'); } state TacticalMove { ignores SeePlayer, HearNoise; function SetFall() { Acceleration = vect(0,0,0); Destination = Location; NextState = 'Attacking'; NextLabel = 'Begin'; NextAnim = 'Fighter'; GotoState('FallingState'); } function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType); if ( health <= 0 ) return; if ( NextState == 'TakeHit' ) { NextState = 'TacticalMove'; NextLabel = 'TakeHit'; GotoState('TakeHit'); } } function HitWall(vector HitNormal, actor Wall) { if (Physics == PHYS_Falling) return; Focus = Destination; //if (PickWallAdjust()) // GotoState('TacticalMove', 'AdjustFromWall'); if ( bChangeDir || (FRand() < 0.5) || (((Enemy.Location - Location) Dot HitNormal) < 0) ) { DesiredRotation = Rotator(Enemy.Location - location); GiveUpTactical(false); } else { bChangeDir = true; Destination = Location - HitNormal * FRand() * 500; } } function FearThisSpot(Actor aSpot) { Destination = Location + 120 * Normal(Location - aSpot.Location); } function AnimEnd() { PlayCombatMove(); } function Timer() { bReadyToAttack = True; Enable('Bump'); Target = Enemy; if (VSize(Enemy.Location - Location) <= (MeleeRange + Enemy.CollisionRadius + CollisionRadius)) GotoState('MeleeAttack'); else if ( bHasRangedAttack && ((!bMovingRangedAttack && (FRand() < 0.8)) || (FRand() > 0.5 + 0.17 * skill)) ) GotoState('RangedAttack'); } function EnemyNotVisible() { if ( aggressiveness > relativestrength(enemy) ) { if (ValidRecovery()) GotoState('TacticalMove','RecoverEnemy'); else GotoState('Attacking'); } Disable('EnemyNotVisible'); } function bool ValidRecovery() { local actor HitActor; local vector HitLocation, HitNormal; HitActor = Trace(HitLocation, HitNormal, Enemy.Location, LastSeeingPos, false); return (HitActor == None); } function GiveUpTactical(bool bNoCharge) { if ( !bNoCharge && (2 * CombatStyle > (3 - Skill) * FRand()) ) GotoState('Charging'); else if ( bReadyToAttack && (skill > 3 * FRand() - 1) ) GotoState('RangedAttack'); else GotoState('RangedAttack', 'Challenge'); } /* PickDestination() Choose a destination for the tactical move, based on aggressiveness and the tactical situation. Make sure destination is reachable */ function PickDestination(bool bNoCharge) { local vector pickdir, enemydir, enemyPart, Y, minDest; local actor HitActor; local vector HitLocation, HitNormal, collSpec; local float Aggression, enemydist, minDist, strafeSize, optDist; local bool success, bNoReach; bChangeDir = false; if (Region.Zone.bWaterZone && !bCanSwim && bCanFly) { Destination = Location + 75 * (VRand() + vect(0,0,1)); Destination.Z += 100; return; } if ( Enemy.Region.Zone.bWaterZone ) bNoCharge = bNoCharge || !bCanSwim; else bNoCharge = bNoCharge || (!bCanFly && !bCanWalk); success = false; enemyDist = VSize(Location - Enemy.Location); Aggression = 2 * (CombatStyle + FRand()) - 1.1; if ( intelligence == BRAINS_Human ) { if ( Enemy.bIsPlayer && (AttitudeToPlayer == ATTITUDE_Fear) && (CombatStyle > 0) ) Aggression = Aggression - 2 - 2 * CombatStyle; if ( Weapon != None ) Aggression += 2 * Weapon.SuggestAttackStyle(); if ( Enemy.Weapon != None ) Aggression += 2 * Enemy.Weapon.SuggestDefenseStyle(); } if ( enemyDist > 1000 ) Aggression += 1; if ( bIsPlayer && !bNoCharge ) bNoCharge = ( Aggression < FRand() ); if ( (Physics == PHYS_Walking) || (Physics == PHYS_Falling) ) { if (Location.Z > Enemy.Location.Z + 140) //tactical height advantage Aggression = FMax(0.0, Aggression - 1.0 + CombatStyle); else if (Location.Z < Enemy.Location.Z - CollisionHeight) // below enemy { if ( !bNoCharge && (Intelligence > BRAINS_Reptile) && (Aggression > 0) && (FRand() < 0.6) ) { GotoState('Charging'); return; } else if ( (enemyDist < 1.1 * (Enemy.Location.Z - Location.Z)) && !actorReachable(Enemy) ) { bNoReach = (Intelligence > BRAINS_None); aggression = -1.5 * FRand(); } } } if (!bNoCharge && (Aggression > 2 * FRand())) { if ( bNoReach && (Physics != PHYS_Falling) ) { TweenToRunning(0.15); GotoState('Charging', 'NoReach'); } else GotoState('Charging'); return; } if (enemyDist > FMax(VSize(OldLocation - Enemy.OldLocation), 240)) Aggression += 0.4 * FRand(); enemydir = (Enemy.Location - Location)/enemyDist; minDist = FMin(160.0, 3*CollisionRadius); if ( bIsPlayer ) optDist = 80 + FMin(EnemyDist, 250 * (FRand() + FRand())); else optDist = 50 + FMin(EnemyDist, 500 * FRand()); Y = (enemydir Cross vect(0,0,1)); if ( Physics == PHYS_Walking ) { Y.Z = 0; enemydir.Z = 0; } else enemydir.Z = FMax(0,enemydir.Z); strafeSize = FMax(-0.7, FMin(0.85, (2 * Aggression * FRand() - 0.3))); enemyPart = enemydir * strafeSize; strafeSize = FMax(0.0, 1 - Abs(strafeSize)); pickdir = strafeSize * Y; if ( bStrafeDir ) pickdir *= -1; bStrafeDir = !bStrafeDir; collSpec.X = CollisionRadius; collSpec.Y = CollisionRadius; collSpec.Z = FMax(6, CollisionHeight - 18); minDest = Location + minDist * (pickdir + enemyPart); HitActor = Trace(HitLocation, HitNormal, minDest, Location, false, collSpec); if (HitActor == None) { success = (Physics != PHYS_Walking); if ( !success ) { collSpec.X = FMin(14, 0.5 * CollisionRadius); collSpec.Y = collSpec.X; HitActor = Trace(HitLocation, HitNormal, minDest - (18 + MaxStepHeight) * vect(0,0,1), minDest, false, collSpec); success = (HitActor != None); } if (success) Destination = minDest + (pickdir + enemyPart) * optDist; } if ( !success ) { collSpec.X = CollisionRadius; collSpec.Y = CollisionRadius; minDest = Location + minDist * (enemyPart - pickdir); HitActor = Trace(HitLocation, HitNormal, minDest, Location, false, collSpec); if (HitActor == None) { success = (Physics != PHYS_Walking); if ( !success ) { collSpec.X = FMin(14, 0.5 * CollisionRadius); collSpec.Y = collSpec.X; HitActor = Trace(HitLocation, HitNormal, minDest - (18 + MaxStepHeight) * vect(0,0,1), minDest, false, collSpec); success = (HitActor != None); } if (success) Destination = minDest + (enemyPart - pickdir) * optDist; } else { if ( (CombatStyle <= 0) || (Enemy.bIsPlayer && (AttitudeToPlayer == ATTITUDE_Fear)) ) enemypart = vect(0,0,0); else if ( (enemydir Dot enemyPart) < 0 ) enemyPart = -1 * enemyPart; pickDir = Normal(enemyPart - pickdir + HitNormal); minDest = Location + minDist * pickDir; collSpec.X = CollisionRadius; collSpec.Y = CollisionRadius; HitActor = Trace(HitLocation, HitNormal, minDest, Location, false, collSpec); if (HitActor == None) { success = (Physics != PHYS_Walking); if ( !success ) { collSpec.X = FMin(14, 0.5 * CollisionRadius); collSpec.Y = collSpec.X; HitActor = Trace(HitLocation, HitNormal, minDest - (18 + MaxStepHeight) * vect(0,0,1), minDest, false, collSpec); success = (HitActor != None); } if (success) Destination = minDest + pickDir * optDist; } } } if ( !success ) GiveUpTactical(bNoCharge); else { pickDir = (Destination - Location); enemyDist = VSize(pickDir); if ( enemyDist > minDist + 2 * CollisionRadius ) { pickDir = pickDir/enemyDist; HitActor = Trace(HitLocation, HitNormal, Destination + 2 * CollisionRadius * pickdir, Location, false); if ( (HitActor != None) && ((HitNormal Dot pickDir) < -0.6) ) Destination = HitLocation - 2 * CollisionRadius * pickdir; } } } function BeginState() { MinHitWall += 0.15; bAvoidLedges = ( !bCanJump && (CollisionRadius > 40) ); bCanJump = false; bCanFire = false; } function EndState() { bAvoidLedges = false; MinHitWall -= 0.15; if (JumpZ > 0) bCanJump = true; } //FIXME - what if bReadyToAttack at start TacticalTick: Sleep(0.02); Begin: TweenToRunning(0.15); Enable('AnimEnd'); if (Physics == PHYS_Falling) { DesiredRotation = Rotator(Enemy.Location - Location); Focus = Enemy.Location; Destination = Enemy.Location; WaitForLanding(); } PickDestination(false); DoMove: if ( !bCanStrafe ) { DoDirectMove: Enable('AnimEnd'); if ( GetAnimGroup(AnimSequence) == 'MovingAttack' ) { AnimSequence = ''; TweenToRunning(0.12); } bCanFire = false; MoveTo(Destination); } else { DoStrafeMove: Enable('AnimEnd'); bCanFire = true; StrafeFacing(Destination, Enemy); } if (FRand() < 0.5) PlayThreateningSound(); if ( (Enemy != None) && !LineOfSightTo(Enemy) && ValidRecovery() ) Goto('RecoverEnemy'); else { bReadyToAttack = true; GotoState('Attacking'); } NoCharge: TweenToRunning(0.15); Enable('AnimEnd'); if (Physics == PHYS_Falling) { DesiredRotation = Rotator(Enemy.Location - Location); Focus = Enemy.Location; Destination = Enemy.Location; WaitForLanding(); } PickDestination(true); Goto('DoMove'); AdjustFromWall: Enable('AnimEnd'); StrafeTo(Destination, Focus); Destination = Focus; Goto('DoMove'); TakeHit: TweenToRunning(0.12); Goto('DoMove'); RecoverEnemy: Enable('AnimEnd'); bReadyToAttack = true; HidingSpot = Location; bCanFire = false; Destination = LastSeeingPos + 3 * CollisionRadius * Normal(LastSeeingPos - Location); if ( bCanStrafe || (VSize(LastSeeingPos - Location) < 3 * CollisionRadius) ) StrafeFacing(Destination, Enemy); else MoveTo(Destination); if ( Weapon == None ) Acceleration = vect(0,0,0); if ( NeedToTurn(Enemy.Location) ) { PlayTurning(); TurnToward(Enemy); } if ( bHasRangedAttack && CanFireAtEnemy() ) { Disable('AnimEnd'); DesiredRotation = Rotator(Enemy.Location - Location); if ( Weapon == None ) { PlayRangedAttack(); FinishAnim(); TweenToRunning(0.1); bReadyToAttack = false; SetTimer(TimeBetweenAttacks, false); } else { FireWeapon(); if ( Weapon.bSplashDamage ) { bFire = 0; bAltFire = 0; } } if ( bCanStrafe && (FRand() + 0.1 > CombatStyle) ) { Enable('EnemyNotVisible'); Enable('AnimEnd'); Destination = HidingSpot + 4 * CollisionRadius * Normal(HidingSpot - Location); Goto('DoMove'); } } if ( !bMovingRangedAttack ) bReadyToAttack = false; GotoState('Attacking'); } state Hunting { ignores EnemyNotVisible; /* MayFall() called by engine physics if walking and bCanJump, and is about to go off a ledge. Pawn has opportunity (by setting bCanJump to false) to avoid fall */ function MayFall() { bCanJump = ( (intelligence == BRAINS_None) || (MoveTarget != None) || PointReachable(Destination) ); } function FearThisSpot(Actor aSpot) { Destination = Location + 120 * Normal(Location - aSpot.Location); GotoState('Wandering', 'Moving'); } function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType); if ( health <= 0 ) return; bFrustrated = true; if (NextState == 'TakeHit') { if (AttitudeTo(Enemy) == ATTITUDE_Fear) { NextState = 'Retreating'; NextLabel = 'Begin'; } else { NextState = 'Hunting'; NextLabel = 'AfterFall'; } GotoState('TakeHit'); } } function HearNoise(float Loudness, Actor NoiseMaker) { if ( SetEnemy(NoiseMaker.instigator) ) LastSeenPos = Enemy.Location; } function SetFall() { NextState = 'Hunting'; NextLabel = 'AfterFall'; NextAnim = AnimSequence; GotoState('FallingState'); } function bool SetEnemy(Pawn NewEnemy) { local float rnd; if (Global.SetEnemy(NewEnemy)) { rnd = FRand(); if ( bReadyToAttack ) { if (rnd < 0.3) PlayAcquisitionSound(); else if (rnd < 0.6) PlayThreateningSound(); } bReadyToAttack = true; DesiredRotation = Rotator(Enemy.Location - Location); if ( !bHasRangedAttack || (CombatStyle > FRand()) ) GotoState('Charging'); else GotoState('Attacking'); return true; } return false; } function AnimEnd() { PlayRunning(); Disable('AnimEnd'); } function Timer() { bReadyToAttack = true; Enable('Bump'); SetTimer(1.0, false); } function HitWall(vector HitNormal, actor Wall) { if (Physics == PHYS_Falling) return; if ( Wall.IsA('Mover') && Mover(Wall).HandleDoor(self) ) { if ( SpecialPause > 0 ) Acceleration = vect(0,0,0); GotoState('Hunting', 'SpecialNavig'); return; } Focus = Destination; if (PickWallAdjust()) GotoState('Hunting', 'AdjustFromWall'); else MoveTimer = -1.0; } function PickDestination() { local NavigationPoint path; local actor HitActor; local vector HitNormal, HitLocation, nextSpot, ViewSpot; local float posZ, elapsed; local bool bCanSeeLastSeen; // If no enemy, or I should see him but don't, then give up if ( (Enemy == None) || (Enemy.Health <= 0) ) { WhatToDoNext('',''); return; } bAvoidLedges = false; elapsed = Level.TimeSeconds - HuntStartTime; if ( (elapsed > 30) && ((intelligence < BRAINS_Human) || (elapsed > 90)) ) { WhatToDoNext('',''); return; } if ( JumpZ > 0 ) bCanJump = true; if ( ActorReachable(Enemy) ) { if ( bIsBoss || (numHuntPaths < 8 + Skill) || (elapsed < 15) || ((Normal(Enemy.Location - Location) Dot vector(Rotation)) > -0.5) ) { Destination = Enemy.Location; MoveTarget = None; numHuntPaths++; } else WhatToDoNext('',''); return; } numHuntPaths++; ViewSpot = Location + EyeHeight * vect(0,0,1); bCanSeeLastSeen = false; if ( intelligence > BRAINS_Reptile ) { HitActor = Trace(HitLocation, HitNormal, LastSeenPos, ViewSpot, false); bCanSeeLastSeen = (HitActor == None); if ( bCanSeeLastSeen ) { HitActor = Trace(HitLocation, HitNormal, LastSeenPos, Enemy.Location, false); bHunting = (HitActor != None); } else bHunting = true; if ( FindBestPathToward(Enemy) ) return; } MoveTarget = None; if ( bFromWall ) { bFromWall = false; if ( !PickWallAdjust() ) { if ( CanStakeOut() ) GotoState('StakeOut'); else WhatToDoNext('', ''); } return; } if ( !bIsBoss && (NumHuntPaths > 20) && ((Intelligence < BRAINS_Human) || (NumHuntPaths > 60)) ) { WhatToDoNext('', ''); return; } if ( LastSeeingPos != vect(1000000,0,0) ) { Destination = LastSeeingPos; LastSeeingPos = vect(1000000,0,0); HitActor = Trace(HitLocation, HitNormal, Enemy.Location, ViewSpot, false); if ( HitActor == None ) { If (VSize(Location - Destination) < 20) { HitActor = Trace(HitLocation, HitNormal, Enemy.Location, ViewSpot, false); if (HitActor == None) { SetEnemy(Enemy); return; } } return; } } bAvoidLedges = ( (CollisionRadius > 42) && (Intelligence < BRAINS_Human) ); posZ = LastSeenPos.Z + CollisionHeight - Enemy.CollisionHeight; nextSpot = LastSeenPos - Normal(Enemy.Location - Enemy.OldLocation) * CollisionRadius; nextSpot.Z = posZ; HitActor = Trace(HitLocation, HitNormal, nextSpot , ViewSpot, false); if ( HitActor == None ) Destination = nextSpot; else if ( bCanSeeLastSeen ) Destination = LastSeenPos; else { Destination = LastSeenPos; HitActor = Trace(HitLocation, HitNormal, LastSeenPos , ViewSpot, false); if ( HitActor != None ) { // check if could adjust and see it if ( PickWallAdjust() || FindViewSpot() ) GotoState('Hunting', 'AdjustFromWall'); else if ( bIsBoss || VSize(Enemy.Location - Location) < 1200 ) GotoState('StakeOut'); else { WhatToDoNext('Waiting', 'TurnFromWall'); return; } } } LastSeenPos = Enemy.Location; } function bool FindViewSpot() { local vector X,Y,Z, HitLocation, HitNormal; local actor HitActor; local bool bAlwaysTry; GetAxes(Rotation,X,Y,Z); // try left and right // if frustrated, always move if possible bAlwaysTry = bFrustrated; bFrustrated = false; HitActor = Trace(HitLocation, HitNormal, Enemy.Location, Location + 2 * Y * CollisionRadius, false); if ( HitActor == None ) { Destination = Location + 2.5 * Y * CollisionRadius; return true; } HitActor = Trace(HitLocation, HitNormal, Enemy.Location, Location - 2 * Y * CollisionRadius, false); if ( HitActor == None ) { Destination = Location - 2.5 * Y * CollisionRadius; return true; } if ( bAlwaysTry ) { if ( FRand() < 0.5 ) Destination = Location - 2.5 * Y * CollisionRadius; else Destination = Location - 2.5 * Y * CollisionRadius; return true; } return false; } function BeginState() { SpecialGoal = None; SpecialPause = 0.0; bFromWall = false; SetAlertness(0.5); } function EndState() { bAvoidLedges = false; bHunting = false; if ( JumpZ > 0 ) bCanJump = true; } AdjustFromWall: StrafeTo(Destination, Focus); Destination = Focus; if ( MoveTarget != None ) Goto('SpecialNavig'); else Goto('Follow'); Begin: numHuntPaths = 0; HuntStartTime = Level.TimeSeconds; AfterFall: TweenToRunning(0.15); bFromWall = false; Follow: WaitForLanding(); if ( CanSee(Enemy) ) SetEnemy(Enemy); PickDestination(); SpecialNavig: if ( SpecialPause > 0.0 ) { Disable('AnimEnd'); Acceleration = vect(0,0,0); PlayChallenge(); Sleep(SpecialPause); SpecialPause = 0.0; Enable('AnimEnd'); } if (MoveTarget == None) MoveTo(Destination); else MoveToward(MoveTarget); if ( Intelligence < BRAINS_Human ) { if ( FRand() > 0.3 ) PlayRoamingSound(); else if ( FRand() > 0.3 ) PlayThreateningSound(); } if ( (Orders == 'Guarding') && !LineOfSightTo(OrderObject) ) GotoState('Guarding'); Goto('Follow'); } state StakeOut { ignores EnemyNotVisible; function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType); if ( health <= 0 ) return; bFrustrated = true; LastSeenPos = Enemy.Location; if (NextState == 'TakeHit') { if (AttitudeTo(Enemy) == ATTITUDE_Fear) { NextState = 'Retreating'; NextLabel = 'Begin'; } else { NextState = 'Attacking'; NextLabel = 'Begin'; } GotoState('TakeHit'); } else GotoState('Attacking'); } function HearNoise(float Loudness, Actor NoiseMaker) { if ( SetEnemy(NoiseMaker.instigator) ) LastSeenPos = Enemy.Location; } function SetFall() { NextState = 'StakeOut'; NextLabel = 'Begin'; NextAnim = AnimSequence; GotoState('FallingState'); } function bool SetEnemy(Pawn NewEnemy) { local float rnd; if (Global.SetEnemy(NewEnemy)) { rnd = FRand(); if (rnd < 0.3) PlayAcquisitionSound(); else if (rnd < 0.6) PlayThreateningSound(); bReadyToAttack = true; DesiredRotation = Rotator(Enemy.Location - Location); GotoState('Attacking'); return true; } return false; } function Timer() { bReadyToAttack = true; Enable('Bump'); SetTimer(1.0, false); } function rotator AdjustAim(float projSpeed, vector projStart, int aimerror, bool leadTarget, bool warnTarget) { local rotator FireRotation; local vector FireSpot; local actor HitActor; local vector HitLocation, HitNormal; FireSpot = LastSeenPos; aimerror = aimerror * (0.5 * (4 - skill - FRand())); HitActor = Trace(HitLocation, HitNormal, FireSpot, ProjStart, false); if( HitActor != None ) { ////log("adjust aim up"); FireSpot.Z += 0.9 * Target.CollisionHeight; HitActor = Trace(HitLocation, HitNormal, FireSpot, ProjStart, false); bClearShot = (HitActor == None); } FireRotation = Rotator(FireSpot - ProjStart); FireRotation.Yaw = FireRotation.Yaw + 0.5 * (Rand(2 * aimerror) - aimerror); viewRotation = FireRotation; return FireRotation; } function BeginState() { Acceleration = vect(0,0,0); bCanJump = false; bClearShot = true; bReadyToAttack = true; SetAlertness(0.5); } function EndState() { if ( JumpZ > 0 ) bCanJump = true; } Begin: Acceleration = vect(0,0,0); PlayChallenge(); TurnTo(LastSeenPos); if ( bHasRangedAttack && bClearShot && (FRand() < 0.5) && (VSize(Enemy.Location - LastSeenPos) < 150) && CanStakeOut() ) PlayRangedAttack(); FinishAnim(); PlayChallenge(); if ( bCrouching && !Region.Zone.bWaterZone ) Sleep(1); bCrouching = false; Sleep(1 + FRand()); if ( !bHasRangedAttack || !bClearShot || (VSize(Enemy.Location - Location) > 350 + (FRand() * RelativeStrength(Enemy) - CombatStyle) * 350) ) GotoState('Hunting', 'AfterFall'); else if ( CanStakeOut() ) Goto('Begin'); else GotoState('Hunting', 'AfterFall'); } state TakeHit { ignores seeplayer, hearnoise, bump, hitwall; function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType); } function Landed(vector HitNormal) { if (Velocity.Z < -1.4 * JumpZ) MakeNoise(-0.5 * Velocity.Z/(FMax(JumpZ, 150.0))); bJustLanded = true; } function Timer() { bReadyToAttack = true; if ( SpeechTime > 0 ) { SpeechTime = -1.0; bIsSpeaking = false; if ( TeamLeader != None ) TeamLeader.bTeamSpeaking = false; } } function PlayHitAnim(vector HitLocation, float Damage) { if ( LastPainTime - Level.TimeSeconds > 0.1 ) { PlayTakeHit(0.1, hitLocation, Damage); BeginState(); GotoState('TakeHit', 'Begin'); } } function BeginState() { LastPainTime = Level.TimeSeconds; LastPainAnim = AnimSequence; } Begin: // Acceleration = Normal(Acceleration); FinishAnim(); if ( skill < 2 ) Sleep(0.05); if ( (Physics == PHYS_Falling) && !Region.Zone.bWaterZone ) { Acceleration = vect(0,0,0); NextAnim = ''; GotoState('FallingState', 'Ducking'); } else if (NextState != '') GotoState(NextState, NextLabel); else GotoState('Attacking'); } state FallingState { ignores Bump, Hitwall, WarnTarget; function ZoneChange(ZoneInfo newZone) { Global.ZoneChange(newZone); if (newZone.bWaterZone) { TweenToWaiting(0.15); //FIXME - play splash sound and effect GotoState('FallingState', 'Splash'); } } //choose a jump velocity function adjustJump() { local float velZ; local vector FullVel; velZ = Velocity.Z; FullVel = Normal(Velocity) * GroundSpeed; If (Location.Z > Destination.Z + CollisionHeight + 2 * MaxStepHeight) { Velocity = FullVel; Velocity.Z = velZ; Velocity = EAdjustJump(); Velocity.Z = 0; if ( VSize(Velocity) < 0.9 * GroundSpeed ) { Velocity.Z = velZ; return; } } Velocity = FullVel; Velocity.Z = JumpZ + velZ; Velocity = EAdjustJump(); } function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType); if ( health <= 0 ) return; if (Enemy == None) { Enemy = instigatedBy; NextState = 'Attacking'; NextLabel = 'Begin'; } if (Enemy != None) LastSeenPos = Enemy.Location; if (NextState == 'TakeHit') { NextState = 'Attacking'; NextLabel = 'Begin'; GotoState('TakeHit'); } } function bool SetEnemy(Pawn NewEnemy) { local bool result; result = false; if ( Global.SetEnemy(NewEnemy)) { result = true; NextState = 'Attacking'; NextLabel = 'Begin'; } return result; } function Timer() { if (Enemy != None) bReadyToAttack = true; } function Landed(vector HitNormal) { local float landVol, minJumpZ; minJumpZ = FMax(JumpZ, 150.0); bJustLanded = true; if ( (Velocity.Z < -0.8 * minJumpZ) || bUpAndOut) { MakeNoise(-0.5 * Velocity.Z/minJumpZ); PlayLanded(Velocity.Z); if ( Velocity.Z < FMin(-600, -3.5 * JumpZ) ) TakeDamage(-0.04 * (Velocity.Z + FMax(400, 3.5 * JumpZ)), Self, Location, vect(0,0,0), 'Fell'); landVol = Velocity.Z/JumpZ; landVol = 0.005 * Mass * FMin(5, landVol * landVol); if ( !FootRegion.Zone.bWaterZone ) PlaySound(Land, SLOT_Interact, FMin(20, landVol)); if ( health > 0 ) GotoState('FallingState', 'Landed'); } else if ( Velocity.Z < -0.8 * JumpZ ) { PlayLanded(Velocity.Z); GotoState('FallingState', 'FastLanded'); } else GotoState('FallingState', 'Done'); } function SeePlayer(Actor SeenPlayer) { Global.SeePlayer(SeenPlayer); disable('SeePlayer'); disable('HearNoise'); } function EnemyNotVisible() { enable('SeePlayer'); enable('HearNoise'); } function SetFall() { if (!bUpAndOut) GotoState('FallingState'); } function EnemyAcquired() { NextState = 'Acquisition'; NextLabel = 'Begin'; } function BeginState() { if (Enemy == None) Disable('EnemyNotVisible'); else { Disable('HearNoise'); Disable('SeePlayer'); } } function EndState() { bUpAndOut = false; } LongFall: if ( bCanFly ) { SetPhysics(PHYS_Flying); Goto('Done'); } Sleep(0.7); TweenToFighter(0.2); if ( bHasRangedAttack && (Enemy != None) ) { TurnToward(Enemy); FinishAnim(); if ( CanFireAtEnemy() ) { PlayRangedAttack(); FinishAnim(); } PlayChallenge(); FinishAnim(); } TweenToFalling(); if ( Velocity.Z > -150 ) //stuck { SetPhysics(PHYS_Falling); if ( Enemy != None ) Velocity = groundspeed * normal(Enemy.Location - Location); else Velocity = groundspeed * VRand(); Velocity.Z = FMax(JumpZ, 250); } Goto('LongFall'); FastLanded: FinishAnim(); Goto('Done'); Landed: if ( !bIsPlayer ) //bots act like players Acceleration = vect(0,0,0); FinishAnim(); if ( !bIsPlayer && (skill < 3) ) Sleep(0.08); Done: if ( NextAnim == '' ) { bUpAndOut = false; if ( NextState != '' ) GotoState(NextState, NextLabel); else GotoState('Attacking'); } if ( !bUpAndOut ) { if ( NextAnim == 'Fighter' ) TweenToFighter(0.2); else TweenAnim(NextAnim, 0.2); } Splash: bUpAndOut = false; FinishAnim(); if ( NextState != '' ) GotoState(NextState, NextLabel); else GotoState('Attacking'); Begin: if (Enemy == None) Disable('EnemyNotVisible'); else { Disable('HearNoise'); Disable('SeePlayer'); } if (bUpAndOut) //water jump { if ( !bIsPlayer ) { DesiredRotation = Rotation; DesiredRotation.Pitch = 0; Velocity.Z = 440; } } else { if (Region.Zone.bWaterZone) { SetPhysics(PHYS_Swimming); GotoState(NextState, NextLabel); } if ( !bJumpOffPawn ) AdjustJump(); else bJumpOffPawn = false; PlayFall: TweenToFalling(); FinishAnim(); PlayInAir(); } if (Physics != PHYS_Falling) Goto('Done'); Sleep(2.0); Goto('LongFall'); Ducking: } state MeleeAttack { ignores SeePlayer, HearNoise, Bump; /* DamageTarget check if attack hit target, and if so damage it */ function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType); if ( health <= 0 ) return; if (NextState == 'TakeHit') { NextState = 'MeleeAttack'; NextLabel = 'Begin'; } } function KeepAttacking() { if ( (Enemy == None) || (Enemy.Health <= 0) || (VSize(Enemy.Location - Location) > (MeleeRange + Enemy.CollisionRadius + CollisionRadius)) ) GotoState('Attacking'); } function EnemyNotVisible() { //log("enemy not visible"); GotoState('Attacking'); } function AnimEnd() { GotoState('MeleeAttack', 'DoneAttacking'); } function BeginState() { Target = Enemy; Disable('AnimEnd'); bReadyToAttack = false; } Begin: if ( Enemy == None ) GotoState('Attacking'); DesiredRotation = Rotator(Enemy.Location - Location); if ( skill < 3 ) TweenToFighter(0.15); else TweenToFighter(0.11); FaceTarget: Acceleration = vect(0,0,0); //stop if (NeedToTurn(Enemy.Location)) { PlayTurning(); TurnToward(Enemy); TweenToFighter(0.1); } FinishAnim(); OldAnimRate = 0; // force no tween if ( (Physics == PHYS_Swimming) || (Physics == PHYS_Flying) ) { if ( VSize(Location - Enemy.Location) > MeleeRange + CollisionRadius + Enemy.CollisionRadius ) GotoState('RangedAttack', 'ReadyToAttack'); } else if ( (Abs(Location.Z - Enemy.Location.Z) > FMax(CollisionHeight, Enemy.CollisionHeight) + 0.5 * FMin(CollisionHeight, Enemy.CollisionHeight)) || (VSize(Location - Enemy.Location) > MeleeRange + CollisionRadius + Enemy.CollisionRadius) ) GotoState('RangedAttack', 'ReadyToAttack'); ReadyToAttack: DesiredRotation = Rotator(Enemy.Location - Location); PlayMeleeAttack(); Enable('AnimEnd'); Attacking: TurnToward(Enemy); Goto('Attacking'); DoneAttacking: Disable('AnimEnd'); KeepAttacking(); if ( FRand() < 0.3 - 0.1 * skill ) { Acceleration = vect(0,0,0); //stop DesiredRotation = Rotator(Enemy.Location - Location); PlayChallenge(); FinishAnim(); TweenToFighter(0.1); } Goto('FaceTarget'); } state RangedAttack { ignores SeePlayer, HearNoise, Bump; function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType); if ( health <= 0 ) return; if (NextState == 'TakeHit') { NextState = 'RangedAttack'; NextLabel = 'Begin'; } } function StopWaiting() { Timer(); } function EnemyNotVisible() { ////log("enemy not visible"); //let attack animation completes } function KeepAttacking() { if ( !bFiringPaused && ((FRand() > ReFireRate) || (Enemy == None) || (Enemy.Health <= 0) || !CanFireAtEnemy()) ) GotoState('Attacking'); } function Timer() { if ( bFiringPaused ) { TweenToRunning(0.12); GotoState(NextState, NextLabel); } } function AnimEnd() { GotoState('RangedAttack', 'DoneFiring'); } function BeginState() { Target = Enemy; Disable('AnimEnd'); bReadyToAttack = false; if ( bFiringPaused ) { SetTimer(SpecialPause, false); SpecialPause = 0; } } function EndState() { bFiringPaused = false; } Challenge: Disable('AnimEnd'); Acceleration = vect(0,0,0); //stop DesiredRotation = Rotator(Enemy.Location - Location); PlayChallenge(); FinishAnim(); if ( bCrouching && !Region.Zone.bWaterZone ) Sleep(0.8 + FRand()); bCrouching = false; TweenToFighter(0.1); Goto('FaceTarget'); Begin: if ( Enemy == None ) GotoState('Attacking'); Acceleration = vect(0,0,0); //stop DesiredRotation = Rotator(Enemy.Location - Location); TweenToFighter(0.15); FaceTarget: Disable('AnimEnd'); if (NeedToTurn(Enemy.Location)) { PlayTurning(); TurnToward(Enemy); TweenToFighter(0.1); } FinishAnim(); if (VSize(Location - Enemy.Location) < 0.9 * MeleeRange + CollisionRadius + Enemy.CollisionRadius) GotoState('MeleeAttack', 'ReadyToAttack'); ReadyToAttack: if (!bHasRangedAttack) GotoState('Attacking'); DesiredRotation = Rotator(Enemy.Location - Location); PlayRangedAttack(); Enable('AnimEnd'); Firing: if (Enemy == None ) GotoState('Attacking'); TurnToward(Enemy); Goto('Firing'); DoneFiring: Disable('AnimEnd'); KeepAttacking(); Goto('FaceTarget'); } state VictoryDance { ignores EnemyNotVisible; function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType); if ( health <= 0 ) return; Enemy = instigatedBy; if ( NextState == 'TakeHit' ) { NextState = 'Attacking'; //default NextLabel = 'Begin'; GotoState('TakeHit'); } else if (health > 0) GotoState('Attacking'); } function EnemyAcquired() { //log(Class$" just acquired an enemy"); GotoState('Acquisition'); } function PickDestination() { local Actor path; local vector destpoint; if (Target == None) { WhatToDoNext('Waiting', 'TurnFromWall'); return; } destpoint = Target.Location; destpoint.Z += CollisionHeight - Target.CollisionHeight; if (pointReachable(destpoint)) { MoveTarget = Target; Destination = destpoint; } else { if (SpecialGoal != None) path = FindPathToward(SpecialGoal); else path = FindPathToward(Target); if (path != None) { MoveTarget = path; Destination = path.Location; } else WhatToDoNext('Waiting', 'TurnFromWall'); } } function BeginState() { SpecialGoal = None; SpecialPause = 0.0; SetAlertness(-0.3); } Begin: if ( (Target == None) || (VSize(Location - Target.Location) < (1.3 * CollisionRadius + Target.CollisionRadius + CollisionHeight - Target.CollisionHeight)) ) Goto('Taunt'); Destination = Target.Location; TweenToWalking(0.3); FinishAnim(); PlayWalking(); Enable('Bump'); MoveToEnemy: WaitForLanding(); PickDestination(); if (SpecialPause > 0.0) { Acceleration = vect(0,0,0); TweenToPatrolStop(0.3); Sleep(SpecialPause); SpecialPause = 0.0; TweenToWalking(0.1); FinishAnim(); PlayWalking(); } MoveToward(MoveTarget, WalkingSpeed); Enable('Bump'); If (VSize(Location - Target.Location) < (1.3 * CollisionRadius + Target.CollisionRadius + Abs(CollisionHeight - Target.CollisionHeight))) Goto('Taunt'); Goto('MoveToEnemy'); Taunt: Acceleration = vect(0,0,0); TweenToFighter(0.2); FinishAnim(); PlayTurning(); TurnToward(Target); DesiredRotation = rot(0,0,0); DesiredRotation.Yaw = Rotation.Yaw; setRotation(DesiredRotation); TweenToFighter(0.2); FinishAnim(); PlayVictoryDance(); FinishAnim(); WhatToDoNext('Waiting','TurnFromWall'); } /* TriggerAlarm is used by unfriendly creatures to run to an actor and trigger something, or by friendly creatures to lead the player to something */ State TriggerAlarm { ignores HearNoise, SeePlayer; function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { local bool bWasFriendly; bWasFriendly = ( !bNoWait && Enemy.bIsPlayer && (AttitudeToPlayer == ATTITUDE_Friendly) ); Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType); if ( health <= 0 ) return; if (NextState == 'TakeHit') { if ( bWasFriendly && (AttitudeToPlayer < ATTITUDE_Friendly) ) { AlarmTag = ''; NextState = 'Attacking'; NextLabel = 'Begin'; } else { NextState = 'TriggerAlarm'; NextLabel = 'Recover'; } GotoState('TakeHit'); } } function SetFall() { NextState = 'TriggerAlarm'; NextLabel = 'Recover'; NextAnim = AnimSequence; GotoState('FallingState'); } function EnemyNotVisible() { //friendly creatures will stop and wait if (AttitudeTo(Enemy) >= ATTITUDE_Ignore) GotoState('AlarmPaused', 'WaitForPlayer'); } function Touch(actor Other) { if (Other == OrderObject) AlarmDone(); } function Bump(actor Other) { local vector VelDir, OtherDir; local float speed; if (Other == OrderObject) { AlarmDone(); if ( (Pawn(Other) != None) && SetEnemy(Pawn(Other)) ) GotoState('MeleeAttack'); return; } if ( (Other == Enemy) || SetEnemy(Pawn(Other)) ) { GotoState('MeleeAttack'); return; } if ( TimerRate <= 0 ) setTimer(1.0, false); speed = VSize(Velocity); if ( speed > 1 ) { VelDir = Velocity/speed; VelDir.Z = 0; OtherDir = Other.Location - Location; OtherDir.Z = 0; OtherDir = Normal(OtherDir); if ( (VelDir Dot OtherDir) > 0.9 ) { Velocity.X = VelDir.Y; Velocity.Y = -1 * VelDir.X; Velocity *= FMax(speed, 200); } } Disable('Bump'); } function AlarmDone() { local pawn OtherPawn; local Actor A; local AlarmPoint AlarmSpot; AlarmSpot = AlarmPoint(OrderObject); if ( AlarmSpot != None ) { if( AlarmSpot.Event != '' ) foreach AllActors( class 'Actor', A, AlarmSpot.Event ) { if ( (TeamScriptedPawn(A) != None) && AlarmSpot.bKillMe ) TeamScriptedPawn(A).Hated = self; A.Trigger( self, instigator ); } if ( AlarmSpot.bDestroyAlarmTriggerer ) { OtherPawn = Level.PawnList; while ( OtherPawn != None ) { OtherPawn.Killed(self, self, ''); OtherPawn = OtherPawn.nextPawn; } level.game.Killed(self, self, ''); //log(class$" dying"); if( Event != '' ) foreach AllActors( class 'Actor', A, Event ) A.Trigger( Self, Instigator ); Weapon = None; Level.Game.DiscardInventory(self); Destroy(); return; } AlarmTag = AlarmSpot.NextAlarm; if ( AlarmSpot.pausetime > 0.0 ) { Acceleration = vect(0,0,0); if (AttitudeTo(Enemy) > ATTITUDE_Ignore) GotoState('AlarmPaused', 'WaitAround'); else GotoState('AlarmPaused'); } else if ( AlarmTag != '' ) { FindAlarm(); GotoState('TriggerAlarm', 'Begin'); } else if (AttitudeTo(Enemy) > ATTITUDE_Ignore) { Acceleration = vect(0,0,0); GotoState('Roaming'); } else { bReadyToAttack = true; GotoState('Attacking'); } return; } AlarmTag = ''; if (AttitudeToPlayer > ATTITUDE_Ignore) GotoState('AlarmPaused', 'WaitAround'); else { bReadyToAttack = true; GotoState('Attacking'); } } function FindAlarm() { if ( (OrderObject == None) || (OrderObject.Tag != AlarmTag) ) //find alarm object { if ( (AlarmPoint(OrderObject) != None) && (AlarmPoint(OrderObject).NextAlarm == AlarmTag) ) OrderObject = AlarmPoint(OrderObject).NextAlarmObject; else if ( AlarmTag != '' ) foreach AllActors(class 'Actor', OrderObject, AlarmTag) break; } if ( (OrderObject == None) || (OrderObject.Tag != AlarmTag) ) { AlarmTag = ''; GotoState('Attacking'); } } function AnimEnd() { if ( bSpecialPausing ) PlayPatrolStop(); else if (!bCanFire) PlayRunning(); else PlayCombatMove(); bReadyToAttack = bMovingRangedAttack; } function BeginState() { bCanFire = false; SpecialGoal = None; SpecialPause = 0.0; bSpecialPausing = false; if ( !Enemy.bIsPlayer || ((AttitudeToPlayer == ATTITUDE_Fear) && !bInitialFear && (Default.AttitudeToPlayer == ATTITUDE_Friendly)) ) { GotoState('Attacking'); return; } FindAlarm(); // if ( (TeamLeader != None) && !TeamLeader.bTeamSpeaking ) // TeamLeader.SpeakOrderTo(self); } Recover: if ( (AlarmPoint(OrderObject) != None) && !AlarmPoint(OrderObject).bNoFail && !actorReachable(OrderObject) ) { AlarmTag=''; GotoState('Attacking'); } Begin: bReadyToAttack = false; Target = Enemy; TweenToRunning(0.15); bFromWall = false; CloseIn: WaitForLanding(); Enable('AnimEnd'); if ( OrderObject == None ) { Alarmtag = ''; GotoState('Attacking'); } If ( actorReachable(OrderObject) ) { if ( bCanStrafe && (AlarmPoint(OrderObject) != None) && AlarmPoint(OrderObject).bStrafeTo ) { bCanFire = true; StrafeFacing(OrderObject.Location, Enemy); } else { bCanFire = false; MoveToward(OrderObject); } } else { if (SpecialGoal != None) MoveTarget = FindPathToward(SpecialGoal); else MoveTarget = FindPathToward(OrderObject); if (MoveTarget == None) { AlarmTag = ''; log("no path to alarm"); GotoState('Attacking'); } if ( SpecialPause > 0.0 ) { if ( (AlarmPoint(OrderObject) != None) && AlarmPoint(OrderObject).bStrafeTo ) { bFiringPaused = true; NextState = 'Charging'; NextLabel = 'Moving'; GotoState('RangedAttack'); } bSpecialPausing = true; Acceleration = vect(0,0,0); TweenToPatrolStop(0.3); if ( (SpecialPause == 2.5) && IsA('Nali') ) SpecialPause = 8; Sleep(SpecialPause); SpecialPause = 0.0; TweenToRunning(0.1); bSpecialPausing = False; } if ( bCanStrafe && (AlarmPoint(OrderObject) != None) && AlarmPoint(OrderObject).bStrafeTo ) { bCanFire = true; StrafeFacing(MoveTarget.Location, Enemy); } else { bCanFire = false; MoveToward(MoveTarget); } if ( !bNoWait && (AttitudeToPlayer > ATTITUDE_Ignore) && ((VSize(Location - Enemy.Location) > CollisionRadius + Enemy.CollisionRadius + 320) || !LineOfSightTo(Enemy)) ) { Acceleration = vect(0,0,0); GotoState('AlarmPaused', 'WaitForPlayer'); } } if ( ( NavigationPoint(OrderObject) != None) && (VSize(Location - OrderObject.Location) < CollisionRadius + Abs(CollisionHeight - OrderObject.CollisionHeight)) ) Touch(OrderObject); else if ( VSize(Location - OrderObject.Location) < CollisionRadius + CollisionHeight + OrderObject.CollisionRadius + 10 ) Touch(OrderObject); Goto('CloseIn'); } state AlarmPaused { ignores HearNoise; function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { local bool bWasFriendly; bWasFriendly = ( Enemy.bIsPlayer && (AttitudeToPlayer == ATTITUDE_Friendly) ); Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType); if ( health <= 0 ) return; if (NextState == 'TakeHit') { if ( bWasFriendly && (instigatedBy == Enemy) ) AlarmTag = ''; if ( AlarmTag == '' ) { NextState = 'Attacking'; NextLabel = 'Begin'; } else { NextState = 'TriggerAlarm'; NextLabel = 'Recover'; } GotoState('TakeHit'); } } function SetFall() { NextState = 'TriggerAlarm'; NextLabel = 'Recover'; NextAnim = AnimSequence; GotoState('FallingState'); } function Bump(actor Other) { if (Other == Enemy) GotoState('MeleeAttack'); else if ( (Pawn(Other) != None) && SetEnemy(Pawn(Other)) ) GotoState('MeleeAttack'); Disable('Bump'); } function Timer() { if ( AlarmTag != '' ) GotoState('TriggerAlarm'); else GotoState('Attacking'); } function FindShootTarget() { local actor A; A = None; if ( AlarmPoint(OrderObject).shoottarget != '' ) ForEach AllActors(class 'Actor', A, AlarmPoint(OrderObject).shoottarget ) break; if ( A == None) target = enemy; else { target = A; if ( Pawn(target) != None) SetEnemy(pawn(Target)); } } function EnemyNotVisible() { if ( AlarmPoint(OrderObject).bStopIfNoEnemy ) { Enable('SeePlayer'); Disable('EnemyNotVisible'); Disable('Timer'); GotoState('AlarmPaused', 'WaitForEnemy'); } } function SeePlayer(Actor SeenPlayer) { Disable('SeePlayer'); Enable('Timer'); GotoState('AlarmPaused', 'Begin'); } function PlayWaitAround() { PlayPatrolStop(); } function BeginState() { Disable('EnemyNotVisible'); Disable('SeePlayer'); Disable('Timer'); } WaitForEnemy: Acceleration = vect(0,0,0); FinishAnim(); TweenToPatrolStop(0.3); FinishAnim(); Waiting: PlayPatrolStop(); FinishAnim(); Goto('Waiting'); Begin: Acceleration = vect(0,0,0); Enable('Timer'); SetTimer( AlarmPoint(OrderObject).pausetime, false ); if ( bHasRangedAttack && AlarmPoint(OrderObject).bAttackWhilePaused ) { Enable('EnemyNotVisible'); if ( AlarmPoint(OrderObject).ShootTarget != '' ) FindShootTarget(); else { if (Enemy.bIsPlayer && ( AttitudeToPlayer > ATTITUDE_Hate) ) AttitudeToPlayer = ATTITUDE_Hate; Target = Enemy; } if ( AlarmPoint(OrderObject).AlarmAnim != '') { TweenAnim(AlarmPoint(OrderObject).AlarmAnim, 0.2); if (NeedToTurn(Target.Location)) TurnToward(Target); FinishAnim(); if ( AlarmPoint(OrderObject).AlarmSound != None) PlaySound( AlarmPoint(OrderObject).AlarmSound); PlayAnim(AlarmPoint(OrderObject).AlarmAnim); if ( AlarmPoint(OrderObject).ducktime > 0 ) { if ( Target != Enemy ) Sleep(AlarmPoint(OrderObject).ducktime); else { if ( TimerRate <= 0 ) SetTimer( AlarmPoint(OrderObject).ducktime + 1, false); MoveTimer = TimerCounter; While ( TimerCounter < MoveTimer + AlarmPoint(OrderObject).ducktime ) { TurnToward(Enemy); sleep(0.0); } } } } Attack: if (NeedToTurn(Target.Location)) { PlayTurning(); TurnToward(Target); } TweenToFighter(0.15); FinishAnim(); DesiredRotation = Rotator(Target.Location - Location); PlayRangedAttack(); FinishAnim(); Goto('Attack'); } if ( AlarmPoint(OrderObject).bStopIfNoEnemy) Enable('EnemyNotVisible'); if ( NeedToTurn(Location + AlarmPoint(OrderObject).lookdir) ) { PlayTurning(); TurnTo(Location + AlarmPoint(OrderObject).lookdir); } if ( AlarmPoint(OrderObject).AlarmAnim != '') { TweenAnim(AlarmPoint(OrderObject).AlarmAnim, 0.2); FinishAnim(); PlayAnim(AlarmPoint(OrderObject).AlarmAnim); } else { TweenToPatrolStop(0.3); FinishAnim(); PlayPatrolStop(); } sleep( AlarmPoint(OrderObject).pausetime ); Timer(); WaitForPlayer: Disable('AnimEnd'); NextAnim = ''; Acceleration = vect(0,0,0); Wait: if (NeedToTurn(Enemy.Location)) { PlayTurning(); TurnToward(Enemy); } TweenToWaiting(0.2); FinishAnim(); PlayWaiting(); FinishAnim(); if ( (VSize(Location - Enemy.Location) > CollisionRadius + Enemy.CollisionRadius + 220) || (!Enemy.LineOfSightTo(Self)) ) Goto('Wait'); TweenToRunning(0.15); GotoState('TriggerAlarm'); WaitAround: Disable('AnimEnd'); Acceleration = vect(0,0,0); if ( (AlarmPoint(OrderObject) != None) && NeedToTurn(Location + AlarmPoint(OrderObject).lookdir) ) { PlayTurning(); TurnTo(Location + AlarmPoint(OrderObject).lookdir); } if ( (AlarmPoint(OrderObject) != None) && AlarmPoint(OrderObject).AlarmAnim != '') { TweenAnim(AlarmPoint(OrderObject).AlarmAnim, 0.2); FinishAnim(); PlayAnim(AlarmPoint(OrderObject).AlarmAnim); FinishAnim(); } else { TweenToPatrolStop(0.2); FinishAnim(); if (NeedToTurn(Enemy.Location)) { PlayTurning(); TurnToward(Enemy); TweenToPatrolStop(0.2); } PlayWaitAround(); FinishAnim(); PlayWaitAround(); FinishAnim(); PlayWaitAround(); FinishAnim(); TweenToPatrolStop(0.1); FinishAnim(); } if (AlarmTag == '') WhatToDoNext('',''); else GotoState('TriggerAlarm'); } state Greeting { ignores SeePlayer, EnemyNotVisible; function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType) { local eAttitude AttEn; Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType); if ( health <= 0 ) return; if ( Enemy != None ) { AttEn = AttitudeTo(Enemy); if (NextState == 'TakeHit') { if (AttEn == ATTITUDE_Fear) { NextState = 'Retreating'; NextLabel = 'Begin'; } else { NextState = 'Attacking'; NextLabel = 'Begin'; } GotoState('TakeHit'); } else GotoState('Attacking'); } } function Bump(actor Other) { //log(Other.class$" bumped "$class); if ( (Pawn(Other) != None) && (Enemy != Other) ) SetEnemy(Pawn(Other)); if ( TimerRate <= 0 ) setTimer(1.0, false); Disable('Bump'); } function Timer() { Enable('Bump'); } function EnemyAcquired() { if (AttitudeTo(Enemy) < ATTITUDE_Ignore) GotoState('Acquisition', 'PlayOut'); } function AnimEnd() { PlayWaiting(); } function Landed(vector HitNormal) { SetPhysics(PHYS_None); } Begin: MakeNoise(1.0); //log(class$ " greeting"); Acceleration = vect(0,0,0); TweenToWaiting(0.2); } }U }-G' B B O \O uO PO LSN Tl O TfTO fB FO qO nqVeC B Zq7TbfXO rT rsO ~ St fw O sO eO }TF w!eHBU TdO QqMq/O wSSTx O PTy eIfPf} fxO lr{ qAw|O BT@ O O TC O BB qgO KqrBOfJq;qTq]rdfOqF P qlq<O UBpO jqqf{qjqIqI B Gr| B zO yB NB oB IePP+rCP@P P3P5BGBCM~O APO  rlO c rhPP0P&PPPP P P B }P6PEr|PlfL PFq]B N B s O ~O fB {PYqEPQB cqKfv O ZeC eAB q rjfB qz B zB yq_B^fpO AP1B r B @B rfHq`rGO f rFO VeTw\qAPcruPyrmO WO ZPxP"qG qpqTO i O h T\q} qUB ZTarH BV TDO SfSeLrrfb PpPIO ]T{O pPiPjPXevPfqJ PFs{OB }rgs|rt TCqSB dr~B {w_drd O p TOH wbfWqD PwXQPyTA wyrYqLO g PFO drJeU fzsUwKr|ezwaO oq@eQrLf=O CrrfMfVB~ rVB`P Ps edPS fhdO qPR PPsftfNd{fLf^ Pxq[eVqw rfcqLP[ PZPUf[B@ qS fSO [rhrWTqsDsEq{ s@snrKspFsMsHO _wMsouf~asoxPrUO o PrTsnaspO LO vslswQspHsksjsvsvusvsB isnsZs=~sxsRfZQI PJf~`^ qswPssUeRsvPJwT O e TaO p O ^ s=~PF P{PEO k O U f[frTPlO ` PCO a TCO W s=mP|O Y P@ swje| q]O [ wNswbPJfDPqO N wwO n O o O s O j w_whfzO Q rUf|PAP[wcwarYwlPq dzwt[K O D PL f~rXrVrsrQ erDerPerPwr}sHsIsWsJsKsLsVsFsHPM P[swTTCTCO zsyP&xP9O DPnsT]w^ qWBZPMP2swSO Z O \ PZsssoscsnsisXs@s~sErXs7es7`sT[sT^sowsovsoysovsotsousT`sTasYsXsUsVsTsPshsKsLsH^ 5FsMsHsrsIsqsJspsxsosk^ 5kslsesospwfssstsysPszqGs}s7gO X sWsSsQsMsOsNsJsIsGsdsnsqsuswsBs|Pr PW[PG O YO hO BPEO IO Xwn^ owwT^O bO ^sGsCO gPOtPvO `wrsAr`qsBO HsxO MO [O \^ 5Ww~PbsT\qOz rUrI wPwOwNO ewKP]rCP}^ 5MwhPjsowsT_swOwLw\O RPYswRswNww][`Wsr^ j^ k^ i^ lsssds`s^^ msBsrsqs{Ns{Ps{Ssosnsmsksjsishsesgsfscsbsas_^ ]sn_sn`snbsvt^ Q^ ~svwsPsOsAsNsJsBsCsCsFsGsHsIsJ^ [sisvysossstsuwsp@spAspGB }sIs{Ls{Ms{Qs{Rs{TsncsndsnesnfsvvsvxsKsLsGsIsFsDsEsAs@ssvzsv{smslsqspsrsw^ ~spBspDspCspEsn^Bef^O VO qs7fO kO P`O nO cQk Qo s{O APO zO ] PTP^ Pr Pq PV Pn QE Qm QJ P Pl PRPXwEPvuPD ]HMn_  va  C\  PX  ]c XiQk AeBO @ QT Q __ mr yT FD SP  `DlQ  z> Gu SdI ac  nm {p HK TP  a4^nYiL\i MZlu gXS uW C,7PX Gd  T$$a E ELRC `_mnLO Z N gmu \C TQm oK |nIu W0x e#^rLPZ  ^akvsy2/lyl [0z i }vnE { SV `O m_y?V: dH p_M }QG  Km  X:p eLbrpA iP`K^7Ai>p wG CX O n\T njwexn]wnk yX EfD]|k AzXl H aVZ d vpf  ~QKnYP gstEBnPL] U^~ sqAA OR[XP i AuD@Ci RR  _h lR yAgGgnU |(AI X WNed/h Ir W o dS  qs~2\ L{X2` f\aU s\^ H\]UscO  q i~Zp L0{ Y0y  fUcs: `Vv dLr q {} AK |  Y UeQ^sc BN  Oh\sj Ax{FATb  bl oe}Z m [ h stTm B YOX J^ OhIvl DP R\ _Om k o xEz EXh S| aLoo]^nlzz0r HgAT l bfpp ~^ KyS XXK fXE  s S @p Nm ZXh ggk u ]BJQl _Eml {l I X W{ d0^ q/w ~ULp Znfwl t ABXw Pw ^h l{ z2p GXnTBb\\p\[ ~0s Kp YyF eyE  r/n vLuZw hnvnDs R ^W IjXF s~0@V0pp `W3=mhjsxvFq l T] bD^oIM%^[XDyXnGRU RcXXq&v rALL| Z ng*p u l B} P w ^ v l v yh FT l Sla94op ccT  pcH }Ip K lW(z el s({ A{O b ]sjp xb D{Qh_{mgs{yW Ip UpbL~p b ~`KnYXf  g`tr{ Brz POm ^ vkb7yIG ppc }pd K@ Y nf:HtwO|D KXw W p e T  qdM ~ TK V Y^| fp b on{S IW  WG dF pn}E  Kr]X E fK  rwp sLlZL p hT {t h BsG P` \yu  i\r vyK BHO0 A ]]j nx { F{ R p `z l rzAHYAI {WYfeg cshVrg drYsJBA(k C[6Ozn En s_b@YN]  \m hm up[Brr]D|  Og|  \V  il  vJ  C[  PR ]Si v xhElW S f  `e l t y cFrk T9_Q ` Y qP  ~xk J2 o W!i c._ pf  }yXIyf  W d  pi R ~C KL o W p dpnp]A ~]p Kp] W\6Idwlmmp {wf  G K Sl`kncA }bo J fV ndf  rJv ~ RuK v @XMGA\EAj fxWF f Unb f  p l|] J_ Wp d(_ qc ~K JbW ref  sf  fKx YC f}s0vA{Ov ]sp jAwfEXSf  aWQm p ~  K ] WYdlrIUw@Xn w0z  D>p QT^ v m\z>U H ] p ivTvd ET f  ST l_]ml{ p I  VuFb  q3-}v{jW x e  Eh RX] ^ /kk Z n fg sxB {`GnSdL A Z mg sv hD oR E  ` { m9k zS  GQj  T s`-n p J y  VDyc p q u}_KO YU fO rp  hK lY Q hp  uqXB ]ZVhi w/sDXu R_c `_F lXsyXhG/hU g c u p f ~ _J e XS} e G  q$ C }`I* i WgdgyrcN @` MS|ZR i fv p D jP {^vA  lSyQ GQ`Tq f  cvTob}q {KY Yg@fy  u A A RNSV]wse j u w jEq ST h` +nR mYR t hL p tO @CMp [H_gY FI g Ts bZ oj{VI` W Ve]sTA lO: } ^E k ]x  FZ R[ _ Q lIo yS E\{R!"Da\te CtG  B TN h\ sjkx\Z F jT r  b{ o W |\eI CW Ee!j s\_@] N(H[Xc r  rm A  v L O Y0tf0\u0uCI  QfA ^0w k)i x"QE @ V4\#'cW JmV dC ph}E{  K)|  Xdeap s!y  y  KsWp esry  @sL- AZ@ hXhup CXsPh^y  lTxi FdbS]aC oV{f  I XVsuhCi  Q* ^rA jk wk D AQv_|  mS  z~ GS Up{ay  oM  {r  HgUWcQqE SLB Zfp gy  slo @lh LjYCg]uTCn QE  ^]kr  yA FN S `A lT Zyrf  Sh` ]n] |' [ I3 g VLcc~ r^ G  p^H|z DVQ]_ ^mR {{ HT hVTd y  rY ~T sJqhXfvf] \^iZ [ wADmRV`> g nGa{Z\ sjKx [ H@ Up a+hm 0U|  ENE RTWl  esr[ @[ MxPZ\j RFnTYg b}  nJ z hG g U ]a[to RcJtqb esshA ]OM ] 8i39ahZTh]v|TDm X y  e r  qI} K K|X ]ft 37t| k`  /y y  hnt i B m  O{\whjwsx hF[ Tf~aQe _ j lpsxph FKy  SIy  _`kGy  K o W ndn r n sLQ y  ZEy  fCy  r\t~ s[ n i 0v~f R dPqI\UR [ Q\p^"i l\Ay A G ] T g a| nN }c y  KrTX%O f\Ns%AA ^O ]] } kuy  w p Dq nQ:_\Y* k h* vunC[Qrl  _] p ltxZG n UW y  bU y  n.zI YHH v  V y  cS y  o^{ OI \KWc|  by  oA{SuI NX@ gy  ty  @x  LX]Y\ @g\3#g]JXsXXhf N ty  BhNvV\lO jTwLEuT c[ oR|w JVX]f8v  t }Au ~H JU W]ccZq(}G@czG} VTbVpV ~AKgK Yy  fD rS ~M}y  Ky  Wy  cq N os}:y  KhXq u f WrT@p NZZ Vhky  vU_  BW  Nw []gT )uL  ^ Wko y4^Fk dsq|   xKTY]ghu k CO| ][0e#iVLJIZdZcy]qLB]MT[LQiLcwk| ESUQJ| `v  nD{y  IsVJ!d)x  Ey  Rk ^u jJy  xy  DsP`^y  l g xy  D RP0U^0x m0g {0y I]y  VdrSbAuQ C OK [R iv`y  D> Px \N j@x` xk Ek RL1`L QL 1^k Oe \]dik My  [k gy  ty  @/ y  L|  XTd|  ry  ~rVJAXsf A tvAsO L ]N j Cx v{H|  I N UR  cVpnr~N p|  ~vJLAX|  fk sv@sNLe \LFjLEx sV vd\$rM|  V$bLa Fk TMN aMso|  }` IR  VMk cA pr@ }n  JLxTWdJkdAydpGk Uvb Vpdk FR  SN ` 5nBcJuqsf^gtv[(YiC}B( iahd&Iy  ork{hI!,0W\y  G |  STy  _ vkNy  yd KEd1P sA N OA ] k iHk v ] C |  P v\h j |  wHN Ddy)RHv{q I sV sd N r k @+ k M; |  ZTg f; vF k T; sak o; N |sJ=sX; k fZstlQ_"#}=k `v |  lq |  xq vE:FSq sbq k pk }v vJPnXv sFsTvb|  py  |k Hv N V {dv k rA W\LW!h |  I vUW+Qc Kt s N Mcm[ k icf vdAC AD |  R v^ k l sy @ GWxTTy  h N tPy  BvNMy  \ k h R  uYK BVy  Ps\N j}a xdsY I |  g I vs I sA dk O dy  \ dN i |  w dvC I N Q I k _ sl bGz A A N N R  \ |  i k u vB k P s] N k 9N y 9sG 9vU 9|  c k o d|  | XA H "#T |  w !C 1!d vE sS N a k o \H[| w  W Mvc |kq A\ imj hW vA e sr  ] @ N O  ]]  K k jy sG |x  U |w  b 8 vJn ix N F vT m  b 'Yo |  H  ")T h } SJ G;] hX sf Hst Fy  B ny  N hZ y  h ht y  B sN [ \ +s i y  v +|  B +K O v] sk |  y hE p y  S z _ y  m j y  z ]F  y  T `  y  o  y  { NG  y  V ^|  b ^N n ^s| |  J ah V vc sq h  jL m  Z Fg Xu LC a Q h ^ n k ky h G kT @ b k o x { s I |  V y  c ip w  ~ x  K VX I \f-f k S x _ y  m hz vx H vy  V vk c x o y  } EBJ k L \LX \{f \Et \oB A P \p] \nk iy \DG \V U \X c hq s N M s[ 0]i y  F k R }y  _  @ k V x @ E sR T` y  n Yz VH TV y  d Vq y   y  K y  X y  d y  q q } k_K fIY Jb N p y y  ~ `K 0DY y  g 0ns 0sA y  O y  [ y  g # y  s $ B STM SQ[ 0t i 0~ w 9 2!E l f ls 0dA NO E  ] ^vi y w UD ^k S y  ` y  l y  x KiD 8v\R @ n @| q hJ By  X q sd "y  r ~~ ?y  L * |  X 5y  d * sp y  ~ [eiJ Vs XN A y  N |  Z vf st N B |  P k \ k #|i (Ae {  f fE s \FH O|  G T|  T va W,o } j @[ |  [ S|m g33k jX 1^ iX JO E Y S Me eVTr j-}F x C g P WX ,] Q433I W4 %| vX y)a \ d(,J 8v[v Dk Q c&^ DvD SyAR L &S _|y DKu O 6@ X&v ds 3\ BX rDO p@S |  S dt J_ IZi oc%,C b %o du 3T }UUJG UlQ @@} [ } `>J (kH wdNms SF%` E E i@Q B<r(Q j@y k y |  E |  Q BU(] CUE)E DU$(n hw[V T Nq } U ' g:af F_G d~Tf LU0'z ]GPa |  q FI} S3F sHdy RUy)] SUF*F IcUGp UUy$w [xl[ 9c27G XU'~ ccwe /N \ [U5(i ~U #Q [evt 92Bj c 3l S Z_ [ y Dd>,F S0'r 7|  Y dF@e <|  e :K q u=_}~ v{ dj@I y d,I c/u S&^ L@-\ $L$+I S6Et 0G Ky 40#dD ~0GCh 0ijk YJBU x W A e s r UQ |  P Sl_] S #| JU&'_ NU'F 1m 0qqJ {"F{ hA N O g[ \ 0(,B +Xn S5qF  3w X  _j (YI A b x o PUQ)} QUY)f %E O D[ ni ow pE {S VU #a LF)D LY(m LQ)U s ~ WU#K ZU#n |  Q g^ .T5l Z#a eVRD jLV Ul;b r '] [ D LlxQ  E I |  U L 'b L5UI S'^ L f"E [g f|pu dU@)e x  N bUN][ L&x - [^ ]0l d@.\ J"(J o %,r [ ^ k k _ W-x Ze L&&  ze L :_ &nY L&G 0Zm LE!G oh S PW  Dg hiEk dp 5@T TqT  'E lpl L E\ L]5a nU@4V Z |  J ?|  W S c s |  C i@O 1|  O j@[ 3|  [ F_g Dc>,F UnZr @U##L }6@o 42o 4#2a FS 'Y S j@ di@j 7a j jU,w k c H|  p Y ^f| [ Sb G[u eLSrC L|  u ^ .A \ Cno L Lf"] Qh  U &L r Ar NYP d '^ x"#E z h { v d0&D TP-j eU bW UgWy w[M P 9S2!] c j~ Wc,h d&&T d ]z ^W sFu lY{ [ "(T $d$,| @ ch  E4K x+! (xS`  (s  39[ m J-T fiCA Jb-D b kCq Scit  &]  @.C  Y)q pSJ7Z !R  Q dV^ . T4t a J2h ([aZ  ^{ OWY k p   } A ] m D/j f~!Ym J@z C|CAW1DDaWb:Hq[ B WPOa B_k #Na@6omDge_eLtvZji4wDeSL{!W,CG[J1"Xb Xzw Rd UJ`s}jS Rgf1y c,j_e7VsHmMI6FzN @h L[ Zx |-fY  VSk [7iY@`rAq`}{Qk LL6\X\ t[ A[ N`R[i4}mE jabAvsw@c tEYJLy!,0Ehui4{CZP~@f iNXp wwNlC[ oD|j^@rL^hjx\x+&Ti4tzzi4Xzn`_F Pe] tqu[f p A$$`M Dm 3-q #^i4LA o^M ^mkA _0X 1"Hya j AKV R;Y1 i4{T  `OuPo9 I9+"H91j5xGuK I *Lk #!vHZcW@.zfFhh ^ Pz,oB  ,[| ^-G 3,tD>,`Q" 3,LW,xg$ 3,dzf-P@ & 3B}o%Nx(wMM ) gDBI9Ik `teSbBQ[ dL0&qc) kW@d MBb) #SO: x bX) e}o4 h l4 N zc) HwF}) b}Y ) 3-_yIqrL Ib~@ `X&lkRZ `I knI @ |`IPWEGeL lcwL92OCxMRrIAW_!,8vd~=n zk_ ?e dE!D$$$eAI_TcJ QmA__M~&iK_!t0?U_+!T$uIIY hbhJ5br!_,0T CDlrG` |  y` s F6ASJh Tc x ac k oy*{X*eQ)OY)xF*ak E K@6WH?M.LT~Lu i4JwNYIq [ bp@oN@ oe x| _qtj ;e!j,0`U 3P4#9Cy!|o%,]^| 4@Il| -I| 3'vjq] hNI ")\jxRENk W5|  dF)pj Y E yg E@6R| ^FHKFNKW\KhjKsxKn FcKS92E^ 2c2UE3G$$+z&e 1*K :uB 9.o&:]c ,2W08I y  A&MK[s aA2b5IT 0]l@M |  M s Z6&g}}-M x z k HQ5TY(IF*q E [@6g@ J]h Jgl Jq4t{Aj_#oy'R 3,Qr O} [ Lj+!Y k z\i4QF jqW WH Zg_cOF +^UK v\sa  ,O k{ "7f h ] (jW,Rc +"~b *`o%pJd Lzi "(FS  ,njd-ZPU 'Gx ns HBN^ 1!P $ql 'U  3#| Ax_4_ BNS A _#a Q  G-D i4wq   h! +!H!V R^i! hG!as U! xRH!! ,1Z!J XCK! iN!d~;w!eV;r!hwGm!g:\t!q bP! 4^r!RsP! i4LSC!b^O"Oc m" E ,P" k ,|"AYh" o ,A" i4lm"_ $Y"] H}" m ,E"z x `q" oQ" J ,@" !l"4M"E5A"$$Wv"i4LM"BY$ F*[$  Ae*+!s*7 #T*h}w* B t*C k P*C N ]*C sk*C vy*C |  G* iS*X i4m|* Ai* 4pj*.T5Z*mD)O*N x  x*N w  E* uDQ*x |-U*cKB*wNCM*T [ P*Y|  ]*Z hi*dh Ew*[ i4u|*xXq*j xI*A_#A*927d*Q;[*x V*^ [ d*!,1q*R b*[[!* (`*(H*E)p*$$TY*Om*TDx|* dt*T+3X*&dK*(TNo*0C}*n y  @*OL* T\[* .w*.e*5BS* KU*ld`*v |  D+v s Q+6&^+ (D+y x l+y k z+Q)F+Y$o+F%S+ E x+@6D+4*z+k Id+4#em+(8R+y ,J+u _Gv+onz}+i Pw+ |  G+ l\T+[ p+[ eS|+ h O+ItM]++!j+ 3K+abB~+cQ@+ 3Q+ A @D+ N D+ RrP+[e{B+ i4Q}+}13N+ iA+ ?j+cv ri+h [+&h+Si4K[N+ p Y, &&e,xh K,]%X,L %},92jb,[[#L, uo, p d,8p,E!h,$$pI,,Z.a xKF.w[ Q.n^.W cL.L 5o.A_#d.RG.W,U.q x]A. @I^. [ g.b vt. dj. Y)N.[ w.SUD. Y. k u. N B. sP. v^. |  l. xx. g W.r Ad. YC. @ Q. k ^.k fk. K J. |  X. s e.J Xpr.|  b. [ n. -z.hrg.  Y. k u. N B. sP. v^. |  l.( Fx. K~.A _&I. uo.OEd.x "#i. h L. AY.vvZ.uwP.U"G.Toi.%[X. [g.ci4hv.xW^/ [ u/di4KA/Li4QL1 ^]2i4Ik2 [tC}#U'BC