*~(@<e{wȟElB(None BoneNameReqMinHitDistanceDamageEmitterAdvancedEmitter bCompletedSubDamageBones DamageModbFataloffsetVector RForearm LForearm RUpperArm LUpperArmMeleeAttackAnim bFunctional ReqBones DamageDelay DOTZEngineEngine BDHSZombiesCore BeginPlayJawSpecialDamage HeadTexturesAdvancedEngineHealthLCalfXDOTZCharactersUserRCalfNamesHeadMesh BodyTextures AttackingDONEBegin EndStatePerform_MoveToLocation BeginState RefireRate DoSpecialWeaponFireAgainTrySeekTargetSeekingTryClearObstacle UpdateFocusInAwarenessRange EAT_STUFFOnThreatSpotted AcquireEnemyEatinggetAttackPointWanderPerform_MeleeAttack EndCharge OnHeardNoise SameTeamAsIsHumanControlledOtisOnBumpBDHSZombieAIRole configure AttackBiteSystemInitPerform_Eating DontBeStupidDEBAIT MeleeAttackSMASH_OBSTACLE StartChargegetChargeDurationCrawlingMeleeAttacks AttackRightA AttackRightBAttackTwoHand AttackRightC AttackLeftA AttackLeftB AttackLeftCgetSmashActorCrawlAttackFallCrawlAttackBiteAdvancedPlayAnim ShouldChargeCrawlAttackRight MeleeAttacks MultiTimerBDHSZombieAIControllerBDHSYoungAdultFemale DebugFlagsBDHSTeenagerMaleBDHSTeenagerFemaleBDHSSkeletonMaleBDHSSeniorMaleBDHSSeniorFemaleGetAttackLocationPlaySpawnAnimBDHSNurseFemaleBDHSMiddleAgedMaledoSmashBDHSMiddleAgedFemaleBDHSHospitalPatientMale BDHSHoboMaleBDHSHoboFemale BDHSGoreMaleBDHSGoreFemale BDHSCopMale GameplayMinWanderDelay AttackRangeMaxWanderDelayTheExclaimManagerHumanPawnBaseLastSeekRefreshTimeiAwarenessRangeCrawlEatingAnim EatingAnimMaxChargingZombies AttractorInAttackRangeScuttlingZombiebAllowedToChargeOnThreatHeardMaxTimeBetweenChargesOnWitnessedKill OnLostSightOnTakingDamageMeleeAttackSucceeded ChargeFailedMinTimeBetweenChargesMinChargeDistMaxChargeDist SeePlayer HearNoise PreBeginPlayDefaultWeaponType CrawlEating KilledByPerform_Error_Stop ShouldStrafe shouldWalk IsFiringSetCombatTimerTimedFireWeaponAtEnemyBDHSYoungAdultMaleNotEngagedWanderFailed OnKilled JackSlade OnHitMover OnHitWallbMeleeAttackCapableGetLocalPlayerControllerAITypeSetRandomFocalPointLocationPerform_NotEngaged_WanderSpawnExclaimManagerbRangedAttackCapable GiveWeapon DisplayDebugpotentialEnemy exclaimMgrf myAIRole curBehaviourYPos InitialStage BBPGibLeg BBPGibJawBBPGibForearm BBPGibBicepSetPos ScriptText DOTZTZombiesFemaleNurseBodyShaderA FemaleNurseFemaleNurseHeadShaderAFemaleYoungAdultMaleMiddleAgedFemaleYoungAdultBodyShaderAFemaleYoungAdultHeadShaderAFemaleHoboHeadShaderAFemaleHoboBodyShaderAMaleYoungAdultHeadShaderAMaleGoreHeadShaderAMaleGoreBodyShaderAFemaleGoreHeadShaderAFemaleGoreBodyShaderAMaleSkeletonHeadShaderAMaleCopHeadShaderAMaleCopBodyShaderAMaleSkeletonBodyShaderA FemaleHoboMaleYoungAdult FemaleGore MaleGore MaleSkeletonMaleCopMaleMiddleAgedBodyShaderA MaleSeniorFemaleMiddleAgedBodyShaderAFemaleMiddleAgedHeadShaderAFemaleMiddleAgedMaleMiddleAgedHeadShaderAMaleSeniorBodyShaderAMaleSeniorHeadShaderAMaleHospitalPatientHeadShaderAMaleHospitalPatientBodyShaderAMaleHoboHeadShaderAMaleHoboBodyShaderAFemaleTeenagerHeadShaderAFemaleTeenagerBodyShaderAMaleHospitalPatient MaleHoboFemaleTeenager MaleTeenagerMaleTeenagerHeadShaderAMaleTeenagerBodyShaderA FemaleSeniorFemaleSeniorBodyShaderAFemaleSeniorHeadShaderAMaleYoungAdultBodyShaderAMaleYoungAdultBodyShaderCMaleMiddleAgedHeadShaderCFemaleNurseBodyShaderBFemaleNurseBodyShaderCFemaleNurseHeadShaderBFemaleNurseHeadShaderCFemaleNurseBodyShaderDFemaleNurseBodyShaderEFemaleNurseHeadShaderDFemaleNurseHeadShaderEFemaleNurseHeadShaderFFemaleNurseHeadShaderGFemaleNurseHeadShaderHFemaleNurseHeadShaderIFemaleNurseHeadShaderJFemaleYoungAdultBodyShaderBFemaleYoungAdultBodyShaderCFemaleYoungAdultBodyShaderDFemaleYoungAdultBodyShaderEFemaleYoungAdultHeadShaderBFemaleYoungAdultHeadShaderCFemaleYoungAdultHeadShaderDFemaleYoungAdultHeadShaderEFemaleYoungAdultHeadShaderFFemaleYoungAdultHeadShaderGFemaleYoungAdultHeadShaderHFemaleYoungAdultHeadShaderIFemaleYoungAdultHeadShaderJMaleMiddleAgedHeadShaderBMaleMiddleAgedHeadShaderDMaleMiddleAgedHeadShaderEMaleMiddleAgedHeadShaderFMaleMiddleAgedHeadShaderGMaleMiddleAgedHeadShaderHMaleMiddleAgedHeadShaderIMaleMiddleAgedHeadShaderJMaleMiddleAgedBodyShaderBMaleMiddleAgedBodyShaderCMaleMiddleAgedBodyShaderDMaleMiddleAgedBodyShaderEMaleSeniorHeadShaderBMaleSeniorHeadShaderCMaleSeniorHeadShaderDMaleSeniorHeadShaderEMaleSeniorHeadShaderFMaleSeniorHeadShaderGMaleSeniorHeadShaderHMaleSeniorHeadShaderIMaleSeniorHeadShaderJMaleSeniorBodyShaderBAMaleSeniorBodyShaderDMaleSeniorBodyShaderEFemaleMiddleAgedHeadShaderBFemaleMiddleAgedHeadShaderCFemaleMiddleAgedHeadShaderDFemaleMiddleAgedHeadShaderEFemaleMiddleAgedHeadShaderFFemaleMiddleAgedHeadShaderGFemaleMiddleAgedHeadShaderHFemaleMiddleAgedHeadShaderIFemaleMiddleAgedHeadShaderJFemaleMiddleAgedBodyShaderBFemaleMiddleAgedBodyShaderCFemaleMiddleAgedBodyShaderDFemaleMiddleAgedBodyShaderEFemaleTeenagerBodyShaderBFemaleTeenagerBodyShaderCFemaleTeenagerBodyShaderDFemaleTeenagerBodyShaderEFemaleTeenagerHeadShaderBFemaleTeenagerHeadShaderCFemaleTeenagerHeadShaderDFemaleTeenagerHeadShaderEFemaleTeenagerHeadShaderFFemaleTeenagerHeadShaderGFemaleTeenagerHeadShaderHFemaleTeenagerHeadShaderIFemaleTeenagerHeadShaderJMaleHoboBodyShaderBMaleHoboBodyShaderCMaleHoboBodyShaderDMaleHoboBodyShaderEMaleHoboHeadShaderBMaleHoboHeadShaderCMaleHoboHeadShaderDMaleHoboHeadShaderEMaleHoboHeadShaderFMaleHoboHeadShaderGMaleHoboHeadShaderHMaleHoboHeadShaderIMaleHoboHeadShaderJMaleHospitalPatientBodyShaderBMaleHospitalPatientBodyShaderCMaleHospitalPatientBodyShaderD AccelerationMaleHospitalPatientHeadShaderBMaleHospitalPatientHeadShaderCMaleHospitalPatientHeadShaderDMaleHospitalPatientHeadShaderEMaleHospitalPatientHeadShaderFMaleHospitalPatientHeadShaderGMaleHospitalPatientHeadShaderHMaleHospitalPatientHeadShaderIMaleHospitalPatientHeadShaderJMaleTeenagerBodyShaderBMaleTeenagerBodyShaderCMaleTeenagerBodyShaderDMaleTeenagerBodyShaderEMaleTeenagerHeadShaderBMaleTeenagerHeadShaderCMaleTeenagerHeadShaderDMaleTeenagerHeadShaderEMaleTeenagerHeadShaderFMaleTeenagerHeadShaderGMaleTeenagerHeadShaderHMaleTeenagerHeadShaderIMaleTeenagerHeadShaderJFemaleSeniorBodyShaderBFemaleSeniorBodyShaderCFemaleSeniorBodyShaderDFemaleSeniorBodyShaderEFemaleSeniorHeadShaderBFemaleSeniorHeadShaderCFemaleSeniorHeadShaderDFemaleSeniorHeadShaderEFemaleSeniorHeadShaderFFemaleSeniorHeadShaderGFemaleSeniorHeadShaderHFemaleSeniorHeadShaderIFemaleSeniorHeadShaderJMaleSkeletonBodyShaderBMaleSkeletonBodyShaderCMaleSkeletonBodyShaderDMaleSkeletonBodyShaderEMaleCopBodyShaderBMaleCopBodyShaderCMaleCopBodyShaderDMaleCopBodyShaderEMaleCopHeadShaderBMaleCopHeadShaderCMaleCopHeadShaderDMaleCopHeadShaderEMaleCopHeadShaderFMaleCopHeadShaderGMaleCopHeadShaderHMaleCopHeadShaderIMaleCopHeadShaderJMaleSkeletonHeadShaderBMaleSkeletonHeadShaderCMaleSkeletonHeadShaderDMaleSkeletonHeadShaderEMaleSkeletonHeadShaderFMaleSkeletonHeadShaderGMaleSkeletonHeadShaderHMaleSkeletonHeadShaderIMaleSkeletonHeadShaderJFemaleGoreBodyShaderBFemaleGoreBodyShaderCFemaleGoreBodyShaderDFemaleGoreBodyShaderEFemaleGoreHeadShaderBFemaleGoreHeadShaderCFemaleGoreHeadShaderDFemaleGoreHeadShaderEFemaleGoreHeadShaderFFemaleGoreHeadShaderGFemaleGoreHeadShaderHFemaleGoreHeadShaderIFemaleGoreHeadShaderJMaleGoreBodyShaderBMaleGoreBodyShaderCMaleGoreBodyShaderDMaleGoreBodyShaderEMaleGoreHeadShaderBMaleGoreHeadShaderCMaleGoreHeadShaderDMaleGoreHeadShaderEMaleGoreHeadShaderFMaleGoreHeadShaderGMaleGoreHeadShaderHMaleGoreHeadShaderIMaleGoreHeadShaderJMaleYoungAdultBodyShaderBMaleYoungAdultBodyShaderDMaleYoungAdultBodyShaderEMaleYoungAdultHeadShaderBMaleYoungAdultHeadShaderCMaleYoungAdultHeadShaderDMaleYoungAdultHeadShaderEMaleYoungAdultHeadShaderFMaleYoungAdultHeadShaderGMaleYoungAdultHeadShaderHMaleYoungAdultHeadShaderIMaleYoungAdultHeadShaderJFemaleHoboBodyShaderBFemaleHoboBodyShaderCFemaleHoboBodyShaderDFemaleHoboBodyShaderEFemaleHoboHeadShaderBFemaleHoboHeadShaderCFemaleHoboHeadShaderDFemaleHoboHeadShaderEFemaleHoboHeadShaderFFemaleHoboHeadShaderGFemaleHoboHeadShaderHFemaleHoboHeadShaderIFemaleHoboHeadShaderJCZ Location Velocity ReturnValue RandRange GroundSpeedWeapon LevelInfo ControllerPlayerControllerthreatDOTZAICanvasLevelShaderPawn SkeletalMeshVGSPAIControllerActorPlayerClassPackageConstOpponentFactoryExclaimManagerAIRole TextBuffer BBParticlesZombiePawnBaseBotbControlAnimationsDOTZAIControllerDOTZZombieExclaimMgr DOTZAIRole SkelHeadZombieFactory MoveTimerFocusEnemyaptimerIDTargetFailedReachTime NoiseMaker AnimSpawnSeen SpawnAnims bForceRunCONFIGURE_HACK_TIMER bConfigured EATCHANNEL numLooks SeekLocationLastSeekInstigatorCurrentObstacleCurrentAttackPointNumClearAttemptsClearStartTime EatTarget MAX_EAT_DISTFailedEatAttemptsDistToEatTarget EatingTime MAX_EAT_TIMELastHeardEnemyTimeREACQUIRE_DELAYNumChargingZombiesLastChargeTimeChargeStartTime bIsChargingChargeDuration bIgnoreBumps bActivatedSTART_REACQUIRE_TIMER CHARGE_TIMERPRE_CHARGE_TIMERTHINK_AGAIN_TIMER MELEE_RANGEDONT_BE_STUPID_TIMER zombieBot obstacleObject FunctionStateStruct SpawnTimeStandardMaleBaseStandardFemaleBase StrPropertyStructPropertyArrayPropertyClassProperty NamePropertyObjectPropertyFloatProperty BoolProperty IntProperty DOTZAZombies ByteProperty bIsCrawlingNetMode TimeSecondsVictimKiller Smashable AttackPointResultYLdist AdvancedPawn LoudnessDamageEventInstigatorStageMaleHospitalPatientBodyShaderEOtherMaleSeniorBodyShaderCxT\B!fܿq GAPAPAPL9L9a"L9a"܈L9ebL9L9L9a"ɰ{ʏAPL9CŏAPCŏAPGpCy6xMw"L]#"XDOTZCharacters.ZombieGropeWeapont[aS]H*W!D1JF$i6  GC  KN;~ r * 9r } a/!{ a/!u}. q!/!' F4`[  r* N6 6 9? {w 5'q!% IP789@ R.$r*-r*9?,a/!Xa/!>*  '        1'( H~@("tU@{HFйLڔJq333HL9ebfܔJqfܔJqJq IcL9HL9HHHHHHHHHHHL9a"HHJqJqJqHHHJqzkHH63HzkHzkHzkHzkHzkHHHHL9HebHL9f܆HebHL9HL9f܆HHebHL9q GebHL9HL9HL9ebHHHL9HL9HL9HJqHL9HHL9a"HHHHHHHL9HL9HL9HL9HL9HHHL9HL9HL9HL9HHHHHHHL9JqHL9HL9JqJqJqHL9HL9HL9HL9HL9fܔJqf܆HHHL9HJqebebJqebHL9ebHL9ebHL9L9HJqebebL9HL9HHJqL9HGCr"2q$ As$Av$ z"H$DG$BF$pA@$A~^"2K,QPN2 51 N 9?7'3( ]Ez q!6 O` !a9D RT7TRw*R-+( S\6La=L?.W '-' '<VNy U.*/..-.-6  0A%,A&, W('.W '-( Y-I2--  2A%,A&, ZMJ/ 2,M, `Ha~MeleeAttack*w*1'a # #-+(a@9?&DMeleeAttack-done ' 0A%,A&, Ls9Z; q!H  0A%,A&, |jfB,Y6cy"!>%!YTiffany MetcalfeZYMS"Y NS"Y PS"Y QS"Y RS"Y SS"Y OS"Y  B" LY:VS" US"Y YS"Y is" : S $?S " : S $?S " : S $>S " : S $>S" : S $>S"" : @S $" : S $?S " : S $?SY $Y "#N// Copyright (C) 2005 Brainbox Games. All Rights Reserved. // September 27, 2005 //----------------------------------------------------------- // //----------------------------------------------------------- class BDHSMiddleAgedMale extends StandardMaleBase placeable; function BeginPlay() { Super.BeginPlay(); SpecialDamage.Remove( 0,5); SpecialDamage.Remove( 1,2); }  .A%,A&, dggB,Y6fZsdڠ.Y!IJosh Druckmanis" : S $?S " : S $?S " : S $>S " : S $>S" : S $>S"" : @S $" : S $?S " : S $?SY $Y "# 2A%,A&, R// Copyright (C) 2005 Brainbox Games. All Rights Reserved. // September 27, 2005 //----------------------------------------------------------- // //----------------------------------------------------------- class BDHSMiddleAgedFemale extends StandardFemaleBase placeable; function BeginPlay() { Super.BeginPlay(); SpecialDamage.Remove( 0,5); SpecialDamage.Remove( 1,2); } hSiB,Y6jl׷>%!ITracy Baudaisis" : S $?S " : S $?S " : S $>S " : S $>S" : S $>S"" : @S $" : S $?S " : S $?SY $Y "#_ 100 7A%,A&,  ,A%,A&,  ,A%,A&, k 10 +A%,A&, o 1.5S// Copyright (C) 2005 Brainbox Games. All Rights Reserved. // September 27, 2005 //----------------------------------------------------------- // //----------------------------------------------------------- class BDHSHospitalPatientMale extends StandardMaleBase placeable; function BeginPlay() { Super.BeginPlay(); SpecialDamage.Remove( 0,5); SpecialDamage.Remove( 1,2); } waPS( S// Copyright (C) 2005 Brainbox Games. All Rights Reserved. // September 27, 2005 /** * ZombieAIRole - * * @version $Rev: 5272 $ * @author Jesse LaChapelle (jesse@digitalextremes.com) * @author Neil Gower (neilg@digitalextremes.com) * @date June 2004 */ class BDHSZombieAIRole extends DOTZAIRole; //=========================================================================== // Settings //=========================================================================== var int AttackRange; var float MinWanderDelay; var float MaxWanderDelay; //=========================================================================== // internal data //=========================================================================== // wander var protected int numLooks; // seek var protected Vector SeekLocation; var protected Actor LastSeekInstigator; var protected float LastSeekRefreshTime; // obstacle smashing var protected Smashable CurrentObstacle; var protected AttackPoint CurrentAttackPoint; var protected int NumClearAttempts; var protected float ClearStartTime; // eating var protected Actor EatTarget; const MAX_EAT_DIST = 100; var protected int FailedEatAttempts; var protected float DistToEatTarget; var int EatingTime; const MAX_EAT_TIME = 10; // enemy mgmt var protected float LastHeardEnemyTime; const REACQUIRE_DELAY = 1.5; // charging var protected int NumChargingZombies; // using default value as a class var. var protected const int MaxChargingZombies; var protected const float MaxChargeDist; var protected const float MinChargeDist; var protected float MinTimeBetweenCharges; var protected float MaxTimeBetweenCharges; var protected float LastChargeTime; var protected float ChargeStartTime; var protected bool bIsCharging; var protected float ChargeDuration; var protected bool bIgnoreBumps; var() bool bAllowedToCharge; // other var protected bool bActivated; const START_REACQUIRE_TIMER = 68694; const CHARGE_TIMER = 8375093; const PRE_CHARGE_TIMER = 8375094; const THINK_AGAIN_TIMER = 92843; const MELEE_RANGE = 50; const DONT_BE_STUPID_TIMER = 29384; var BDHSZombieAIController zombieBot; //=========================================================================== // Events of interest... //=========================================================================== function OnTakingDamage(Pawn Other, float Damage) { super.OnTakingDamage( other, damage ); //in multiplayer, if some other human shoots you then go after them instead if (Level.NetMode != NM_StandAlone && BDHSZombieAIController(Other.Controller)==None){ bot.enemy = Other; } } /** * Called whenever an enemy pawn is in sight. */ function OnThreatSpotted( Pawn threat ) { // // Log( self @ "OnThreatSpotted" @ threat ) ; if ( threat == None ) return; //TODO: this probably needs fancying up. Possibly only switch if // closer, or human controlled... // zombies have stiff necks, they can't look up and down very far... if ( abs(threat.location.z - bot.pawn.location.z) > 2048 ) { return; } if ( threat != bot.Enemy ) { bot.AcquireEnemy(threat, true); } GotoState( 'Attacking' ); } /** * */ function OnThreatHeard( Pawn threat ) { // // Log( self @ "OnThreatHeard not used by ZombieAIRole" ) ; } /** * Called when something does a MakeNoise(). Instead of directly * acquiring the enemy at this point (as the base class does), start * seeking, in an effort to cause an OnThreatSpotted(). */ function OnHeardNoise( float Loudness, Actor NoiseMaker ) { // // Log( self @ "OnHeardNoise" @ loudness @ noiseMaker ) ; if ( noiseMaker == None ) return; if ( NoiseMaker == bot.Enemy ) lastHeardEnemyTime = Level.timeSeconds; if ( NoiseMaker.isA('Attractor') || NoiseMaker.isA('HumanPawnBase') ) { //FIXME this may be a little wrong, don't want to reset seek state... if ( TrySeekTarget(NoiseMaker) ) GotoState( 'Seeking', 'BEGIN' ); } } /** * It's all over for this zombie... */ function OnKilled( Controller killer ) { super.OnKilled( killer ); EndCharge(); } /** * Mmmmm... tasty carrion to feed on... */ function OnWitnessedKill( Controller killer, Pawn victim ) { super.OnWitnessedKill( killer, victim ); if ( victim.IsHumanControlled() || victim.IsA('Otis') ) { EatTarget = victim; GotoState( 'DoSpecial', 'EAT_STUFF' ); } } //=========================================================================== // High level AI scripts/plans... //=========================================================================== /** * Sets a to be the new seek target, if it is better than the current * target. * * @returns true - target is now a, false otherwise. */ function bool TrySeekTarget( Actor a ) { // do some easy checks... if ( LastSeekInstigator == none // if we don't have a seek target... || (LastSeekInstigator == a // or refreshing current target... && Level.TimeSeconds - lastSeekRefreshTime > 3) || a.IsA('JackSlade') || a.isA('Otis') ) { // or it's a hero... LastSeekInstigator = a; LastSeekRefreshTime = Level.TimeSeconds; SeekLocation = a.Location; return true; } // check if the new seek target is closer than the current seek // target... if ( VSize(bot.Pawn.Location - a.location) <= VSize(bot.Pawn.Location - SeekLocation) ) { LastSeekInstigator = a; SeekLocation = a.Location; bot.updateFocus( a ); return true; } // new target didn't meet any criteria to override the current one. return false; } /** */ function TryClearObstacle( Actor obstacle ) { local Pawn potentialEnemy; // if it's an enemy, kill it! potentialEnemy = Pawn(obstacle); if ( potentialEnemy != None && !bot.SameTeamAs(potentialEnemy.controller) ) { bot.acquireEnemy(potentialEnemy, true); GotoState( 'Attacking' ); return; } // check if it's smashable... currentObstacle = Smashable(obstacle); if ( currentObstacle != None ) { // // Log( self @ "hulk smash!" ) ; numClearAttempts = 0; GotoState( 'DoSpecial', 'SMASH_OBSTACLE' ); } else { // // Log( self @ obstacle @ "not smashable" ) ; } //FIXME: need a way to resume after clearing the obstacle. } /** * Determines whether it's appropriate to charge at the enemy now. */ function bool ShouldCharge() { local bool result; // do some quick checks before the expensive one... if ( bot.Enemy == none || !bAllowedToCharge ) return false; // hack scuttlers to just charge a lot. if ( bot.Pawn.isA( 'ScuttlingZombie' ) ) { if ( (Level.TimeSeconds - ChargeStartTime) < MinTimeBetweenCharges || VSize(bot.Enemy.location - bot.pawn.Location) > MaxChargeDist * 1.5 ) { return false; } else return true; } // check limits... else { if ( default.NumChargingZombies >= MaxChargingZombies && Level.TimeSeconds - default.LastChargeTime < MaxTimeBetweenCharges ) { // // Log( self @ "too many charging zombies" @ default.NumChargingZombies ) ; return false; } } // some other checks if ( (Level.TimeSeconds - ChargeStartTime) < MinTimeBetweenCharges // time to complete spawn anim... || (Level.TimeSeconds - bot.Pawn.SpawnTime) < 5 // range to enemy... || VSize(bot.Enemy.location - bot.pawn.Location) > MaxChargeDist || VSize(bot.Enemy.location - bot.pawn.Location) < MinChargeDist ) { // // Log( self @ "something else preventing charge" ) ; return false; } // if it all checks out, make sure we have a straight run at the enemy... // (this would be the expensive check) log(" last failed reach time: " $ ZombieBot.FailedReachTime); // log(" last failed reach: " $ ZombieBot.LastFailedReach); if (Level.TimeSeconds - ZombieBot.FailedReachTime > 10){ result = bot.actorReachable(bot.Enemy); if ( !result ) { // Log( self @ "charge enemy not reachable" ) ; } } else { return false; } return result; } //=========================================================================== // Wander - no (known) threats nearby, nothing in particular to do but // wander around in an undead stupor. //=========================================================================== auto state Wander { function BeginState() { // // Log( self @ "entering wander state" ) ; } function EndState() { // // Log( self @ "leaving wander state" ) ; } function NotEngagedWanderFailed() { GotoState( 'Attacking' ); } BEGIN: while ( true ) { // // Log( self @ "wandering" ) ; Sleep( 1 ); // look around randomly... numLooks = RandRange( 1, 5 ); while ( numLooks > 0 ) { bot.SetRandomFocalPointLocation( 2000 ); Sleep( RandRange(10, 30) ); --numLooks; } // // Log( self @ "doing the wander behaviour" ) ; // find a new place to stand around... bot.Perform_NotEngaged_Wander(); WaitForNotification(); // now just stand there for a while... Sleep( RandRange(MinWanderDelay, MaxWanderDelay) ); } } //=========================================================================== // Seeking - no enemy directly accessible, but something of interest // to seek towards, such as an attractor or the sound of a player. //=========================================================================== state Seeking { function BeginState() { // // Log( self @ "entering seeking state" ) ; // entering this state implies there is something to seek // towards... // if ( !(LastSeekInstigator != None ) ) { Log( "(" $ self $ ") assertion violated: (LastSeekInstigator != None )", 'DEBUG' ); assert( LastSeekInstigator != None ); }// ; } function EndState() { // // Log( self @ "leaving seeking state" ) ; // stop moving! bot.Perform_Error_Stop(); } /** * Bumping into things may interrupt the seeking... */ function OnBump( Actor other ) { // // Log( self @ "OnBump" @ other ) ; TryClearObstacle( other ); } /** */ function OnHitWall( Actor other ) { // // Log( self @ "OnHitWall" @ other ) ; TryClearObstacle( other ); } /** */ function OnHitMover( Actor other ) { // // Log( self @ "OnHitMover" @ other ) ; TryClearObstacle( other ); } BEGIN: // move to SeekLocation... // // Log( self @ "seeking to" @ seekLocation ) ; bot.Perform_MoveToLocation( seekLocation, 128 ); WaitForNotification(); //TODO: maybe we arrived at an eat point? chow down! //FIXME: assumes we made it to the location... LastSeekInstigator = None; // if we didn't end up in the attack state already, go back to // wandering around until something new comes up to seek... GotoState( 'Wander' ); } //=========================================================================== // Attacking - engaged with an enemy, give 'em what for! //=========================================================================== state Attacking { function BeginState() { // // Log( self @ "entering attack state" ) ; LastSeekInstigator = bot.enemy; bot.updateFocus( bot.enemy ); bot.SetCombatTimer(); } function EndState() { // // Log( self @ "leaving attack state" ) ; bot.SetTimer( 0, false ); } /** * Lost sight of the enemy, try to recover him... */ function OnLostSight() { // // Log( self @ "OnLostSight" @ bot.Enemy ) ; SetMultiTimer( START_REACQUIRE_TIMER, REACQUIRE_DELAY, false ); } /** * Attack isn't working. :-( */ function ChargeFailed() { //SetMultiTimer( START_REACQUIRE_TIMER, REACQUIRE_DELAY, false ); } /** */ function OnBump( Actor other ) { local Pawn enemy; if ( bIgnoreBumps ) return; enemy = Pawn( other ); if ( enemy != none && enemy.IsHumanControlled() ) { bIgnoreBumps = true; // should set it back again after some time... bot.WeaponFireAgain(bot.Pawn.Weapon.RefireRate(),false); } } // // Zombies are very single-minded, and ignore many inputs when // attacking... // function OnThreatSpotted( Pawn threat ) { if ( threat == bot.Enemy ) { // // Log( self @ "reacquired" @ threat ) ; SetMultiTimer( START_REACQUIRE_TIMER, 0, false ); } else { // // Log( self @ "ignoring OnThreatSpotted" @ threat ) ; } } function OnHeardNoise( float Loudness, Actor NoiseMaker) { // // Log( self @ "ignoring HearNoise" @ loudness ) ; if ( NoiseMaker == bot.Enemy ) lastHeardEnemyTime = Level.timeSeconds; } function bool TrySeekTarget( Actor a ) { return false; } /** * @returns a little bit less than the amount of time it should take to * charge the enemy. */ function float getChargeDuration() { local float dist; dist = VSize(bot.enemy.location - bot.pawn.location) * 0.8; return dist/bot.pawn.GroundSpeed; } BEGIN: while ( true ) { // // Log( self @ "attacking" ) ; // Charge! if ( shouldCharge() ) { StartCharge(); chargeDuration = getChargeDuration(); // // Log( self @ "charge should take" @ chargeDuration @ "seconds" ) ; if ( chargeDuration > 1.5 ) { // some wild flailing along the way... SetMultiTimer( PRE_CHARGE_TIMER, 0.2, false ); } // timer will trigger an attack just before the bot reaches the // enemy, so that it overlaps with the running. SetMultiTimer( CHARGE_TIMER, chargeDuration, false ); bIgnoreBumps = false; bot.Perform_MoveToLocation( bot.pawn.location + ( (bot.enemy.location - bot.pawn.location)*0.9 ), MELEE_RANGE ); WaitForNotification(); EndCharge(); } // normal attack else { if ( VSize(bot.enemy.location - bot.pawn.location) < MELEE_RANGE ) { bIgnoreBumps = true; bot.Perform_MeleeAttack(); WaitForNotification(); bIgnoreBumps = false; } else { // move to a spot in front of the enemy... bot.Perform_MoveToLocation( bot.pawn.location + ( (bot.enemy.location - bot.pawn.location)*0.8 ), MELEE_RANGE ); // wait a bit and then re-think this action, since moves can // take a really long time... WaitForNotification( 2 ); } } //if you just killed enemy, eat 'im! //NOTE: should probably check range to the body here... if ( bot.Enemy.Health <= 0 ) { EatTarget = bot.Enemy; GotoState( 'DoSpecial', 'EAT_STUFF' ); } //FIXME: do we need this? Sleep( 0.3 ); } } //=========================================================================== // Performing some special activity... //=========================================================================== state DoSpecial { function BeginState() { EatingTime = Level.TimeSeconds; // // Log( self @ "entering special state" ) ; } function EndState() { // // Log( self @ "leaving special state" ) ; bot.target = none; bot.Focus = none; bot.updateFocus( None ); } // Zombies are very single-minded, and ignore many inputs when // doing special stuff... function OnThreatSpotted( Pawn threat ) { // // Log( self @ "ignoring OnThreatSpotted" @ threat ) ; if (Level.TimeSeconds - EatingTime > MAX_EAT_TIME){ super.OnThreatSpotted(threat); } } function OnHeardNoise( float Loudness, Actor NoiseMaker) { // // Log( self @ "ignoring HearNoise" @ loudness ) ; if ( NoiseMaker == bot.Enemy ) lastHeardEnemyTime = Level.timeSeconds; if (Level.TimeSeconds - EatingTime > MAX_EAT_TIME){ super.OnHeardNoise( Loudness, NoiseMaker); } } BEGIN: // if you didn't pick a specific thing to do, we're done! Goto( 'DONE' ); SMASH_OBSTACLE: // // Log( self @ "smashing" ) ; // get into position... currentAttackPoint = currentObstacle.getAttackPoint( bot.pawn ); if ( currentAttackPoint == None ) Goto( 'DONE' ); bot.Perform_MoveToLocation( currentAttackPoint.getAttackLocation() ); WaitForNotification(); // face the right way... bot.Target = currentObstacle.getSmashActor(); Bot.Focus = currentObstacle.getSmashActor(); Sleep( 1 ); // wait for rotation // start attacking ... for ( numClearAttempts = 0; numClearAttempts < 5; ++numClearAttempts ) { // // Log( self @ "Attacking obstacle" ) ; bot.Perform_MeleeAttack(); WaitForNotification(); if ( currentObstacle.getAttackPoint(bot.pawn) == none ) break; } if ( currentObstacle.getAttackPoint(bot.pawn) != none ) { // if the obstacle is still in place, smash it good! currentObstacle.doSmash( bot.pawn ); } bot.target = none; bot.Focus = none; goto( 'DONE' ); EAT_STUFF: // // Log( self @ "Eating stuff" ) ; failedEatAttempts = 0; while ( failedEatAttempts < 5 ) { if ( EatTarget == none && bot.enemy.Health <= 0 ) { EatTarget = bot.enemy; } if ( EatTarget != none ) { distToEatTarget = VSize(EatTarget.location - bot.pawn.location); if ( distToEatTarget > MAX_EAT_DIST) { // zombies love to eat, so they run towards food. zombieBot.bForceRun = true; Sleep( RandRange( 0.1, 0.7 ) ); // // Log( self @ "GRABBING A BITE:" @ eatTarget @ eatTarget.location ) ; bot.Perform_MoveToLocation( eatTarget.location, MAX_EAT_DIST ); WaitForNotification( 1 ); bot.Pawn.Velocity = vect( 0,0,0 ); bot.Pawn.Acceleration = vect( 0,0,0 ); zombieBot.bForceRun = false; } bot.target = eatTarget; bot.Focus = eatTarget; if (VSize(EatTarget.location - bot.pawn.location ) <= MAX_EAT_DIST){ DOTZAIController(bot).Perform_Eating(); } else { // bail out if you're not getting any closer to the target... if ( distToEatTarget - VSize(EatTarget.location - bot.Pawn.Location) < 128 ){ // a little hack to make the zombie walk away... LastSeekInstigator = EatTarget; SeekLocation = Vect(0,0,1) * bot.Pawn.Location + ( Vect(-1,-1,0) * Normal(bot.Pawn.Location - eatTarget.location) * RandRange(0.5, 1.5) * 512 ); goto( 'DONE' ); } ++failedEatAttempts; } Sleep( 0.3 ); } else goto( 'DONE' ); } Goto( 'DONE' ); DONE: // // Log( self @ "done DoSpecial" ) ; bot.Target = none; if ( bot.enemy != none ) GotoState( 'Attacking' ); else if ( LastSeekInstigator != none ) GotoState( 'Seeking' ); else GotoState( 'Wander' ); } //=========================================================================== // HELPERS //=========================================================================== /** */ function init( VGSPAIController c ) { super.init( c ); zombieBot = BDHSZombieAIController( c ); SetMultiTimer( DONT_BE_STUPID_TIMER, 6.0 + RandRange(0, 2.5), false ); } /** */ function MultiTimer( int timerID ) { switch ( timerID ) { //TODO: might be better to be in a separate state for "just lost contact", // which can more quickly reacquire... case START_REACQUIRE_TIMER: global.TrySeekTarget( bot.enemy ); GotoState( 'Seeking' ); break; case PRE_CHARGE_TIMER: case CHARGE_TIMER: // asynchronous attack, hopefully timed a little before reaching the // enemy... bot.WeaponFireAgain(bot.Pawn.Weapon.RefireRate(),false); break; case THINK_AGAIN_TIMER: // interrupt movement to allow bot a chance to reassess the situation. bot.MoveTimer = -1; break; case DONT_BE_STUPID_TIMER: DontBeStupid(); break; default: super.MultiTimer( timerID ); } } /** * Periodically override zombie behaviour, in hopes of avoiding stupid * situations. */ function DontBeStupid() { local Pawn player; // // Log( self @ "Checking for stupid situations... if you are not in multiplayer mode" ) ; if (Level.NetMode == NM_Standalone){ player = Level.GetLocalPlayerController().pawn; if ( player == none ) return; // ignore the player if he's too far up... if ( abs(player.location.z - bot.pawn.location.z) < 2048 ) { // if the player IS the enemy, and you can attack, then get on it! if ( player == bot.Enemy && GetStateName() != 'Attacking' && bot.actorReachable(bot.Enemy)) { GotoState( 'Attacking' ); } // if the player isn't the enemy, but you can see and reach him, then // start attacking! if ( player != bot.Enemy && bot.CanSee(player) && bot.actorReachable(bot.Enemy)) { bot.AcquireEnemy(player, true); GotoState( 'Attacking' ); } } SetMultiTimer( DONT_BE_STUPID_TIMER, 4.0 + RandRange(0, 2.5), false ); } } /** * Bookkeeping for when a charge starts */ function StartCharge() { ChargeStartTime = Level.TimeSeconds; default.LastChargeTime = ChargeStartTime; zombieBot.bForceRun = true; bIsCharging = true; default.NumChargingZombies = default.NumChargingZombies + 1; } /** * Bookkeeping for when a charge ends. Safe to call even when not charging. */ function EndCharge() { if ( !bIsCharging ) return; default.NumChargingZombies = default.NumChargingZombies - 1; bIsCharging = false; zombieBot.bForceRun = false; } /** * InAttackRange */ function bool InAttackRange(actor enemy){ //NOTE: maybe migrate this to the ZombieGropeWeapon? if(VSize(bot.pawn.location - enemy.location) < 50){ return true; } else { return false; } } /** * Realtime onscreen debug info... */ function DisplayDebug( Canvas c, out float YL, out float YPos ) { super.DisplayDebug( c, YL, YPos ); c.SetPos(4, YPos); C.DrawText( "LastSeekInstigator:" @ LastSeekInstigator @ "SeekLocation:" @ SeekLocation ); YPos += YL; C.SetPos(4,YPos); } /** */ function PreBeginPlay() { super.PreBeginPlay(); // make sure charging is possibe at the beginning of the game... ChargeStartTime = Level.TimeSeconds - MinTimeBetweenCharges; LastChargeTime = ChargeStartTime; } //=============================================================== // Default Properties //===============================================================  0A%,A&, #}vQJ?#.4w#*#-'=-  pS// Copyright (C) 2005 Brainbox Games. All Rights Reserved. // September 27, 2005 /** * ZombieAIController - * * @version $Rev: 4980 $ * @author Jesse LaChapelle (jesse@digitalextremes.com) * @author Neil Gower (neilg@digitalextremes.com) * @date June 2004 */ class BDHSZombieAIController extends DOTZAIController; // settings var name EatingAnim; var name CrawlEatingAnim; var int iAwarenessRange; var string DefaultWeaponType; // internal var class TheExclaimManager; var bool bForceRun; const CONFIGURE_HACK_TIMER = 294850; var bool bConfigured; const EATCHANNEL = 20; /** */ function BeginPlay() { super.BeginPlay(); SetMultiTimer( CONFIGURE_HACK_TIMER, 3, false ); } /** */ function MultiTimer( int timerID ) { //NOTE: an ugly hack to make sure that pawns not spawned from factories get // their weapon. if ( timerID == CONFIGURE_HACK_TIMER ) { if ( !bConfigured ) configure( none, none ); } else super.MultiTimer( timerID ); } /** */ function bool SameTeamAs(Controller C) { // only zombies return (BDHSZombieAIController(c) != None); } /** */ function configure( OpponentFactory f, Stage initialStage ) { bConfigured = true; super(VGSPAIController).configure( f, initialStage ); if (Pawn != None){ Pawn.GiveWeapon( DefaultWeaponType ); if (AdvancedPawn(Pawn) != none && ZombieFactory(f) != none && ZombieFactory(f).SpawnAnims.length > 0){ AdvancedPawn(Pawn).AnimSpawn = ZombieFactory(f).SpawnAnims; AdvancedPawn(Pawn).PlaySpawnAnim(); } } } /** */ function bool shouldWalk() { local AdvancedPawn ap; ap = AdvancedPawn( Pawn ); // make sure crawlers don't try to force through a run... if ( ap != none && ap.bIsCrawling ) return true; else return !bForceRun; } /** */ function bool ShouldStrafe() { return false; } /** * Attempt a melee attack against the current enemy. */ function Perform_MeleeAttack() { GotoState( 'MeleeAttack' ); } /** */ state MeleeAttack { BEGIN: curBehaviour = "MeleeAttack"; if ( Enemy != none ) updateFocus( Enemy, true ); FinishRotation(); //TODO: check range? move closer? Pawn.Acceleration = vect(0,0,0); Pawn.Velocity = vect(0,0,0); //NOTE: with the current melee implementation, this just means firing the // "weapon" WeaponFireAgain(Pawn.Weapon.RefireRate(),false); //TODO: sync up with completion of the attack animation... sleep( 2 + FRand() * 1 ); //TODO: if we had feedback from the weapon about hit/miss, the role callback // would be more meaningful... myAiRole.MeleeAttackSucceeded(); curBehaviour = "MeleeAttack-done"; } /**************************************************************** * Perform_Eating * Command to start the eating animation **************************************************************** */ function Perform_Eating() { GotoState('Eating'); } /**************************************************************** * InAwarnessRange **************************************************************** */ function bool InAwarenessRange(actor enemy){ if(VSize(pawn.location - enemy.location) < iAwarenessRange){ return true; } else { return false; } } function SpawnExclaimManager(){ exclaimMgr = Spawn(TheExclaimManager, self); exclaimMgr.init(self); } /** * Override firing to trigger the melee flail of a zombie. * * NOTE This won't be necessary if we make the ZombieGrope weapon fully * NOTE functional. */ function TimedFireWeaponAtEnemy() { // Log( self @ "firing!" ) ; //NOTE assumes the weapon is a melee attack weapon... if ( (Pawn.Weapon != None) && !Pawn.Weapon.IsFiring() ) { WeaponFireAgain( Pawn.Weapon.RefireRate(), false ); } } //=============================================================== // state Eating //=============================================================== state Eating { ignores KilledBy, EnemyNotVisible; function BeginState() { local AdvancedPawn ap; ap = AdvancedPawn( pawn ); if (ap.bIsCrawling) EatingAnim = CrawlEatingAnim; } function EndState() { // clobber the eat anim loop //AdvancedPawn(pawn).PlayAnim( EatingAnim ); //LoopAnim( EatingAnim ); AdvancedPawn(pawn).AdvancedPlayAnim( EatingAnim,,,,true ); bControlAnimations = false; } /** */ function SeePlayer(Pawn Seen){ if ( InAwarenessRange(Seen) ) { Super.SeePlayer(Seen); } } /** */ function HearNoise( float Loudness, Actor NoiseMaker){ if (InAwarenessRange(NoiseMaker)){ Super.HearNoise(Loudness, NoiseMaker); } } BEGIN: Sleep( RandRange( 0.1, 0.8 ) ); AdvancedPawn(Pawn).AdvancedPlayAnim(EatingAnim,,,,true); bControlAnimations = true; //Pawn.LoopAnim(EatingAnim); } //=============================================================== // DefaultProperties //=============================================================== rljB,Y6yS٠.Y!Y Simon Fernandes Jamie Tayloris" : S $?S " : S $?S " : S $>S " : S $>S" : S $>S"" : @S $" : S $?S " : S $?SY $Y "#N// Copyright (C) 2005 Brainbox Games. All Rights Reserved. // September 27, 2005 //----------------------------------------------------------- // //----------------------------------------------------------- class BDHSSeniorFemale extends StandardFemaleBase placeable; function BeginPlay() { Super.BeginPlay(); SpecialDamage.Remove( 0,5); SpecialDamage.Remove( 1,2); } N// Copyright (C) 2005 Brainbox Games. All Rights Reserved. // September 27, 2005 //----------------------------------------------------------- // //----------------------------------------------------------- class BDHSYoungAdultMale extends StandardMaleBase placeable; function BeginPlay() { Super.BeginPlay(); SpecialDamage.Remove( 0,5); SpecialDamage.Remove( 1,2); } M// Copyright (C) 2005 Brainbox Games. All Rights Reserved. // September 27, 2005 //----------------------------------------------------------- // //----------------------------------------------------------- class BDHSNurseFemale extends StandardFemaleBase placeable; function BeginPlay() { Super.BeginPlay(); SpecialDamage.Remove( 0,5); SpecialDamage.Remove( 1,2); } QA8-1'Fw* b8w.*w.*7.%...e q 68694 8375093@ 8375094A 92843B 50C 29384DmkB,Y6E'b .Y!Y Sean Georget Jamie Tayloris" : S $?S " : S $?S " : S $>S " : S $>S" : S $>S"" : @S $" : S $?S " : S $?SY $Y "#DCT ZCX9:9:$r.* {[UB,Y6G:.Y!Y* David Drew Jeff StygaJason Kucherawyis" : S $?S " : S $?S " : S $>S " : S $>S" : S $>S"" : @S $" : S $?S " : S $?SY $Y "#R// Copyright (C) 2005 Brainbox Games. All Rights Reserved. // September 27, 2005 //----------------------------------------------------------- // //----------------------------------------------------------- class BDHSYoungAdultFemale extends StandardFemaleBase placeable; function BeginPlay() { Super.BeginPlay(); SpecialDamage.Remove( 0,5); SpecialDamage.Remove( 1,2); } N// Copyright (C) 2005 Brainbox Games. All Rights Reserved. // September 27, 2005 //----------------------------------------------------------- // //----------------------------------------------------------- class BDHSHoboFemale extends StandardFemaleBase placeable; function BeginPlay() { Super.BeginPlay(); SpecialDamage.Remove( 0,5); SpecialDamage.Remove( 1,2); } /Lu  IB]B,Y6MDK>%!Y! Zan HarriottNathalie Baudaisis" : S $?S " : S $?S " : S $>S " : S $>S" : S $>S"" : @S $" : S $?S " : S $?SY $Y "# JulB,Y6O S>%!Y Dana Veljicis" : S $?S " : S $?S " : S $>S " : S $>S" : S $>S"" : @S $" : S $?S " : S $?SY $Y "#%AWA: UB<2lw.B* P@A`Q@O=a/!>q!,!3  6A%,A&, H// Copyright (C) 2005 Brainbox Games. All Rights Reserved. // September 27, 2005 //----------------------------------------------------------- // //----------------------------------------------------------- class BDHSGoreMale extends StandardMaleBase placeable; function BeginPlay() { Super.BeginPlay(); SpecialDamage.Remove( 0,5); SpecialDamage.Remove( 1,2); } f0[(2%0"-1A**00 TnmB,Y6VoTFD.Y!YBrent Baudais Rob TaylorZYMS"Y NS"Y PS"Y QS"Y RS"Y SS"Y OS"Y  B" LY:VS" US"Y YS"Y is" : S $?S " : S $S " : S $>S " : S $>S" : S $>S"" : @S $" : S $?S " : S $?SY $Y "#?&0.&]w* < 5'q!% .&w*%q!,!I L// Copyright (C) 2005 Brainbox Games. All Rights Reserved. // September 27, 2005 //----------------------------------------------------------- // //----------------------------------------------------------- class BDHSTeenagerMale extends StandardMaleBase placeable; function BeginPlay() { Super.BeginPlay(); SpecialDamage.Remove( 0,5); SpecialDamage.Remove( 1,2); } L// Copyright (C) 2005 Brainbox Games. All Rights Reserved. // September 27, 2005 //----------------------------------------------------------- // //----------------------------------------------------------- class BDHSGoreFemale extends StandardFemaleBase placeable; function BeginPlay() { Super.BeginPlay(); SpecialDamage.Remove( 0,5); SpecialDamage.Remove( 1,2); } X\X ?#r* -D(a/!}A  2?(' J"G(.9?,:  2:  I(p last failed reach time: 9U49?, -b1-6(- Y^_B,Y6] .Y!Y5Jake LaChapelleLuke LaChapelleJesse LaChapelleis" : S $?S " : S $?S " : S $>S " : S $>S" : S $>S"" : @S $" : S $?S " : S $?SY $Y "#[a8$'a?9D?@`% ^Da AA$_aaLK '*# _(/$ `Ve$ q!% ^i/Z,<) Ca*q!8 ',*;) c(@*O d>?Ha+ 0> ha@@( e=ZO , 0= q 20g(a5 (- ([)   fff?HBa:"  9?,2- '9a- ([)   L?HBa@%q!,!3a> '*q/0B1S l(x1 a( mB1aV ?( nE2 o;?/3u -  .;sw*=- '(-+(  294850R// Copyright (C) 2005 Brainbox Games. All Rights Reserved. // September 27, 2005 //----------------------------------------------------------- // //----------------------------------------------------------- class BDHSTeenagerFemale extends StandardFemaleBase placeable; function BeginPlay() { Super.BeginPlay(); SpecialDamage.Remove( 0,5); SpecialDamage.Remove( 1,2); } /p:45+)r:aV () zwcB,Y6tŬ>%!Y Hazel Shaveris" : S $?S " : S $?S " : S $>S " : S $>S" : S $>S"" : @S $" : S $?S " : S $?SY $Y "#%sv;6.,r5 5 2A%,A&, ?uy.H7( zx|K/8`'  L?' 'rO`B,Y6}li>%!IMegan Johnsonis" : S $?S " : S $?S " : S $>S " : S $>S" : S $>S"" : @S $" : S $?S " : S $?SY $Y "#kC,pFp !&7:r* !&) daTTa?%,9ar7*4w7*h** !&%,r*%w*  9?,d- 'a=333?) Ba? # #- (   9?,d.E  9?, a(#? a(#  ??9? !&a> !&a !&*)w*q!%E>w*q!/Eq!8 &3ZI'H*pB9D (JC2**1* /@44D-+9?9?, 4  6A%,A&, %AE; E^,r(\9?9?, E( J// Copyright (C) 2005 Brainbox Games. All Rights Reserved. // September 27, 2005 //----------------------------------------------------------- // //----------------------------------------------------------- class BDHSHoboMale extends StandardMaleBase placeable; function BeginPlay() { Super.BeginPlay(); SpecialDamage.Remove( 0,5); SpecialDamage.Remove( 1,2); } L// Copyright (C) 2005 Brainbox Games. All Rights Reserved. // September 27, 2005 //----------------------------------------------------------- // //----------------------------------------------------------- class BDHSSkeletonMale extends StandardMaleBase placeable; function BeginPlay() { Super.BeginPlay(); SpecialDamage.Remove( 0,5); SpecialDamage.Remove( 1,2); } ~)DrT=).)ar@ @( EbaB,Y6G{ .Y!9 Joe Grantis" : S $?S " : S $?S " : S $>S " : S $>S" : S $>S"" : @S $" : S $?S " : S $?SY $Y "#F+[zU+ -V 8.q!/ 56 q5(-+( j rF + L// Copyright (C) 2005 Brainbox Games. All Rights Reserved. // September 27, 2005 //----------------------------------------------------------- // //----------------------------------------------------------- class BDHSSeniorMale extends StandardMaleBase placeable; function BeginPlay() { Super.BeginPlay(); SpecialDamage.Remove( 0,5); SpecialDamage.Remove( 1,2); } HFY[Y9:9:$\Dr* 96 6 9?r a!%bq!%9wbb 5'q!%ar@ @( ZXnB,Y6K>%!YSue LaChapelleis" : S $?S " : S $?S " : S $>S " : S $>S" : S $>S"" : @S $" : S $?S " : S $?SY $Y "#JJ]H"- '-!'  & L:G_6 -!   &-!(- ( M3|s`;7 3 9?,2'9(  4A%,A&, Nc^a$@;aѨLastSeekInstigator:9VSeekLocation:9X $@ G// Copyright (C) 2005 Brainbox Games. All Rights Reserved. // September 27, 2005 //----------------------------------------------------------- // //----------------------------------------------------------- class BDHSCopMale extends StandardMaleBase placeable; function BeginPlay() { Super.BeginPlay(); SpecialDamage.Remove( 0,5); SpecialDamage.Remove( 1,2); } IebB,Y6S?~T.Y!YKen LaChapelleis" : S $?S " : S $?S " : S $>S " : S $>S" : S $>S"" : @S $" : S $?S " : S $?SY $Y "#RpoB,Y6TR>.Y!Y"Dominic FeiraSeelan Vamathevais" : S $?S " : S $?S " : S $>S " : S $>S" : S $>S"" : @S $" : S $?S " : S $?SY $Y "#QKeb." HHHqHGHNGDGLGEPPG{GBGEHHG`PBGDLtGPGzHMGmGOGnGkEPYGQGGP@GIGMGlGUHTHNHIHDH^HEHFHGQXHvHYGRHHHsHKHZH[HuHXGJGIGTGSH~G[EwGVGRPyGGFP\GyE*G E(QsPXE[EDEAEWGOSEJEcUWEIEoE;E?LuLAPeE[GKEKE4EAECKhRVQ]RQG\P{MaEGSEBQWEEEEENEEYEZEVE`AyAiAjAkAlAmAnAoApAqAzAeAfAgAhCDE9ARABACADAEAFAGAHAIAJASA~AA@AeCXEQAMAWAXAYAZA[A\A]A^A_ALA`AaAbAcCNEPAOA~AcAE<AAABACADAEAJAFAGAHAICvETA`A\GJA^A_A`AaAbAcAdA_AXAYAZA[C^PgA@AvAwAxAyAzA{A|A}A~ACAeAfAgAhCHG|AxAuAvAwAxAyAzA{A|A}AwAqArAsAtCuGdAAAmAnAoApAqArAsAtAuABAiAjAkAlCIQHA~ACADAEAFAGAHAIAJAKAAA@AAABCFQxA|APAQARASATAUAVAWAXA}ALAMANAOCGA@ATAuAvAwAxAyAzA{A|A}AUAqArAsAtCYGNAtAfAgAjAkAlAmAnAoApArAdAeAhAiCsM_AQAJAKALAMANAOAPAQARAPASAgAUAVCKGKAVAhAiAjAkAlAmAnAoApAWAdAeAfAgCZGLA\AOAPAQARASATAUAVAWA]AKALAMANC[A]A{A\A]A^A_A`AaAbAcAdAaAYAbAZA[CEHm C\tPHh D?TQHi _HB lF yHw FHgRHz `b m%^ yHu F/} SY `d m}fzrIHk Wi dy pHf |HjHHo VHp bY n] {Hq GHs SHF _flHy zHx FHv RwZ ^^ kH;qwC h_ u^ Ar NHv [[ g\^ sZ` @WZ MH4uZ[ Od [HH gYt} B^ Ox \w hL tt@} Of \f if vf CH.WPZ gZ trAb OH~[a i}juH@ C@sOHG BHz NHs ZHq f\a sOY2CME#POv s`5TZt6aNTNoUc NT*7[+RT(6}TI-s+`TJ1KHO|+KHr v9#Csv f+rf~ ]fp4Y[+tgX_f+wjp4]bHl iXKHn cy+m+X+CHr n+wHt byp4^lP"JHp4_l+Kwv vQIBp4{SKjiFp4Yop4YHcp4XaANyH{ GH| SH}_H~mH {H@ GHA Pkf\HCZBUs\v Op4][p4YxHQ} p]j}%a glWsHW)J<(sHAP[j+kp4SV[BimG k?v rH0s~p4Wqp4WHHXv_v U_~aH8a_*@(]V#{H/R^*p((M?#u0XZ$He lY$uc+YH%AD*CE(-HB-uEb?hAc ip4]u/4=RcXO%;8ga _+k?. VTvv DK]Pv m`XyH,z Q**K(>u/4:s+m%;XXp4Upp4WEHDI\aTeH[byp4W[HFRrnZDHJF^H:?dH|Hc+kv VHcLbp4RnbZ@okZHK7E