// Helper actor to find all possible spawnpoints for humans on the map. Class ExtSpawnPointHelper extends Info transient; var transient array PendingList,CheckedList; var array ValidSpawnSpots; static final function ExtSpawnPointHelper FindHelper(WorldInfo Level) { local ExtSpawnPointHelper H; foreach Level.DynamicActors(class'ExtSpawnPointHelper',H) return H; return Level.Spawn(class'ExtSpawnPointHelper'); } final function Actor PickBestSpawn() { local Actor N,BestN; local KFPawn P; local float Score,BestScore,Dist; local KFPawn_Human H; BestN = None; BestScore = 0; foreach ValidSpawnSpots(N) { if(Rand(4)==0) { Score = FRand(); foreach WorldInfo.AllPawns(class'KFPawn',P,N.Location,2000.f) { if(!P.IsAliveAndWell()) continue; Dist = VSize(N.Location-P.Location); if(FastTrace(P.Location,N.Location)) Dist*=0.75; if(P.IsA('KFPawn_Human')) Score+=(3000.f-Dist)/2000.f; else Score-=(3500.f-Dist)/2500.f; } if(BestN==None || Score>BestScore) { BestN = N; BestScore = Score; } } } // See if can spawn ontop of other players. foreach WorldInfo.AllPawns(class'KFPawn_Human',H) { if(!H.IsAliveAndWell() || H.Physics==PHYS_Falling || (ExtHumanPawn(H)!=None && ExtHumanPawn(H).bFeigningDeath)) continue; Score = FRand(); foreach WorldInfo.AllPawns(class'KFPawn',P,H.Location,2000.f) { if(!P.IsAliveAndWell()) continue; Dist = VSize(H.Location-P.Location); if(FastTrace(P.Location,H.Location)) Dist*=0.75; if(P.IsA('KFPawn_Human')) Score+=(3000.f-Dist)/3000.f; else Score-=(3500.f-Dist)/3500.f; } if(BestN==None || Score>BestScore) { BestN = H; BestScore = Score; } } return BestN; } function PreBeginPlay() { SetTimer(0.2,false,'InitChecker'); } function InitChecker() { local PlayerStart PS,Fallback; foreach WorldInfo.AllNavigationPoints(class'PlayerStart',PS) { Fallback = PS; if(PS.bEnabled && PS.TeamIndex==0) { CheckSpawn(PS); if(PendingList.Length!=0) break; } } if(PendingList.Length==0 && Fallback!=None) CheckSpawn(Fallback); SetTimer(0.001,true,'NextCheck'); } function NextCheck() { local NavigationPoint N; local byte i; if(PendingList.Length!=0) { while(++i<5 && PendingList.Length!=0) { N = PendingList[PendingList.Length-1]; PendingList.Remove(PendingList.Length-1,1); CheckSpawn(N); } } else { ClearTimer('NextCheck'); CheckedList.Length = 0; } } final function CheckSpawn(NavigationPoint N) { local vector V; local ReachSpec R; local NavigationPoint E; local KFPawnBlockingVolume P; V = N.Location; if(N.MaxPathSize.Radius>30 && N.MaxPathSize.Height>80 && FindSpot(vect(36,36,86),V) && KFDoorMarker(N)==None && PickupFactory(N)==None) { //DrawDebugLine(V,V+vect(0,0,50),255,255,255,true); ValidSpawnSpots.AddItem(N); } CheckedList.AddItem(N); foreach N.PathList(R) { E = R.GetEnd(); if(E==None || R.CollisionRadius<30 || R.CollisionHeight<80 || R.Class==Class'ProscribedReachSpec') { //if(E!=None) // DrawDebugLine(E.Location,N.Location,255,255,0,true); continue; } if(CheckedList.Find(E)!=INDEX_NONE) continue; // DO NOT go through any blocking volumes. V = (N.Location+E.Location) * 0.5; foreach OverlappingActors(class'KFPawnBlockingVolume',P,VSize(N.Location-V),V) { if(P.bBlockPlayers && TraceComponent(V,V,P.CollisionComponent,E.Location,N.Location,vect(36,36,50))) break; } if(P==None) { //DrawDebugLine(E.Location,N.Location,0,255,0,true); PendingList.AddItem(E); } //else DrawDebugLine(E.Location,N.Location,255,0,0,true); } }