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.

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:

<vb> '*** Summoned Ranged Attacker ***

       Case 8


   End Select

End Sub</vb>

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:


<vb> '*** 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</vb>

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).

<vb> '*** 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</vb>

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:


<vb> '*** 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</vb>

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:

<vb> '*** 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</vb>

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.

<vb> '*** 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</vb>

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):

<vb> 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</vb>

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.

<vb> 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</vb>

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

<vb> 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</vb>

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.

<vb> 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</vb>

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:

<vb> '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</vb>

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.

<vb> '*** 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</vb>

Other AIs

Personal tools