// A friendly NPC that can simply talk with a player. // turbo added hack line 328 Class ZMMNPC extends ScriptedPawn Abstract; var() name InitalOrderTag; var NPCOrder CurrentOrder; var transient float BumpTimer; var transient byte NumBumps; var Actor OldMoveTarget; struct FChatMode { var DialogueBox ChatBox; var byte CurLine; var bool bIsChatting; }; var FChatMode ChatMode; // Takes up ~33 (16+8+1) bits of bandwidth var ZMMPlayer TalkingTo; var array CoTalkers; var ZMMNPC CurrentTalker; var Actor TalkMoveDest,TalkViewFocus; var bool bIsCoTalker,bReadyForNextLine; replication { reliable if ( Role==ROLE_Authority ) ChatMode; } function PostBeginPlay() { local NPCOrder N; Super.PostBeginPlay(); if( InitalOrderTag!='' ) foreach AllActors(Class'NPCOrder',N,InitalOrderTag) { SetNewOrders(N); break; } } function DrawEditorSelection( Canvas C ) { local NPCOrder N; if( InitalOrderTag!='' ) foreach AllActors(Class'NPCOrder',N,InitalOrderTag) { C.Draw3DLine(MakeColor(255,255,25),Location,N.Location); break; } } function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType ); function Bump( Actor Other ) { local vector X,Y,Z; if( Other.bIsPawn && Acceleration!=vect(0,0,0) && (Acceleration Dot (Other.Location-Location))>0.f ) { if( BumpTimer0.f ) Y = -Y; OldMoveTarget = MoveTarget; Destination = Location+Y*(CollisionRadius+Other.CollisionRadius); BumpTimer = Level.TimeSeconds+4.f; NumBumps = 0; NotifyEvadeMove(); } else if( ++NumBumps>=20 ) // Someone is blocking his path. { // Allow walk through so player can't break cutscenes. bBlockActors = false; bBlockPlayers = false; SetTimer(2,false,'EnableCollision'); } } } function EnableCollision() { BumpTimer = 0.f; bBlockActors = true; bBlockPlayers = true; } function TalkedToBy( ZMMPlayer Other ) { local Pawn P; local int i; if( CurrentOrder==None || CurrentOrder.MyDialogue==None ) return; ChatMode.ChatBox = CurrentOrder.MyDialogue; ChatMode.CurLine = 0; TalkingTo = Other; Other.TalkingTarget = Self; Other.bFreezeInput = true; for( P=Level.PawnList; P!=None; P=P.nextPawn ) { if( P.Health>0 && ZMMNPC(P)!=None && !P.IsInState('Talking') && ChatMode.ChatBox.IsATalker(P) ) { ZMMNPC(P).TalkingTo = Other; ZMMNPC(P).ChatMode.ChatBox = ChatMode.ChatBox; ZMMNPC(P).bIsCoTalker = true; CoTalkers[i++] = ZMMNPC(P); P.GoToState('Talking'); } } GoToState('Talking'); } function NextTalkLine( byte AnswerNr ); function SetNewOrders( NPCOrder O ) { numHuntPaths = 0; CurrentOrder = O; OrderObject = O.MyPatrol; } function NotifyEvadeMove(); function EndTalkMode(); function bool SetEnemy( Pawn NewEnemy ) { return false; } state FollowingOrders { function AnimEnd() { if( Acceleration==vect(0,0,0) || CurrentOrder==None ) PlayPatrolStop(); else if( CurrentOrder.bIsRunOrders ) PlayRunning(); else PlayWalking(); } final function FindNextPatrol() { if ( PatrolPoint(OrderObject)!=None && PatrolPoint(OrderObject).nextPatrol!='' ) OrderObject = PatrolPoint(OrderObject).NextPatrolPoint; else OrderObject = None; } function NotifyEvadeMove() { GoToState(,'EvadingMove'); } EvadingMove: if( CurrentOrder!=None && CurrentOrder.bIsRunOrders ) MoveTo(Destination); else MoveTo(Destination, WalkingSpeed); if( OldMoveTarget!=None ) { if( CurrentOrder.bIsRunOrders ) MoveToward(OldMoveTarget); else MoveToward(OldMoveTarget, WalkingSpeed); } Begin: WaitForLanding(); if( CurrentOrder==None || PatrolPoint(OrderObject)==None ) { TweenToPatrolStop(0.3); Stop; } TweenToWalking(0.3); MoveToPatrol: if( actorReachable(OrderObject) ) { if( CurrentOrder.bIsRunOrders ) MoveToward(OrderObject); else MoveToward(OrderObject, WalkingSpeed); } 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; TweenToWalking(0.1); } else if( CurrentOrder.bIsRunOrders ) MoveToward(MoveTarget); else MoveToward(MoveTarget, WalkingSpeed); Goto('MoveToPatrol'); } else Goto('GiveUp'); } ReachedPatrol: if ( Patrolpoint(OrderObject).PauseTime > 0.0 ) { Disable('AnimEnd'); Acceleration = vect(0,0,0); TweenToFighter(0.2); FinishAnim(); PlayTurning(); TurnTo(Location + (Patrolpoint(OrderObject)).lookdir); if ( Patrolpoint(OrderObject).PatrolAnim != '' && HasAnim(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); Enable('AnimEnd'); NextAnim = ''; Sleep((Patrolpoint(OrderObject)).pausetime); } } GiveUp: FindNextPatrol(); GoTo'Begin'; } state Talking { Ignores TalkedToBy; function EndTalkMode() { GoToState('FollowingOrders'); } function EndState() { local int i; if( !bIsCoTalker && TalkingTo!=None ) { TalkingTo.TalkingTarget = None; TalkingTo.bFreezeInput = false; TalkingTo.ClientTalkLine(None,0); } ChatMode.ChatBox = None; ChatMode.CurLine = 0; ChatMode.bIsChatting = false; TalkingTo = None; if( !bIsCoTalker ) { for( i=(Array_Size(CoTalkers)-1); i>=0; --i ) { if( CoTalkers[i]!=None ) CoTalkers[i].EndTalkMode(); } Array_Size(CoTalkers,0); } bIsCoTalker = false; } function AnimEnd() { if( Acceleration==vect(0,0,0) || CurrentOrder==None ) PlayPatrolStop(); else if( CurrentOrder.bIsRunOrders ) PlayRunning(); else PlayWalking(); } function NextTalkLine( byte AnswerNr ) { local byte N; if( CurrentTalker!=None && !CurrentTalker.bReadyForNextLine ) return; if( ChatMode.ChatBox.Lines[ChatMode.CurLine].cEndOfDialog ) { EndTalkMode(); return; } N = Array_Size(ChatMode.ChatBox.Lines[ChatMode.CurLine].bAnswers); if( N>0 ) { N = Min(AnswerNr,N-1); TriggerEvent(ChatMode.ChatBox.Lines[ChatMode.CurLine].bAnswers[N].bAnswerEvent,Self,Self); ChatMode.CurLine = ChatMode.ChatBox.PickedAnswer(TalkingTo,ChatMode.CurLine,N); } else ++ChatMode.CurLine; if( ChatMode.CurLine>=Array_Size(ChatMode.ChatBox.Lines) ) { EndTalkMode(); return; } if( CurrentTalker!=None ) { CurrentTalker.ChatMode.bIsChatting = false; CurrentTalker = None; } GoToState(,'Begin'); } function ProcessNextLine() { local int i; local name N; local Actor A; TalkingTo.ClientTalkLine(ChatMode.ChatBox,ChatMode.CurLine); N = ChatMode.ChatBox.Lines[ChatMode.CurLine].dCameraActor; if( N!='' ) { foreach AllActors(Class'Actor',A,N) break; if( A!=None ) { TalkingTo.ViewTarget = A; TalkingTo.bBehindView = false; //turbo's fixhack to prevent camera from getting stuck //!CurrentTalker.ChatMode.bIsChatting && /* if ( CurrentTalker.bReadyForNextLine ) { CurrentTalker.TalkViewFocus = None; TalkingTo.ViewTarget = None; //TalkingTo.bFreezeInput = false; } */ } } //turbo's fixhack to prevent the camera from getting stuck if( N=='' ) { CurrentTalker.TalkViewFocus = None; TalkingTo.ViewTarget = None; } /* //turbo's fixhack to prevent camera from getting stuck else { TalkingTo.ViewTarget = None; TalkingTo.bFreezeInput = false; CurrentTalker.TalkViewFocus = None; } */ N = ChatMode.ChatBox.Lines[ChatMode.CurLine].eTalkerActor; CurrentTalker = Self; if( N!='' ) { for( i=(Array_Size(CoTalkers)-1); i>=0; --i ) { if( CoTalkers[i]!=None && CoTalkers[i].Tag==N ) { CurrentTalker = CoTalkers[i]; break; } } } CurrentTalker.TalkMoveDest = None; N = ChatMode.ChatBox.Lines[ChatMode.CurLine].eTalkerMoveTo; if( N!='' ) foreach AllActors(Class'Actor',CurrentTalker.TalkMoveDest,N) break; CurrentTalker.TalkViewFocus = None; N = ChatMode.ChatBox.Lines[ChatMode.CurLine].dLookAtActor; if( N!='' ) { if( N=='Player' ) CurrentTalker.TalkViewFocus = TalkingTo; else { foreach AllActors(Class'Actor',CurrentTalker.TalkViewFocus,N) break; } } TriggerEvent(ChatMode.ChatBox.Lines[ChatMode.CurLine].eTextEvent,CurrentTalker,CurrentTalker); CurrentTalker.ChatMode.bIsChatting = true; CurrentTalker.bReadyForNextLine = false; if( CurrentTalker!=Self ) CurrentTalker.ChatMode.CurLine = ChatMode.CurLine; CurrentTalker.GoToState('Talking','HandleTalk'); } Begin: Acceleration = vect(0,0,0); TweenToPatrolStop(0.1); if( bIsCoTalker ) Stop; ProcessNextLine(); stop; HandleTalk: if( TalkMoveDest!=None ) { if( ActorReachable(TalkMoveDest) ) { MoveTarget = TalkMoveDest; TalkMoveDest = None; } else { MoveTarget = FindPathToward(TalkMoveDest); if (SpecialPause > 0.0) { Acceleration = vect(0,0,0); TweenToPatrolStop(0.25); Sleep(SpecialPause); SpecialPause = 0.0; TweenToWalking(0.1); GoTo'HandleTalk'; } } if( MoveTarget!=None ) { TweenToWalking(0.1); if( CurrentOrder.bIsRunOrders ) MoveToward(MoveTarget); else MoveToward(MoveTarget,WalkingSpeed); GoTo'HandleTalk'; } } Acceleration = vect(0,0,0); TweenToPatrolStop(0.1); if( TalkViewFocus!=None && NeedToTurn(TalkViewFocus.Location) ) { Sleep(0.1f); PlayTurning(); TurnToward(TalkViewFocus); TweenToPatrolStop(0.1); } bReadyForNextLine = true; } defaultproperties { Orders=FollowingOrders HearingThreshold=5.00 AttitudeToPlayer=4 Intelligence=3 SightCheckType=2 bEditorSelectRender=True Physics=2 NetUpdateFrequency=20.00 }