Adding NPC AIs

From VbGORE Visual Basic Online RPG Engine

vbGORE comes with several options for NPC behavior built-in, such as simple random movement, running towards and attacking a player, or running away from a player. For any serious, large-scale MMORPG, however, you'll eventually want to write your own. For more information on NPCs, take a look at Adding NPCs.

Note: This tutorial was written with the beginner in mind. If you've worked with vbGORE and VB6 a lot, you can probably skim through most of it.

[edit] Writing the code

Every NPC AI code is located in the server's NPC_AI routine - GameServer.NPCs.NPC_AI. This is called during the server's game loop, when the NPC has passed all the checks for updating - it's alive, it's on a map with users, its action timer has expired (it's time for it to act again), etc.

For the sake of this tutorial, we're going to add AI for a summoned NPC with a ranged attack - in this case he can be a Summoned Ninja. Find the NPC_AI sub, and find a blank spot before the End Select statement. We're going to add the case for our new AI there, so go ahead and add a comment header describing your AI, and the Case number (for this, we want 8). As so:

        '*** Summoned Ranged Attacker ***
        Case 8
 
 
    End Select
 
End Sub

All the code under Case 8 will run whenever an NPC with its AI set to 8 acts. So how do we want this NPC to behave? First, as with the summoned melee attacker (Case 7), we want to make sure that it's only run by a summoned NPC with an owner:


        '*** Summoned Ranged Attacker ***
        Case 8
 
            'This routine is for summoned NPCs only!
            If NPCList(NPCIndex).OwnerIndex = 0 Then
                NPCList(NPCIndex).Counters.ActionDelay = timeGetTime + 5000
                Exit Sub
            End If
 
 
    End Select
 
End Sub

It will reset the action timer and abort the sub if the NPC doesn't have an owner. If the rest of your code is well-designed, this sub should never be called by a non-summoned NPC anyway, but it's always better to be safe than sorry.

Next, we want our NPC to look around for any other NPCs it should be attacking (for now, our NPC will only attack other NPCs, as PvP is a little harder to do).

        '*** Summoned Ranged Attacker ***
        Case 8
 
            'This routine is for summoned NPCs only!
            If NPCList(NPCIndex).OwnerIndex = 0 Then
                NPCList(NPCIndex).Counters.ActionDelay = timeGetTime + 5000
                Exit Sub
            End If
 
            'Look for a near-by NPC
            i = NPC_AI_ClosestNPC(NPCIndex, NPCList(NPCIndex).AttackRange \ 2, NPCList(NPCIndex).AttackRange \ 2, NPCList(NPCIndex).OwnerIndex, 1, 1)
 
 
    End Select
 
End Sub

If you're not entirely sure what the NPC_AI_ClosestNPC sub does, it's easy enough to check (it's in the same module). What this sub does is returns the index of the NPC closest to our NPC, inside the range we specify. It also has options for if the NPC has to be hostile, if the NPC has to be attackable, and if the NPC can't be owned by a certain player. If it finds no NPCs, it will return 0, so let's check for that:


        '*** Summoned Ranged Attacker ***
        Case 8
 
            'This routine is for summoned NPCs only!
            If NPCList(NPCIndex).OwnerIndex = 0 Then
                NPCList(NPCIndex).Counters.ActionDelay = timeGetTime + 5000
                Exit Sub
            End If
 
            'Look for a near-by NPC
            i = NPC_AI_ClosestNPC(NPCIndex, NPCList(NPCIndex).AttackRange \ 2, NPCList(NPCIndex).AttackRange \ 2, NPCList(NPCIndex).OwnerIndex, 1, 1)
 
            'Check to see if we could find something
            If i = 0 Then
 
    End Select
 
End Sub

So what do we want the NPC to do if there isn't anything to attack? We'll have it follow the user around, because it's a summon. In this case, we can just copy+paste some code from Case 7 again:

        '*** Summoned Ranged Attacker ***
        Case 8
 
            'This routine is for summoned NPCs only!
            If NPCList(NPCIndex).OwnerIndex = 0 Then
                NPCList(NPCIndex).Counters.ActionDelay = timeGetTime + 5000
                Exit Sub
            End If
 
            'Look for a near-by NPC
            i = NPC_AI_ClosestNPC(NPCIndex, NPCList(NPCIndex).AttackRange \ 2, NPCList(NPCIndex).AttackRange \ 2, NPCList(NPCIndex).OwnerIndex, 1, 1)
 
            'Check to see if we could find something
            If i = 0 Then
                'There is nothing around to attack, so we want to tell it to move towards the user (we're following a bit behind, don't want to get too close to the action)
                If Abs(CInt(NPCList(NPCIndex).Pos.X) - CInt(UserList(NPCList(NPCIndex).OwnerIndex).Pos.X)) < 4 Then
                    If Abs(CInt(NPCList(NPCIndex).Pos.Y) - CInt(UserList(NPCList(NPCIndex).OwnerIndex).Pos.Y)) < 4 Then
                        NPCList(NPCIndex).Counters.ActionDelay = timeGetTime + 500
                        Exit Sub
                    End If
                End If
    End Select
 
End Sub

That last bit of code might not make too much sense, because it's probably backwards from what you're thinking. What these If statements are doing is checking if the NPC is already close enough to the user, instead of checking if the NPC needs to move closer. So what we have so far, in pseudocode, is basically:

If there is no valid target in range, Then:
    If we're close enough to the user that we don't have to move, Then:
        We don't have to do anything, so abort the routine.

However, if we aren't close enough to the user, we have to move towards him. Since it will automatically exit the sub if the NPC is close enough, we can simply add the code without an Else statement.

        '*** Summoned Ranged Attacker ***
        Case 8
 
            'This routine is for summoned NPCs only!
            If NPCList(NPCIndex).OwnerIndex = 0 Then
                NPCList(NPCIndex).Counters.ActionDelay = timeGetTime + 5000
                Exit Sub
            End If
 
            'Look for a near-by NPC
            i = NPC_AI_ClosestNPC(NPCIndex, NPCList(NPCIndex).AttackRange \ 2, NPCList(NPCIndex).AttackRange \ 2, NPCList(NPCIndex).OwnerIndex, 1, 1)
 
            'Check to see if we could find something
            If i = 0 Then
                'There is nothing around to attack, so we want to tell it to move towards the user (we're following a bit behind, don't want to get too close to the action)
                If Abs(CInt(NPCList(NPCIndex).Pos.X) - CInt(UserList(NPCList(NPCIndex).OwnerIndex).Pos.X)) < 4 Then
                    If Abs(CInt(NPCList(NPCIndex).Pos.Y) - CInt(UserList(NPCList(NPCIndex).OwnerIndex).Pos.Y)) < 4 Then
                        NPCList(NPCIndex).Counters.ActionDelay = timeGetTime + 500
                        Exit Sub
                    End If
                End If
 
                'So let's set the direction toward the player, and try to move
                tHeading = Server_FindDirection(NPCList(NPCIndex).Pos, UserList(NPCList(NPCIndex).OwnerIndex).Pos)
 
                If NPC_MoveChar(NPCIndex, tHeading) = 0 Then
                        'Couldn't move so look for alternate paths
 
    End Select
 
End Sub

Now what we've done is set a variable called tHeading to the direction the user is in, using the Server_FindDirection function. We then try to move using the NPC_MoveChar function. NPC_MoveChar tries to move, and if it is successful (the NPC can move) it returns 1. Needless to say, if it isn't, it returns 0. So let's assume we can't move in a direct line to the user. We're going to try and move diagonally or to the side now (for the sake of saving space, I've cut off the top part of the code):

                If Abs(CInt(NPCList(NPCIndex).Pos.X) - CInt(UserList(NPCList(NPCIndex).OwnerIndex).Pos.X)) < 4 Then
                    If Abs(CInt(NPCList(NPCIndex).Pos.Y) - CInt(UserList(NPCList(NPCIndex).OwnerIndex).Pos.Y)) < 4 Then
                        NPCList(NPCIndex).Counters.ActionDelay = timeGetTime + 500
                        Exit Sub
                    End If
                End If
 
                'So let's set the direction toward the player, and try to move
                tHeading = Server_FindDirection(NPCList(NPCIndex).Pos, UserList(NPCList(NPCIndex).OwnerIndex).Pos)
 
                If NPC_MoveChar(NPCIndex, tHeading) = 0 Then
                        'Couldn't move so look for alternate paths
                        Select Case tHeading
                            Case NORTH
                                t1 = NORTHEAST
                                t2 = NORTHWEST
                                t3 = EAST
                                t4 = WEST
                            Case EAST
                                t1 = NORTHEAST
                                t2 = SOUTHEAST
                                t3 = NORTH
                                t4 = SOUTH
                            Case SOUTH
                                t1 = SOUTHWEST
                                t2 = SOUTHEAST
                                t3 = WEST
                                t4 = EAST
                            Case WEST
                                t1 = SOUTHWEST
                                t2 = NORTHWEST
                                t3 = SOUTH
                                t4 = NORTH
                            Case NORTHEAST
                                t1 = NORTH
                                t2 = EAST
                                t3 = NORTHWEST
                                t4 = SOUTHEAST
                            Case SOUTHEAST
                                t1 = EAST
                                t2 = SOUTH
                                t3 = SOUTHWEST
                                t4 = NORTHEAST
                            Case SOUTHWEST
                                t1 = SOUTH
                                t2 = WEST
                                t3 = SOUTHEAST
                                t4 = NORTHWEST
                            Case NORTHWEST
                                t1 = WEST
                                t2 = NORTH
                                t3 = NORTHEAST
                                t4 = SOUTHWEST
                        End Select
    End Select
 
End Sub

That's pretty big, but simple. t1, t2, t3, and t4 represent the alternate directions we can move in. If you trace through that code a bit, you shouldn't have much trouble gathering what it does.

Now we're going to actually try and move in those 4 directions.

                        Case SOUTHWEST
                                t1 = SOUTH
                                t2 = WEST
                                t3 = SOUTHEAST
                                t4 = NORTHWEST
                            Case NORTHWEST
                                t1 = WEST
                                t2 = NORTH
                                t3 = NORTHEAST
                                t4 = SOUTHWEST
                        End Select
                        'Try the alternate movements
                        If NPC_MoveChar(NPCIndex, t1) = 0 Then
                            If NPC_MoveChar(NPCIndex, t2) = 0 Then
                                If NPC_MoveChar(NPCIndex, t3) = 0 Then
                                    If NPC_MoveChar(NPCIndex, t4) = 0 Then
                                        'We still can't move, so just wait
                                        NPCList(NPCIndex).Counters.ActionDelay = timeGetTime + 1000
                                    End If
                                End If
                            End If
                        End If
    End Select
 
End Sub

You can probably figure out what this does by now. It tries moving in each alternate direction, and if it still can't move, it will simply wait. We could implement some sort of advanced pathfinding algorithm to get around obstacles, but let's just say our NPC is dumb :P

                        Case NORTHWEST
                                t1 = WEST
                                t2 = NORTH
                                t3 = NORTHEAST
                                t4 = SOUTHWEST
                        End Select
                        'Try the alternate movements
                        If NPC_MoveChar(NPCIndex, t1) = 0 Then
                            If NPC_MoveChar(NPCIndex, t2) = 0 Then
                                If NPC_MoveChar(NPCIndex, t3) = 0 Then
                                    If NPC_MoveChar(NPCIndex, t4) = 0 Then
                                        'We still can't move, so just wait
                                        NPCList(NPCIndex).Counters.ActionDelay = timeGetTime + 1000
                                    End If
                                End If
                            End If
                        End If
                End If
                Exit Sub
 
            Else
                'Something was found, so now we get in position and attack!
                'Get the position of the NPC
                tPos = NPCList(i).Pos
    End Select
 
End Sub

What we've done now is add the trailing End If statement for If NPC_MoveChar(NPCIndex, tHeading) = 0 Then, and then aborted the sub. If we've gotten this far in the routine, we've either moved or not and there are no enemies, so we don't need to do anything else. If you're a bit confused, take a look at this updated pseudocode for our AI so far:


If there is no valid target in range, Then:
    If we're close enough to the user that we don't have to move, Then:
        We don't have to do anything, so abort the routine.
    End If

    Try to move directly towards the user. If we can't Then:
        Try to move in an alternate path. If we still can't, Then:
            We can't do anything else, so set our timer to wait and try again.
        End If
    End If

    We've either moved or not by now, and there's no target, so abort the routine.

Else
    We do have a target to attack, so get the target's position.
    

Now I'm going to post all the code for moving to the correct distance from the NPC. Don't worry, I'll explain it.

        Else
                'Something was found, so now we get in position and attack!
                'Get the position of the NPC
                tPos = NPCList(i).Pos
 
                'Run away and get in position if we're too close
                If Server_RectDistance(NPCList(NPCIndex).Pos.X, NPCList(NPCIndex).Pos.Y, tPos.X, tPos.Y, 3, 3) Then
                    tHeading = Server_FindDirection(NPCList(NPCIndex).Pos, tPos)
                    'We're going away from it so pick the opposite direction
                    Select Case tHeading
                        Case NORTH: tHeading = SOUTH
                        Case NORTHEAST: tHeading = SOUTHWEST
                        Case EAST: tHeading = WEST
                        Case SOUTHEAST: tHeading = NORTHWEST
                        Case SOUTH: tHeading = NORTH
                        Case SOUTHWEST: tHeading = NORTHEAST
                        Case WEST: tHeading = EAST
                        Case NORTHWEST: tHeading = SOUTHEAST
                    End Select
 
                    'Now let's attempt to move away
                    If NPC_MoveChar(NPCIndex, tHeading) = 0 Then
                        'Can't move there, so try alternate directions
                        Select Case tHeading
                            Case NORTH
                                t1 = NORTHEAST
                                t2 = NORTHWEST
                                t3 = EAST
                                t4 = WEST
                            Case EAST
                                t1 = NORTHEAST
                                t2 = SOUTHEAST
                                t3 = NORTH
                                t4 = SOUTH
                            Case SOUTH
                                t1 = SOUTHWEST
                                t2 = SOUTHEAST
                                t3 = WEST
                                t4 = EAST
                            Case WEST
                                t1 = SOUTHWEST
                                t2 = NORTHWEST
                                t3 = SOUTH
                                t4 = NORTH
                            Case NORTHEAST
                                t1 = NORTH
                                t2 = EAST
                                t3 = NORTHWEST
                                t4 = SOUTHEAST
                            Case SOUTHEAST
                                t1 = EAST
                                t2 = SOUTH
                                t3 = SOUTHWEST
                                t4 = NORTHEAST
                            Case SOUTHWEST
                                t1 = SOUTH
                                t2 = WEST
                                t3 = SOUTHEAST
                                t4 = NORTHWEST
                            Case NORTHWEST
                                t1 = WEST
                                t2 = NORTH
                                t3 = NORTHEAST
                                t4 = SOUTHWEST
                        End Select
                        'Try the alternate moves
                        If NPC_MoveChar(NPCIndex, t1) = 0 Then
                            If NPC_MoveChar(NPCIndex, t2) = 0 Then
                                If NPC_MoveChar(NPCIndex, t3) = 0 Then
                                    If NPC_MoveChar(NPCIndex, t4) = 0 Then
                                        'We still can't move (cornered! ack!) so attack!
                                        NPC_AI_AttackNPC NPCIndex, NPCList(NPCIndex).OwnerIndex
                                        NPCList(NPCIndex).Counters.ActionDelay = timeGetTime + NPCDelayFight
                                    End If
                                End If
                            End If
                        End If
                    End If
                    Exit Sub
                End If
    End Select
 
End Sub

Lotta code right there. However, if you're keen, you'll have noticed it looks almost like the code we used before (In fact, much of it IS the code we used before. I'm far too lazy to write it all out again. Nothing wrong with a little Ctrl+C action). Let's use some more pseudocode to explain what this is doing. Refer to this little snippet, and then back at the code, and see if you can piece together what the code is doing:

If there is no valid target in range, Then:
    If we're close enough to the user that we don't have to move, Then:
        We don't have to do anything, so abort the routine.
    End If

    Try to move directly towards the user. If we can't Then:
        Try to move in an alternate path. If we still can't, Then:
            We can't do anything else, so set our timer to wait and try again.
        End If
    End If

    We've either moved or not by now, and there's no target, so abort the routine.

Else
    We do have a target to attack, so get the target's position.
    If we're closer than 3 tiles to the target, Then:
        Set tHeading to the opposite direction of where the target is
        Try to move in that direction. If we can't Then:
            Try to move in an alternate path. If we still can't, Then:
                We can't move, but we have a target, so attack.
            End If
        End If
        We've either moved away or attacked, so abort the routine.
    End If

Making sense now? We're almost done, but we need some more code. What happens if we're already 3 tiles from the target? We want to go ahead and attack, so:

                        'Try the alternate moves
                        If NPC_MoveChar(NPCIndex, t1) = 0 Then
                            If NPC_MoveChar(NPCIndex, t2) = 0 Then
                                If NPC_MoveChar(NPCIndex, t3) = 0 Then
                                    If NPC_MoveChar(NPCIndex, t4) = 0 Then
                                        'We still can't move (cornered! ack!) so attack!
                                        NPC_AI_AttackNPC NPCIndex, NPCList(NPCIndex).OwnerIndex
                                        NPCList(NPCIndex).Counters.ActionDelay = timeGetTime + NPCDelayFight
                                    End If
                                End If
                            End If
                        End If
                    End If
                    Exit Sub
                End If
 
                'We're already in position, so just attack
                b = NPC_AI_AttackNPC(NPCIndex, NPCList(NPCIndex).OwnerIndex)
                If b Then
                    'Make sure the attack was successful before applying the delay
                    NPCList(NPCIndex).Counters.ActionDelay = timeGetTime + NPCDelayFight
                    Exit Sub
                End If
 
                'Nothing to do, so just wait and try again in a second
                NPCList(NPCIndex).Counters.ActionDelay = timeGetTime + 1000
 
            End If
 
    End Select
 
End Sub

By now, you probably have a good idea of what those last few lines are. For reference, NPC_AI_AttackNPC returns a 1 if the attack is successful and a 0 if it wasn't. The ActionDelay counter is there to make sure that the NPC attacks on-time - don't want him attacking too fast or too slow.

Believe it or not, that's the end! Here's the completed pseudocode for AI number 8:

If there is no valid target in range, Then:
    If we're close enough to the user that we don't have to move, Then:
        We don't have to do anything, so abort the routine.
    End If

    Try to move directly towards the user. If we can't Then:
        Try to move in an alternate path. If we still can't, Then:
            We can't do anything else, so set our timer to wait and try again.
        End If
    End If

    We've either moved or not by now, and there's no target, so abort the routine.

Else
    We do have a target to attack, so get the target's position.
    If we're closer than 3 tiles to the target, Then:
        Set tHeading to the opposite direction of where the target is
        Try to move in that direction. If we can't Then:
            Try to move in an alternate path. If we still can't, Then:
                We can't move, but we have a target, so attack.
            End If
        End If
        We've either moved away or attacked, so abort the routine.
    End If

    We're longer than 3 tiles away and we've gotten this far in the routine, so attack.
    If the attack was successful, Then:
         Update the attack timer.
    End If

    Update the NPC's AI timer to try again in one second.

And here's the completed AI code. Feel free to copy and paste into your own game, although if all you do is copy+paste it without reading the tutorial you won't learn much.

    '*** Summoned Ranged Attacker ***
        'Note: only attacks NPCs for now. Fix later kthx.
        Case 8
 
            'This routine is for summoned NPCs only!
            If NPCList(NPCIndex).OwnerIndex = 0 Then
                NPCList(NPCIndex).Counters.ActionDelay = timeGetTime + 5000
                Exit Sub
            End If
 
            'Look for a near-by NPC
            i = NPC_AI_ClosestNPC(NPCIndex, NPCList(NPCIndex).AttackRange \ 2, NPCList(NPCIndex).AttackRange \ 2, NPCList(NPCIndex).OwnerIndex, 1, 1)
 
            'Check to see if we could find something
            If i = 0 Then
                'There is nothing around to attack, so we want to tell it to move towards the user (we're following a bit behind, don't want to get too close to the action)
                If Abs(CInt(NPCList(NPCIndex).Pos.X) - CInt(UserList(NPCList(NPCIndex).OwnerIndex).Pos.X)) < 4 Then
                    If Abs(CInt(NPCList(NPCIndex).Pos.Y) - CInt(UserList(NPCList(NPCIndex).OwnerIndex).Pos.Y)) < 4 Then
                        NPCList(NPCIndex).Counters.ActionDelay = timeGetTime + 500
                        Exit Sub
                    End If
                End If
                'So let's set the direction toward the player, and try to move
                tHeading = Server_FindDirection(NPCList(NPCIndex).Pos, UserList(NPCList(NPCIndex).OwnerIndex).Pos)
 
                If NPC_MoveChar(NPCIndex, tHeading) = 0 Then
                        'Couldn't move so look for alternate paths
                        Select Case tHeading
                            Case NORTH
                                t1 = NORTHEAST
                                t2 = NORTHWEST
                                t3 = EAST
                                t4 = WEST
                            Case EAST
                                t1 = NORTHEAST
                                t2 = SOUTHEAST
                                t3 = NORTH
                                t4 = SOUTH
                            Case SOUTH
                                t1 = SOUTHWEST
                                t2 = SOUTHEAST
                                t3 = WEST
                                t4 = EAST
                            Case WEST
                                t1 = SOUTHWEST
                                t2 = NORTHWEST
                                t3 = SOUTH
                                t4 = NORTH
                            Case NORTHEAST
                                t1 = NORTH
                                t2 = EAST
                                t3 = NORTHWEST
                                t4 = SOUTHEAST
                            Case SOUTHEAST
                                t1 = EAST
                                t2 = SOUTH
                                t3 = SOUTHWEST
                                t4 = NORTHEAST
                            Case SOUTHWEST
                                t1 = SOUTH
                                t2 = WEST
                                t3 = SOUTHEAST
                                t4 = NORTHWEST
                            Case NORTHWEST
                                t1 = WEST
                                t2 = NORTH
                                t3 = NORTHEAST
                                t4 = SOUTHWEST
                        End Select
                        'Try the alternate movements
                        If NPC_MoveChar(NPCIndex, t1) = 0 Then
                            If NPC_MoveChar(NPCIndex, t2) = 0 Then
                                If NPC_MoveChar(NPCIndex, t3) = 0 Then
                                    If NPC_MoveChar(NPCIndex, t4) = 0 Then
                                        'We still can't move, so just wait
                                        '(we could implement some sort of advanced pathfinding, but let's just say our NPCs failed their IQ tests :P )
                                        NPCList(NPCIndex).Counters.ActionDelay = timeGetTime + 1000
                                    End If
                                End If
                            End If
                        End If
                End If
                Exit Sub
 
            Else
                'Something was found, so now we get in position and attack!
                'Get the position of the NPC
                tPos = NPCList(i).Pos
 
                'Run away and get in position if we're too close
                If Server_RectDistance(NPCList(NPCIndex).Pos.X, NPCList(NPCIndex).Pos.Y, tPos.X, tPos.Y, 3, 3) Then
                    tHeading = Server_FindDirection(NPCList(NPCIndex).Pos, tPos)
                    'We're going away from it so pick the opposite direction
                    Select Case tHeading
                        Case NORTH: tHeading = SOUTH
                        Case NORTHEAST: tHeading = SOUTHWEST
                        Case EAST: tHeading = WEST
                        Case SOUTHEAST: tHeading = NORTHWEST
                        Case SOUTH: tHeading = NORTH
                        Case SOUTHWEST: tHeading = NORTHEAST
                        Case WEST: tHeading = EAST
                        Case NORTHWEST: tHeading = SOUTHEAST
                    End Select
 
                    'Now let's attempt to move away
                    If NPC_MoveChar(NPCIndex, tHeading) = 0 Then
                        'Can't move there, so try alternate directions
                        Select Case tHeading
                            Case NORTH
                                t1 = NORTHEAST
                                t2 = NORTHWEST
                                t3 = EAST
                                t4 = WEST
                            Case EAST
                                t1 = NORTHEAST
                                t2 = SOUTHEAST
                                t3 = NORTH
                                t4 = SOUTH
                            Case SOUTH
                                t1 = SOUTHWEST
                                t2 = SOUTHEAST
                                t3 = WEST
                                t4 = EAST
                            Case WEST
                                t1 = SOUTHWEST
                                t2 = NORTHWEST
                                t3 = SOUTH
                                t4 = NORTH
                            Case NORTHEAST
                                t1 = NORTH
                                t2 = EAST
                                t3 = NORTHWEST
                                t4 = SOUTHEAST
                            Case SOUTHEAST
                                t1 = EAST
                                t2 = SOUTH
                                t3 = SOUTHWEST
                                t4 = NORTHEAST
                            Case SOUTHWEST
                                t1 = SOUTH
                                t2 = WEST
                                t3 = SOUTHEAST
                                t4 = NORTHWEST
                            Case NORTHWEST
                                t1 = WEST
                                t2 = NORTH
                                t3 = NORTHEAST
                                t4 = SOUTHWEST
                        End Select
                        'Try the alternate moves
                        If NPC_MoveChar(NPCIndex, t1) = 0 Then
                            If NPC_MoveChar(NPCIndex, t2) = 0 Then
                                If NPC_MoveChar(NPCIndex, t3) = 0 Then
                                    If NPC_MoveChar(NPCIndex, t4) = 0 Then
                                        'We still can't move (cornered! ack!) so attack!
                                        NPC_AI_AttackNPC NPCIndex, NPCList(NPCIndex).OwnerIndex
                                        NPCList(NPCIndex).Counters.ActionDelay = timeGetTime + NPCDelayFight
                                    End If
                                End If
                            End If
                        End If
                    End If
                    Exit Sub
                End If
 
                'We're already in position, so just attack
                b = NPC_AI_AttackNPC(NPCIndex, NPCList(NPCIndex).OwnerIndex)
                If b Then
                    'Make sure the attack was successful before applying the delay
                    NPCList(NPCIndex).Counters.ActionDelay = timeGetTime + NPCDelayFight
                    Exit Sub
                End If
 
                'Nothing to do, so just wait and try again in a second
                NPCList(NPCIndex).Counters.ActionDelay = timeGetTime + 1000
 
            End If
Personal tools