WIP New MTF AI
Posted: Mon Sep 07, 2015 9:54 pm
Replace the FindPath function in MapSystem.bb with this, as it currently has a bug that generates an invalid path when more than 20 waypoints need to be traversed to reach a destination:
Replace the NPCs type in NPCs.bb with this:
Add this code somewhere in NPCs.bb:
And then replace NPCtypeMTF's case in UpdateNPCs with a call to UpdateMTFUnit. Also add some code to 173 so it can target, kill, and get stopped by MTFs, using OtherNPCSeesMeNPC.
These MTFs are much better at containing 173 than the ones currently ingame (they ignore the player properly now). One MTF unit is a leader, while the others will follow the leader around. They have actual blink timers. They have to face the player to detect them, same with 173. They are usually trying to get to the LCZ as soon as possible. The leader can push other MTFs out of their way, to prevent them from getting stuck in any weird places (this isn't fully functional yet).
This code still needs support for voice lines (the MTFs are mute) and shooting the player (they just follow you). They also need to be able to detect, run away from, and get killed by 106.
Code: Select all
Function FindPath(n.NPCs, x#, y#, z#)
DebugLog "findpath: "+n\NPCtype
Local temp%, dist#, dist2#
Local xtemp#, ytemp#, ztemp#
Local w.WayPoints, StartPoint.WayPoints, EndPoint.WayPoints
Local StartX% = Floor(EntityX(n\Collider,True) / 8.0 + 0.5), StartZ% = Floor(EntityZ(n\Collider,True) / 8.0 + 0.5)
;If StartX < 0 Or StartX > MapWidth Then Return 2
;If StartZ < 0 Or StartZ > MapWidth Then Return 2
Local EndX% = Floor(x / 8.0 + 0.5), EndZ% = Floor(z / 8.0 + 0.5)
;If EndX < 0 Or EndX > MapWidth Then Return 2
;If EndZ < 0 Or EndZ > MapWidth Then Return 2
Local CurrX, CurrZ
;pathstatus = 0, ei ole etsitty reittiä
;pathstatus = 1, reitti löydetty
;pathstatus = 2, reittiä ei ole olemassa
For w.WayPoints = Each WayPoints
w\state = 0
w\Fcost = 0
w\Gcost = 0
w\Hcost = 0
Next
n\PathStatus = 0
n\PathLocation = 0
For i = 0 To 19
n\Path[i] = Null
Next
Local pvt = CreatePivot()
PositionEntity(pvt, x,y,z, True)
temp = CreatePivot()
PositionEntity(temp, EntityX(n\Collider,True), EntityY(n\Collider,True)+0.15, EntityZ(n\Collider,True))
;käytetään aloituspisteenä waypointia, joka on lähimpänä loppupistettä ja joka on näkyvissä
dist = 400.0
For w.WayPoints = Each WayPoints
xtemp = EntityX(w\obj,True)-EntityX(temp,True)
;If xtemp < 8.0 Then
ztemp = EntityZ(w\obj,True)-EntityZ(temp,True)
;If ztemp < 8.0 Then
ytemp = EntityY(w\obj,True)-EntityY(temp,True)
;If ytemp < 8.0 Then
dist2# = (xtemp*xtemp)+(ytemp*ytemp)+(ztemp*ztemp)
If dist2 < dist Then ; And EntityVisible(w\obj, temp)
dist = dist2
StartPoint = w
EndIf
;EndIf
;EndIf
;EndIf
Next
DebugLog "DIST: "+dist
FreeEntity temp
If StartPoint = Null Then Return 2
StartPoint\state = 1
;If EndPoint = Null Then
EndPoint = Null
dist# = 400.0
For w.WayPoints = Each WayPoints
xtemp = EntityX(pvt,True)-EntityX(w\obj,True)
;If xtemp =< 8.0 Then
ztemp = EntityZ(pvt,True)-EntityZ(w\obj,True)
;If ztemp =< 8 Then
ytemp = EntityY(pvt,True)-EntityY(w\obj,True)
dist2# = (xtemp*xtemp)+(ytemp*ytemp)+(ztemp*ztemp)
If dist2 < dist Then ; And EntityVisible(w\obj, pvt)
dist = dist2
EndPoint = w
EndIf
;EndIf
;EndIf
Next
;EndIf
FreeEntity pvt
If EndPoint = StartPoint Then
If dist < 0.4 Then
Return 0
Else
n\Path[0]=EndPoint
Return 1
EndIf
EndIf
If EndPoint = Null Then Return 2
;aloitus- ja lopetuspisteet löydetty, aletaan etsiä reittiä
Repeat
temp% = False
smallest.WayPoints = Null
dist# = 10000.0
For w.WayPoints = Each WayPoints
If w\state = 1 Then
temp = True
If (w\Fcost) < dist Then
dist = w\Fcost
smallest = w
EndIf
EndIf
Next
If smallest <> Null Then
w = smallest
w\state = 2
For i = 0 To 4
If w\connected[i]<>Null Then
If w\connected[i]\state < 2 Then
If w\connected[i]\state=1 Then ;open list
gtemp# = w\Gcost+w\dist[i]
If n\NPCtype = NPCtypeMTF Then
If w\connected[i]\door = Null Then gtemp = gtemp + 0.5
EndIf
If gtemp < w\connected[i]\Gcost Then ;parempi reitti -> overwrite
w\connected[i]\Gcost = gtemp
w\connected[i]\Fcost = w\connected[i]\Gcost + w\connected[i]\Hcost
w\connected[i]\parent = w
EndIf
Else
w\connected[i]\Hcost# = Abs(EntityX(w\connected[i]\obj,True)-EntityX(EndPoint\obj,True))+Abs(EntityZ(w\connected[i]\obj,True)-EntityZ(EndPoint\obj,True))
gtemp# = w\Gcost+w\dist[i]
If n\NPCtype = NPCtypeMTF Then
If w\connected[i]\door = Null Then gtemp = gtemp + 0.5
EndIf
w\connected[i]\Gcost = gtemp
w\connected[i]\Fcost = w\Gcost+w\Hcost
w\connected[i]\parent = w
w\connected[i]\state=1
EndIf
EndIf
EndIf
Next
Else ;open listiltä ei löytynyt mitään
If EndPoint\state > 0 Then
StartPoint\parent = Null
EndPoint\state = 2
Exit
EndIf
EndIf
If EndPoint\state > 0 Then
StartPoint\parent = Null
EndPoint\state = 2
Exit
EndIf
Until temp = False
If EndPoint\state > 0 Then
currpoint.waypoints = EndPoint
twentiethpoint.waypoints = EndPoint
length = 0
Repeat
length = length +1
currpoint = currpoint\parent
If length>20 Then
twentiethpoint = twentiethpoint\parent
EndIf
Until currpoint = Null
currpoint.waypoints = EndPoint
While twentiethpoint<>Null
length=Min(length-1,19)
;DebugLog "LENGTH "+length
twentiethpoint = twentiethpoint\parent
n\Path[length] = twentiethpoint
Wend
Return 1
;RuntimeError length
; For i = 0 To (length-1)
; temp =False
; If length < 20 Then
; n\Path[length-1-i] = currpoint.WayPoints
; Else
; If i < 20 Then
; n\Path[20-1-i] = w.WayPoints
; Else
; ;Return 1
; EndIf
; EndIf
;
; If currpoint = StartPoint Then Return 1
;
; If currpoint\parent <> Null Then
; currpoint = currpoint\parent
; Else
; Exit
; EndIf
;
; Next
Else
DebugLog "FUNCTION FindPath() - reittiä ei löytynyt"
Return 2 ;reittiä määränpäähän ei löytynyt
EndIf
End Function
Code: Select all
Type NPCs
Field obj%, obj2%, obj3%, obj4%, Collider%
Field NPCtype%, ID%
Field DropSpeed#, Gravity%
Field State#, State2#, State3#, PrevState%
Field MakingNoise%
Field Frame#
Field Angle#
Field Sound%, SoundChn%, SoundTimer#
Field Sound2%, SoundChn2%
Field Speed#, CurrSpeed#
Field texture$
Field Idle#
Field Reload#
Field LastSeen%, LastDist#
Field PrevX#, PrevY#, PrevZ#
Field Target.NPCs, TargetID%
Field EnemyX#, EnemyY#, EnemyZ#
Field Path.WayPoints[20], PathStatus%, PathTimer#, PathLocation%
Field NVX#,NVY#,NVZ#,NVName$
Field GravityMult# = 1.0
Field MaxGravity# = 0.2
Field MTFVariant%
Field MTFLeader.NPCs
Field IsDead%
Field BlinkTimer#
Field IgnorePlayer%
End Type
Code: Select all
Function OtherNPCSeesMeNPC%(me.NPCs,other.NPCs)
If other\BlinkTimer<=0.0 Then Return False
If EntityDistance(other\Collider,me\Collider)<4.0 Then
If Abs(DeltaYaw(other\Collider,me\Collider))<40.0 Then
Return True
EndIf
EndIf
Return False
End Function
Function MeNPCSeesPlayer%(me.NPCs)
If me\BlinkTimer<=0.0 Then Return False
If EntityDistance(Collider,me\Collider)<4.0 Then
If Abs(DeltaYaw(me\Collider,Collider))<40.0 Then
Return True
EndIf
EndIf
Return False
End Function
Function UpdateMTFUnit(n.NPCs)
;[Block]
If n\NPCtype<>NPCtypeMTF Then
Local realType$ = ""
Select n\NPCtype
Case NPCtype173
realType = "173"
Case NPCtypeOldMan
realType = "106"
Case NPCtypeGuard
realType = "guard"
Case NPCtypeD
realType = "d"
Case NPCtype372
realType = "372"
Case NPCtypeApache
realType = "apache"
Case NPCtype096
realType = "096"
Case NPCtype049
realType = "049"
Case NPCtypeZombie
realType = "zombie"
Case NPCtype5131
realType = "513-1"
Case NPCtypeTentacle
realType = "tentacle"
Case NPCtype860
realType = "860"
Case NPCtype939
realType = "939"
Case NPCtype066
realType = "066"
Case NPCtype178
realType = "178"
Case NPCtypePdPlane
realType = "PDPlane"
Case NPCtype966
realType = "966"
Case NPCtype1048a
realType = "1048-A"
End Select
RuntimeError "Called UpdateMTFUnit on "+realType
EndIf
;[End Block]
Local x#,y#,z#
Local r.Rooms
Local prevDist#,newDist#
Local n2.NPCs
n\MaxGravity = 0.03
n\BlinkTimer=n\BlinkTimer-FPSfactor
If n\BlinkTimer<=-5.0 Then n\BlinkTimer = 70.0*Rnd(10.0,15.0)
If n\IsDead Then
n\BlinkTimer = -1.0
SetNPCFrame(n, 532)
Return
EndIf
For d.Doors = Each Doors
If (EntityDistance(d\frameobj,n\Collider)<1.2) Then
If (Abs(DeltaYaw(n\Collider,d\frameobj))<45.0) Then
d\open = True
d\templocked = True
EndIf
EndIf
;should add something to stop mtfs from opening doors into the void
Next
DebugLog n\State
If n\Idle>0.0 Then
n\Idle=n\Idle-FPSfactor
If n\Idle<=0.0 Then n\Idle = 0.0
Else
Select Int(n\State) ;what is this MTF doing
Case 0 ;wandering around
;[Block]
n\Speed = 0.015
If n\PathTimer<=0.0 Then ;update path
If n\MTFLeader<>Null Then ;i'll follow the leader
n\PathStatus = FindPath(n,EntityX(n\MTFLeader\Collider,True),EntityY(n\MTFLeader\Collider,True)+0.1,EntityZ(n\MTFLeader\Collider,True)) ;whatever you say boss
Else ;i am the leader
For r = Each Rooms
If ((Abs(r\x-EntityX(n\Collider,True))>12.0) Or (Abs(r\z-EntityZ(n\Collider,True))>12.0)) And (Rand(1,Max(4-Int(Abs(r\z-EntityZ(n\Collider,True)/8.0)),2))=1) Then
x = r\x
y = 0.5
z = r\z
DebugLog r\roomtemplate\Name
Exit
EndIf
Next
n\PathStatus = FindPath(n,x,y,z) ;we're going to this room for no particular reason
EndIf
If n\PathStatus = 1 Then
While n\Path[n\PathLocation]=Null
If n\PathLocation>19 Then Exit
n\PathLocation=n\PathLocation+1
Wend
If n\PathLocation<19 Then
If (n\Path[n\PathLocation]<>Null) And (n\Path[n\PathLocation+1]<>Null) Then
If Abs(DeltaYaw(n\Collider,n\Path[n\PathLocation]\obj))>Abs(DeltaYaw(n\Collider,n\Path[n\PathLocation+1]\obj)) Then
n\PathLocation=n\PathLocation+1
EndIf
EndIf
EndIf
EndIf
n\PathTimer = 70.0 * Rnd(6.0,10.0) ;search again after 6-10 seconds
ElseIf (n\PathTimer<=70.0 * 2.5) And (n\MTFLeader=Null) Then
n\PathTimer=n\PathTimer-FPSfactor
n\CurrSpeed = 0.0
If Rand(1,35)=1 Then
RotateEntity n\Collider,0.0,Rnd(360.0),0.0,True
EndIf
n\Angle = CurveAngle(EntityYaw(n\Collider,True),n\Angle,20.0)
RotateEntity n\obj,-90.0,n\Angle,0.0,True
Else
If n\PathStatus=2 Then
n\PathTimer=n\PathTimer-(FPSfactor*2.0) ;timer goes down fast
n\CurrSpeed = 0.0
If Rand(1,35)=1 Then
RotateEntity n\Collider,0.0,Rnd(360.0),0.0,True
EndIf
n\Angle = CurveAngle(EntityYaw(n\Collider,True),n\Angle,20.0)
RotateEntity n\obj,-90.0,n\Angle,0.0,True
ElseIf n\PathStatus=1 Then
If n\Path[n\PathLocation]=Null Then
If n\PathLocation > 19 Then
n\PathLocation = 0 : n\PathStatus = 0
Else
n\PathLocation = n\PathLocation + 1
EndIf
Else
prevDist# = EntityDistance(n\Collider,n\Path[n\PathLocation]\obj)
PointEntity n\Collider,n\Path[n\PathLocation]\obj
RotateEntity n\Collider,0.0,EntityYaw(n\Collider,True),0.0,True
n\Angle = CurveAngle(EntityYaw(n\Collider,True),n\Angle,20.0)
RotateEntity n\obj,-90.0,n\Angle,0.0,True
n\CurrSpeed = CurveValue(n\Speed,n\CurrSpeed,20.0)
;MoveEntity n\Collider, 0, 0, n\CurrSpeed * FPSfactor
TranslateEntity n\Collider, Cos(EntityYaw(n\Collider,True)+90.0)*n\CurrSpeed * FPSfactor, 0, Sin(EntityYaw(n\Collider,True)+90.0)*n\CurrSpeed * FPSfactor, True
AnimateNPC(n,488, 522, n\CurrSpeed*26)
newDist# = EntityDistance(n\Collider,n\Path[n\PathLocation]\obj)
If (newDist<0.2) Or ((prevDist<newDist) And (prevDist<1.0)) Then
n\PathLocation=n\PathLocation+1
EndIf
EndIf
n\PathTimer=n\PathTimer-FPSfactor ;timer goes down slow
Else
n\PathTimer=n\PathTimer-(FPSfactor*2.0) ;timer goes down fast
If n\MTFLeader = Null Then
If Rand(1,35)=1 Then
RotateEntity n\Collider,0.0,Rnd(360.0),0.0,True
EndIf
n\CurrSpeed = 0.0
ElseIf EntityDistance(n\Collider,n\MTFLeader\Collider)>1.0 Then
PointEntity n\Collider,n\MTFLeader\Collider
RotateEntity n\Collider,0.0,EntityYaw(n\Collider,True),0.0,True
n\CurrSpeed = CurveValue(n\Speed,n\CurrSpeed,20.0)
TranslateEntity n\Collider, Cos(EntityYaw(n\Collider,True)+90.0)*n\CurrSpeed * FPSfactor, 0, Sin(EntityYaw(n\Collider,True)+90.0)*n\CurrSpeed * FPSfactor, True
AnimateNPC(n,488, 522, n\CurrSpeed*26)
Else
If Rand(1,35)=1 Then
RotateEntity n\Collider,0.0,Rnd(360.0),0.0,True
EndIf
n\CurrSpeed = 0.0
EndIf
n\Angle = CurveAngle(EntityYaw(n\Collider,True),n\Angle,20.0)
RotateEntity n\obj,-90.0,n\Angle,0.0,True
EndIf
EndIf
If EntityVisible(n\Collider,Camera) And MeNPCSeesPlayer(n) Then
n\State = 1
n\EnemyX = EntityX(Collider,True)
n\EnemyY = EntityY(Collider,True)
n\EnemyZ = EntityZ(Collider,True)
n\State2 = 70.0*15.0 ;give up after 15 seconds
n\PathTimer=0.0
n\PathStatus=0
EndIf
If EntityVisible(n\Collider,Curr173\Collider) And OtherNPCSeesMeNPC(Curr173,n) And (Curr173\Idle<2) Then
n\State = 2
n\EnemyX = EntityX(Curr173\Collider,True)
n\EnemyY = EntityY(Curr173\Collider,True)
n\EnemyZ = EntityZ(Curr173\Collider,True)
n\State2 = 70.0*15.0 ;give up after 15 seconds
n\State3 = 0.0
n\PathTimer=0.0
n\PathStatus=0
EndIf
;[End Block]
Case 1 ;searching for player
;[Block]
n\Speed = 0.015
n\State2=n\State2-FPSfactor
If EntityVisible(n\Collider,Camera) And MeNPCSeesPlayer(n) Then
n\EnemyX = EntityX(Collider,True)
n\EnemyY = EntityY(Collider,True)
n\EnemyZ = EntityZ(Collider,True)
n\State2 = 70.0*15.0 ;give up after 15 seconds
n\PathTimer=0.0
n\PathStatus=0
For n2.NPCs = Each NPCs
If n2<>n Then
If (n2\NPCtype = NPCtypeMTF) And (n2\State<2) Then
n2\State = 1
n2\EnemyX = EntityX(Collider,True)
n2\EnemyY = EntityY(Collider,True)
n2\EnemyZ = EntityZ(Collider,True)
n2\State2=n2\State2-(FPSfactor*4) ;timer goes down really fast
EndIf
EndIf
Next
If Distance(EntityX(n\Collider,True),EntityZ(n\Collider,True),n\EnemyX,n\EnemyZ)<0.2 Then
; n\CurrSpeed = 0.0
; n\State2=n\State2-FPSfactor
; If Rand(1,30)=1 Then
; x = Rnd(-6.0,6.0)
; z = Rnd(-6.0,6.0)
;
; n\EnemyX = n\EnemyX+x
; n\EnemyY = EntityY(n\Collider,True)
; n\EnemyZ = n\EnemyZ+z
; EndIf
Else
PositionEntity n\obj,n\EnemyX,n\EnemyY,n\EnemyZ,True
PointEntity n\Collider,n\obj
RotateEntity n\Collider,0.0,EntityYaw(n\Collider,True),0.0,True
n\Angle = CurveAngle(EntityYaw(n\Collider,True),n\Angle,20.0)
RotateEntity n\obj,-90.0,n\Angle,0.0,True
n\CurrSpeed = CurveValue(n\Speed,n\CurrSpeed,20.0)
TranslateEntity n\Collider, Cos(EntityYaw(n\Collider,True)+90.0)*n\CurrSpeed * FPSfactor, 0, Sin(EntityYaw(n\Collider,True)+90.0)*n\CurrSpeed * FPSfactor, True
AnimateNPC(n,488, 522, n\CurrSpeed*26)
EndIf
Else
If n\PathTimer<=0.0 Then ;update path
n\PathStatus = FindPath(n,n\EnemyX,n\EnemyY+0.1,n\EnemyZ)
n\PathTimer = 70.0 * Rnd(6.0,10.0) ;search again after 6 seconds
ElseIf n\PathTimer<=70.0 * 2.5 Then
n\PathTimer=n\PathTimer-FPSfactor
n\CurrSpeed = 0.0
If Rand(1,35)=1 Then
RotateEntity n\Collider,0.0,Rnd(360.0),0.0,True
EndIf
n\Angle = CurveAngle(EntityYaw(n\Collider,True),n\Angle,20.0)
RotateEntity n\obj,-90.0,n\Angle,0.0,True
Else
If n\PathStatus=2 Then
n\PathTimer=n\PathTimer-(FPSfactor*2.0) ;timer goes down fast
n\CurrSpeed = 0.0
If Rand(1,35)=1 Then
RotateEntity n\Collider,0.0,Rnd(360.0),0.0,True
EndIf
n\Angle = CurveAngle(EntityYaw(n\Collider,True),n\Angle,20.0)
RotateEntity n\obj,-90.0,n\Angle,0.0,True
ElseIf n\PathStatus=1 Then
If n\Path[n\PathLocation]=Null Then
If n\PathLocation > 19 Then
n\PathLocation = 0 : n\PathStatus = 0
Else
n\PathLocation = n\PathLocation + 1
EndIf
Else
prevDist# = EntityDistance(n\Collider,n\Path[n\PathLocation]\obj)
PointEntity n\Collider,n\Path[n\PathLocation]\obj
RotateEntity n\Collider,0.0,EntityYaw(n\Collider,True),0.0,True
n\Angle = CurveAngle(EntityYaw(n\Collider,True),n\Angle,20.0)
RotateEntity n\obj,-90.0,n\Angle,0.0,True
n\CurrSpeed = CurveValue(n\Speed,n\CurrSpeed,20.0)
TranslateEntity n\Collider, Cos(EntityYaw(n\Collider,True)+90.0)*n\CurrSpeed * FPSfactor, 0, Sin(EntityYaw(n\Collider,True)+90.0)*n\CurrSpeed * FPSfactor, True
AnimateNPC(n,488, 522, n\CurrSpeed*26)
newDist# = EntityDistance(n\Collider,n\Path[n\PathLocation]\obj)
If (newDist<0.2) Or ((prevDist<newDist) And (prevDist<1.0)) Then
n\PathLocation=n\PathLocation+1
EndIf
EndIf
n\PathTimer=n\PathTimer-FPSfactor ;timer goes down slow
Else
PositionEntity n\obj,n\EnemyX,n\EnemyY,n\EnemyZ,True
If (Distance(EntityX(n\Collider,True),EntityZ(n\Collider,True),n\EnemyX,n\EnemyZ)<0.2) Or (Not EntityVisible(n\obj,n\Collider)) Then
If Rand(1,35)=1 Then
RotateEntity n\Collider,0.0,Rnd(360.0),0.0,True
EndIf
If Rand(1,35)=1 Then
For wp.Waypoints = Each Waypoints
If (EntityDistance(wp\obj,n\Collider)<6.0) And (Rand(1,3)=1) Then
n\EnemyX = EntityX(wp\obj,True)
n\EnemyY = EntityY(wp\obj,True)
n\EnemyZ = EntityZ(wp\obj,True)
n\PathTimer = 0.0
Exit
EndIf
Next
EndIf
n\PathTimer=n\PathTimer-FPSfactor ;timer goes down slow
Else
PointEntity n\Collider,n\obj
RotateEntity n\Collider,0.0,EntityYaw(n\Collider,True),0.0,True
n\Angle = CurveAngle(EntityYaw(n\Collider,True),n\Angle,20.0)
RotateEntity n\obj,-90.0,n\Angle,0.0,True
n\CurrSpeed = CurveValue(n\Speed,n\CurrSpeed,20.0)
TranslateEntity n\Collider, Cos(EntityYaw(n\Collider,True)+90.0)*n\CurrSpeed * FPSfactor, 0, Sin(EntityYaw(n\Collider,True)+90.0)*n\CurrSpeed * FPSfactor, True
AnimateNPC(n,488, 522, n\CurrSpeed*26)
EndIf
EndIf
EndIf
EndIf
If n\State2<=0.0 Then
n\State = 0
EndIf
If EntityVisible(n\Collider,Curr173\Collider) And OtherNPCSeesMeNPC(Curr173,n) And (Curr173\Idle<2) Then
n\State = 2
n\EnemyX = EntityX(Curr173\Collider,True)
n\EnemyY = EntityY(Curr173\Collider,True)
n\EnemyZ = EntityZ(Curr173\Collider,True)
n\State2 = 70.0*15.0 ;give up after 15 seconds
n\State3 = 0.0
n\PathTimer=0.0
n\PathStatus=0
EndIf
;DebugLog Distance(EntityX(n\Collider,True),EntityZ(n\Collider,True),n\EnemyX,n\EnemyZ)
;[End Block]
Case 2 ;searching for/looking at 173
;[Block]
If Curr173\Idle = 2 Then
n\State = 0
Else
For n2.NPCs = Each NPCs
If n2<>n Then
If n2\NPCtype = NPCtypeMTF Then
n2\State = 2
EndIf
EndIf
Next
If EntityVisible(n\Collider,Curr173\Collider) Then
n\State2 = 70.0*15.0
n\PathTimer = 0.0
dist# = 1.0
If n\MTFLeader<>Null Then dist = 2.0
If Distance(EntityX(n\Collider,True),EntityZ(n\Collider,True),EntityX(Curr173\Collider,True),EntityZ(Curr173\Collider,True))<dist Then
If n\MTFLeader = Null Then
n\State3=n\State3+FPSfactor
DebugLog "CONTAINING 173: "+n\State3
If n\State3>=70.0*10.0 Then
Curr173\Idle = 2
EndIf
EndIf
Else
PositionEntity n\obj,EntityX(Curr173\Collider,True),EntityY(Curr173\Collider,True),EntityZ(Curr173\Collider,True),True
PointEntity n\Collider,n\obj
RotateEntity n\Collider,0.0,EntityYaw(n\Collider,True),0.0,True
n\Angle = CurveAngle(EntityYaw(n\Collider,True),n\Angle,20.0)
RotateEntity n\obj,-90.0,n\Angle,0.0,True
n\CurrSpeed = CurveValue(n\Speed,n\CurrSpeed,20.0)
TranslateEntity n\Collider, Cos(EntityYaw(n\Collider,True)+90.0)*n\CurrSpeed * FPSfactor, 0, Sin(EntityYaw(n\Collider,True)+90.0)*n\CurrSpeed * FPSfactor, True
AnimateNPC(n,488, 522, n\CurrSpeed*26)
EndIf
Else
If n\PathTimer<=0.0 Then ;update path
n\PathStatus = FindPath(n,EntityX(Curr173\Collider,True),EntityY(Curr173\Collider,True)+0.1,EntityZ(Curr173\Collider,True))
n\PathTimer = 70.0 * Rnd(6.0,10.0) ;search again after 6 seconds
ElseIf n\PathTimer<=70.0 * 2.5 Then
n\PathTimer=n\PathTimer-FPSfactor
n\CurrSpeed = 0.0
If Rand(1,35)=1 Then
RotateEntity n\Collider,0.0,Rnd(360.0),0.0,True
EndIf
n\Angle = CurveAngle(EntityYaw(n\Collider,True),n\Angle,20.0)
RotateEntity n\obj,-90.0,n\Angle,0.0,True
Else
If n\PathStatus=2 Then
n\PathTimer=n\PathTimer-(FPSfactor*2.0) ;timer goes down fast
n\CurrSpeed = 0.0
If Rand(1,35)=1 Then
RotateEntity n\Collider,0.0,Rnd(360.0),0.0,True
EndIf
n\Angle = CurveAngle(EntityYaw(n\Collider,True),n\Angle,20.0)
RotateEntity n\obj,-90.0,n\Angle,0.0,True
ElseIf n\PathStatus=1 Then
If n\Path[n\PathLocation]=Null Then
If n\PathLocation > 19 Then
n\PathLocation = 0 : n\PathStatus = 0
Else
n\PathLocation = n\PathLocation + 1
EndIf
Else
prevDist# = EntityDistance(n\Collider,n\Path[n\PathLocation]\obj)
PointEntity n\Collider,n\Path[n\PathLocation]\obj
RotateEntity n\Collider,0.0,EntityYaw(n\Collider,True),0.0,True
n\Angle = CurveAngle(EntityYaw(n\Collider,True),n\Angle,20.0)
RotateEntity n\obj,-90.0,n\Angle,0.0,True
n\CurrSpeed = CurveValue(n\Speed,n\CurrSpeed,20.0)
TranslateEntity n\Collider, Cos(EntityYaw(n\Collider,True)+90.0)*n\CurrSpeed * FPSfactor, 0, Sin(EntityYaw(n\Collider,True)+90.0)*n\CurrSpeed * FPSfactor, True
AnimateNPC(n,488, 522, n\CurrSpeed*26)
newDist# = EntityDistance(n\Collider,n\Path[n\PathLocation]\obj)
If (newDist<0.2) Or ((prevDist<newDist) And (prevDist<1.0)) Then
n\PathLocation=n\PathLocation+1
EndIf
EndIf
n\PathTimer=n\PathTimer-FPSfactor ;timer goes down slow
Else
n\PathTimer=n\PathTimer-(FPSfactor*2.0) ;timer goes down fast
n\CurrSpeed = 0.0
If Rand(1,35)=1 Then
RotateEntity n\Collider,0.0,Rnd(360.0),0.0,True
EndIf
n\Angle = CurveAngle(EntityYaw(n\Collider,True),n\Angle,20.0)
RotateEntity n\obj,-90.0,n\Angle,0.0,True
EndIf
EndIf
EndIf
EndIf
;[End Block]
End Select
If n\MTFLeader<>Null Then
If EntityDistance(n\Collider,n\MTFLeader\Collider)<0.7 Then
PointEntity n\Collider,n\MTFLeader\Collider
RotateEntity n\Collider,0.0,EntityYaw(n\Collider,True),0.0,True
n\Angle = CurveAngle(EntityYaw(n\Collider,True),n\Angle,20.0)
RotateEntity n\obj,-90.0,n\Angle,0.0,True
TranslateEntity n\Collider, Cos(EntityYaw(n\Collider,True)-45)* 0.01 * FPSfactor, 0, Sin(EntityYaw(n\Collider,True)-45)* 0.01 * FPSfactor, True
EndIf
Else
For n2.NPCs = Each NPCs
If (EntityDistance(n\Collider,n2\Collider)<0.7) And (Abs(DeltaYaw(n\Collider,n2\Collider))<80.0) Then
TranslateEntity n2\Collider, Cos(EntityYaw(n\Collider,True)+90)* 0.01 * FPSfactor, 0, Sin(EntityYaw(n\Collider,True)+90)* 0.01 * FPSfactor, True
EndIf
Next
EndIf
PositionEntity n\obj,EntityX(n\Collider,True),EntityY(n\Collider,True)-0.1,EntityZ(n\Collider,True),True
EndIf
End Function
These MTFs are much better at containing 173 than the ones currently ingame (they ignore the player properly now). One MTF unit is a leader, while the others will follow the leader around. They have actual blink timers. They have to face the player to detect them, same with 173. They are usually trying to get to the LCZ as soon as possible. The leader can push other MTFs out of their way, to prevent them from getting stuck in any weird places (this isn't fully functional yet).
This code still needs support for voice lines (the MTFs are mute) and shooting the player (they just follow you). They also need to be able to detect, run away from, and get killed by 106.