Mirage Source

Free ORPG making software.
It is currently Thu Mar 28, 2024 11:26 am

All times are UTC




Post new topic Reply to topic  [ 52 posts ]  Go to page 1, 2, 3  Next
Author Message
PostPosted: Fri Jul 20, 2007 6:34 am 
Offline
Pro
User avatar

Joined: Mon May 29, 2006 3:26 pm
Posts: 493
Location: São Paulo, Brasil
Google Talk: blackagesbr@gmail.com
Difficulty: 5/5
Need to understand!


19/07/2007
I strongly suggest that it you are going to try to make this tutorial, READ ALL THE THINGS AT THE LINKS INSIDE THIS TUTORIAL!!!
AND BACKUP YOUR SOURCE!!!!
Well, initially, I'd like to thank William for this opportunity and I think this is going to be a great tutorial. The idea of this tutorial is to improve the AI(Artificial Intelligence) of your Mirage Source game. The actual AI is very dumb and it can easily miss the target, not going through the correct/best path. What I did was replace the hole AI with a better code. Let's examine the actual code(that's inside 2 loops, the main is looping the maps and the second is for each MapNpc):

Code:
                ' /////////////////////////////////////////////
                ' // This is used for NPC walking/targetting //
                ' /////////////////////////////////////////////
                ' Make sure theres a npc with the map
                If Map(y).Npc(x) > 0 And MapNpc(y, x).Num > 0 Then
                    Target = MapNpc(y, x).Target
                   
                    ' Check to see if its time for the npc to walk
                    If Npc(NpcNum).Behavior <> NPC_BEHAVIOR_SHOPKEEPER Then
                        ' Check to see if we are following a player or not
                        If Target > 0 Then
                            ' Check if the player is even playing, if so follow'm
                            If IsPlaying(Target) And GetPlayerMap(Target) = y Then
                                DidWalk = False
                               
                                i = Int(Rnd * 5)

First it checks if theres really a npc at that map, if this npc is not a shop keeper, if this npc actually has a target and if this target(players) is online and at the same map this npc is. Then it randomizes a number from 0 to 4.
Code:
                                ' Lets move the npc
                                Select Case i
                                    Case 0
                                        ' Up
                                        If MapNpc(y, x).y > GetPlayerY(Target) And DidWalk = False Then
                                            If CanNpcMove(y, x, DIR_UP) Then
                                                Call NpcMove(y, x, DIR_UP, MOVING_WALKING)
                                                DidWalk = True
                                            End If
                                        End If
                                        ' Down
                                        If MapNpc(y, x).y < GetPlayerY(Target) And DidWalk = False Then
                                            If CanNpcMove(y, x, DIR_DOWN) Then
                                                Call NpcMove(y, x, DIR_DOWN, MOVING_WALKING)
                                                DidWalk = True
                                            End If
                                        End If
                                        ' Left
                                        If MapNpc(y, x).x > GetPlayerX(Target) And DidWalk = False Then
                                            If CanNpcMove(y, x, DIR_LEFT) Then
                                                Call NpcMove(y, x, DIR_LEFT, MOVING_WALKING)
                                                DidWalk = True
                                            End If
                                        End If
                                        ' Right
                                        If MapNpc(y, x).x < GetPlayerX(Target) And DidWalk = False Then
                                            If CanNpcMove(y, x, DIR_RIGHT) Then
                                                Call NpcMove(y, x, DIR_RIGHT, MOVING_WALKING)
                                                DidWalk = True
                                            End If
                                        End If
                                   
                                    Case 1
                                        ' Right
                                        If MapNpc(y, x).x < GetPlayerX(Target) And DidWalk = False Then
                                            If CanNpcMove(y, x, DIR_RIGHT) Then
                                                Call NpcMove(y, x, DIR_RIGHT, MOVING_WALKING)
                                                DidWalk = True
                                            End If
                                        End If
                                        ' Left
                                        If MapNpc(y, x).x > GetPlayerX(Target) And DidWalk = False Then
                                            If CanNpcMove(y, x, DIR_LEFT) Then
                                                Call NpcMove(y, x, DIR_LEFT, MOVING_WALKING)
                                                DidWalk = True
                                            End If
                                        End If
                                        ' Down
                                        If MapNpc(y, x).y < GetPlayerY(Target) And DidWalk = False Then
                                            If CanNpcMove(y, x, DIR_DOWN) Then
                                                Call NpcMove(y, x, DIR_DOWN, MOVING_WALKING)
                                                DidWalk = True
                                            End If
                                        End If
                                        ' Up
                                        If MapNpc(y, x).y > GetPlayerY(Target) And DidWalk = False Then
                                            If CanNpcMove(y, x, DIR_UP) Then
                                                Call NpcMove(y, x, DIR_UP, MOVING_WALKING)
                                                DidWalk = True
                                            End If
                                        End If
                                       
                                    Case 2
                                        ' Down
                                        If MapNpc(y, x).y < GetPlayerY(Target) And DidWalk = False Then
                                            If CanNpcMove(y, x, DIR_DOWN) Then
                                                Call NpcMove(y, x, DIR_DOWN, MOVING_WALKING)
                                                DidWalk = True
                                            End If
                                        End If
                                        ' Up
                                        If MapNpc(y, x).y > GetPlayerY(Target) And DidWalk = False Then
                                            If CanNpcMove(y, x, DIR_UP) Then
                                                Call NpcMove(y, x, DIR_UP, MOVING_WALKING)
                                                DidWalk = True
                                            End If
                                        End If
                                        ' Right
                                        If MapNpc(y, x).x < GetPlayerX(Target) And DidWalk = False Then
                                            If CanNpcMove(y, x, DIR_RIGHT) Then
                                                Call NpcMove(y, x, DIR_RIGHT, MOVING_WALKING)
                                                DidWalk = True
                                            End If
                                        End If
                                        ' Left
                                        If MapNpc(y, x).x > GetPlayerX(Target) And DidWalk = False Then
                                            If CanNpcMove(y, x, DIR_LEFT) Then
                                                Call NpcMove(y, x, DIR_LEFT, MOVING_WALKING)
                                                DidWalk = True
                                            End If
                                        End If
                                   
                                    Case 3
                                        ' Left
                                        If MapNpc(y, x).x > GetPlayerX(Target) And DidWalk = False Then
                                            If CanNpcMove(y, x, DIR_LEFT) Then
                                                Call NpcMove(y, x, DIR_LEFT, MOVING_WALKING)
                                                DidWalk = True
                                            End If
                                        End If
                                        ' Right
                                        If MapNpc(y, x).x < GetPlayerX(Target) And DidWalk = False Then
                                            If CanNpcMove(y, x, DIR_RIGHT) Then
                                                Call NpcMove(y, x, DIR_RIGHT, MOVING_WALKING)
                                                DidWalk = True
                                            End If
                                        End If
                                        ' Up
                                        If MapNpc(y, x).y > GetPlayerY(Target) And DidWalk = False Then
                                            If CanNpcMove(y, x, DIR_UP) Then
                                                Call NpcMove(y, x, DIR_UP, MOVING_WALKING)
                                                DidWalk = True
                                            End If
                                        End If
                                        ' Down
                                        If MapNpc(y, x).y < GetPlayerY(Target) And DidWalk = False Then
                                            If CanNpcMove(y, x, DIR_DOWN) Then
                                                Call NpcMove(y, x, DIR_DOWN, MOVING_WALKING)
                                                DidWalk = True
                                            End If
                                        End If
                                End Select
                               

This number represents the direction(0 up, 1 right, 2 down, 3 left) that the npc will try to move first. If there is nothing on the map, that's a good way to move because you will randomly walk close to him and not all th way right(ex) and then all the way up, directly to the player.
Code:
                           
                                ' Check if we can't move and if player is behind something and if we can just switch dirs
                                If Not DidWalk Then
                                    If MapNpc(y, x).x - 1 = GetPlayerX(Target) And MapNpc(y, x).y = GetPlayerY(Target) Then
                                        If MapNpc(y, x).Dir <> DIR_LEFT Then
                                            Call NpcDir(y, x, DIR_LEFT)
                                        End If
                                        DidWalk = True
                                    End If
                                    If MapNpc(y, x).x + 1 = GetPlayerX(Target) And MapNpc(y, x).y = GetPlayerY(Target) Then
                                        If MapNpc(y, x).Dir <> DIR_RIGHT Then
                                            Call NpcDir(y, x, DIR_RIGHT)
                                        End If
                                        DidWalk = True
                                    End If
                                    If MapNpc(y, x).x = GetPlayerX(Target) And MapNpc(y, x).y - 1 = GetPlayerY(Target) Then
                                        If MapNpc(y, x).Dir <> DIR_UP Then
                                            Call NpcDir(y, x, DIR_UP)
                                        End If
                                        DidWalk = True
                                    End If
                                    If MapNpc(y, x).x = GetPlayerX(Target) And MapNpc(y, x).y + 1 = GetPlayerY(Target) Then
                                        If MapNpc(y, x).Dir <> DIR_DOWN Then
                                            Call NpcDir(y, x, DIR_DOWN)
                                        End If
                                        DidWalk = True
                                    End If
                                   
                                    ' We could not move so player must be behind something, walk randomly.
                                    If Not DidWalk Then
                                        i = Int(Rnd * 2)
                                        If i = 1 Then
                                            i = Int(Rnd * 4)
                                            If CanNpcMove(y, x, i) Then
                                                Call NpcMove(y, x, i, MOVING_WALKING)
                                            End If
                                        End If
                                    End If
                                End If

If you couldn't move that's probably something on the way(the player it self or something else), and this algorithm can't pass thru it, so it will just switch the npc's direction so it will be looking at the player. If even with that, the npc didn't move so it stills away from the player but it can't go closer to it, and it will just randomly walk any direction or just not move at all.
Code:
                            Else
                                MapNpc(y, x).Target = 0
                            End If
                        Else
                            i = Int(Rnd * 4)
                            If i = 1 Then
                                i = Int(Rnd * 4)
                                If CanNpcMove(y, x, i) Then
                                    Call NpcMove(y, x, i, MOVING_WALKING)
                                End If
                            End If

If the npc has no target then it will just randomly make a happy move to anywhere.
Code:
                        End If
                    End If
                End If


Well, this code works, but I really didn't like it, so I deleted every thing and made something all new, able to find the perfect path between the player and the npc, so the npc can make any puzzle and things like this. Actually in my game, this algorithm changed a bit because I'm using my scrolling maps system, but I have a backup here and I'll show you guys how I did it and how it works. It IS quite hard to understand because it uses a few theories from college and most of them are not easy to understand. I'll use a thing named graph, and this graph is quite good think. It is made of vertices and edges. Let's imagine each vertex as a tile and each edge as a possible bridge between each tile.
Image
This is a Screen Shot I've taken from a simple MSE map attached with this little balls and lines connecting the tiles that you can move from one to an other. That's basically a graph... a little bit simplified.
(take a look at http://en.wikipedia.org/wiki/Graph_theory and http://en.wikipedia.org/wiki/Graph_%28data_structure%29)

20/07/2007
If you read all the links and didn't understand anything or you are still missing something on your mind, READ IT AGAIN or ask for someone's help. Don't go further if you don't understand the things before this!
Well, now I'm going to talk about this graph and how the heck this is going to help us out with the AI.
What I did was showing you guys how this graph is represented on a visual world, but there is no such thing in programing so we need to store this data somewhere, somehow.
For this, I numerated each vertex and made a big matrix that holds the information of the connections. That's named adjacency matrix(http://en.wikipedia.org/wiki/Graph_%28d ... esentation). It's like this: we create a matrix NxN(N being the number of vertices we hold, in our case, (MAX_MAPX + 1) * (MAX_MAPY + 1) and fill it with zeros. Then we check if we can move directly from tile X to tile Y(X and Y is the tile number, the enumerated tiles), we just make matrix(X, Y) = 1. So if we look at the matrix and there is a 1 at position (3, 8), it means that we can move from tile 3 to tile 8. But we want our npc to move both ways so we make the same thing but from Y to X, like this matrix(Y, X) = 1.
Considering we already have this adjacency matrix filled with our data, we need now to find the shortest path from point A to point B and that's where the magic is, the BFS algorithm, Breadth-First Search algorithm(http://en.wikipedia.org/wiki/Breadth-first_search).
This is where the important thing happens, and the hard part too... This algorithm searches for the shortest path between vertex A and vertex B. By doing this, it loops thru all the vertices, starting from the end. So it's just like we do to find the correct path in a puzzle game. Instead of starting from the real start, we start from the end and tries to find the path, at least I do that xD. The BFS algorithm is quite easy to implement and there are not much problems, so I'll start to do it now. Focus on this because it's all the magic happening.

First, we need our adjacency matrix declared, let's do that inside modGeneral header.
Code:
' Used for AI
Public NV As Integer ' Number of Vertices
Public Mat() As Byte ' Our Adjacency Matrix
Now we need to initialize this matrix, and we'll do it at InitServer Sub.
Under
Code:
Call SpawnAllMapNpcs
Add this:
Code:
    NV = (MAX_MAPX + 1) * (MAX_MAPY + 1) - 1
    ReDim Mat(0 To NV, 0 To NV) As Byte
Now that it's all there, we need to remove the old AI, almost all of it.
Inside GameAI Sub, remove all this code:
Code:
                                i = Int(Rnd * 5)
                               
                                ' Lets move the npc
                                Select Case i
                                    Case 0
                                        ' Up
                                        If MapNpc(y, x).y > GetPlayerY(Target) And DidWalk = False Then
                                            If CanNpcMove(y, x, DIR_UP) Then
                                                Call NpcMove(y, x, DIR_UP, MOVING_WALKING)
                                                DidWalk = True
                                            End If
                                        End If
                                        ' Down
                                        If MapNpc(y, x).y < GetPlayerY(Target) And DidWalk = False Then
                                            If CanNpcMove(y, x, DIR_DOWN) Then
                                                Call NpcMove(y, x, DIR_DOWN, MOVING_WALKING)
                                                DidWalk = True
                                            End If
                                        End If
                                        ' Left
                                        If MapNpc(y, x).x > GetPlayerX(Target) And DidWalk = False Then
                                            If CanNpcMove(y, x, DIR_LEFT) Then
                                                Call NpcMove(y, x, DIR_LEFT, MOVING_WALKING)
                                                DidWalk = True
                                            End If
                                        End If
                                        ' Right
                                        If MapNpc(y, x).x < GetPlayerX(Target) And DidWalk = False Then
                                            If CanNpcMove(y, x, DIR_RIGHT) Then
                                                Call NpcMove(y, x, DIR_RIGHT, MOVING_WALKING)
                                                DidWalk = True
                                            End If
                                        End If
                                   
                                    Case 1
                                        ' Right
                                        If MapNpc(y, x).x < GetPlayerX(Target) And DidWalk = False Then
                                            If CanNpcMove(y, x, DIR_RIGHT) Then
                                                Call NpcMove(y, x, DIR_RIGHT, MOVING_WALKING)
                                                DidWalk = True
                                            End If
                                        End If
                                        ' Left
                                        If MapNpc(y, x).x > GetPlayerX(Target) And DidWalk = False Then
                                            If CanNpcMove(y, x, DIR_LEFT) Then
                                                Call NpcMove(y, x, DIR_LEFT, MOVING_WALKING)
                                                DidWalk = True
                                            End If
                                        End If
                                        ' Down
                                        If MapNpc(y, x).y < GetPlayerY(Target) And DidWalk = False Then
                                            If CanNpcMove(y, x, DIR_DOWN) Then
                                                Call NpcMove(y, x, DIR_DOWN, MOVING_WALKING)
                                                DidWalk = True
                                            End If
                                        End If
                                        ' Up
                                        If MapNpc(y, x).y > GetPlayerY(Target) And DidWalk = False Then
                                            If CanNpcMove(y, x, DIR_UP) Then
                                                Call NpcMove(y, x, DIR_UP, MOVING_WALKING)
                                                DidWalk = True
                                            End If
                                        End If
                                       
                                    Case 2
                                        ' Down
                                        If MapNpc(y, x).y < GetPlayerY(Target) And DidWalk = False Then
                                            If CanNpcMove(y, x, DIR_DOWN) Then
                                                Call NpcMove(y, x, DIR_DOWN, MOVING_WALKING)
                                                DidWalk = True
                                            End If
                                        End If
                                        ' Up
                                        If MapNpc(y, x).y > GetPlayerY(Target) And DidWalk = False Then
                                            If CanNpcMove(y, x, DIR_UP) Then
                                                Call NpcMove(y, x, DIR_UP, MOVING_WALKING)
                                                DidWalk = True
                                            End If
                                        End If
                                        ' Right
                                        If MapNpc(y, x).x < GetPlayerX(Target) And DidWalk = False Then
                                            If CanNpcMove(y, x, DIR_RIGHT) Then
                                                Call NpcMove(y, x, DIR_RIGHT, MOVING_WALKING)
                                                DidWalk = True
                                            End If
                                        End If
                                        ' Left
                                        If MapNpc(y, x).x > GetPlayerX(Target) And DidWalk = False Then
                                            If CanNpcMove(y, x, DIR_LEFT) Then
                                                Call NpcMove(y, x, DIR_LEFT, MOVING_WALKING)
                                                DidWalk = True
                                            End If
                                        End If
                                   
                                    Case 3
                                        ' Left
                                        If MapNpc(y, x).x > GetPlayerX(Target) And DidWalk = False Then
                                            If CanNpcMove(y, x, DIR_LEFT) Then
                                                Call NpcMove(y, x, DIR_LEFT, MOVING_WALKING)
                                                DidWalk = True
                                            End If
                                        End If
                                        ' Right
                                        If MapNpc(y, x).x < GetPlayerX(Target) And DidWalk = False Then
                                            If CanNpcMove(y, x, DIR_RIGHT) Then
                                                Call NpcMove(y, x, DIR_RIGHT, MOVING_WALKING)
                                                DidWalk = True
                                            End If
                                        End If
                                        ' Up
                                        If MapNpc(y, x).y > GetPlayerY(Target) And DidWalk = False Then
                                            If CanNpcMove(y, x, DIR_UP) Then
                                                Call NpcMove(y, x, DIR_UP, MOVING_WALKING)
                                                DidWalk = True
                                            End If
                                        End If
                                        ' Down
                                        If MapNpc(y, x).y < GetPlayerY(Target) And DidWalk = False Then
                                            If CanNpcMove(y, x, DIR_DOWN) Then
                                                Call NpcMove(y, x, DIR_DOWN, MOVING_WALKING)
                                                DidWalk = True
                                            End If
                                        End If
                                End Select
It is inside this If:
Code:
                ' /////////////////////////////////////////////
                ' // This is used for NPC walking/targetting //
                ' /////////////////////////////////////////////
                ' Make sure theres a npc with the map
                If Map(Y).Npc(X) > 0 And MapNpc(Y, X).num > 0 Then
                    Target = MapNpc(Y, X).Target
                   
                    ' Check to see if its time for the npc to walk
                    If Npc(NpcNum).Behavior <> NPC_BEHAVIOR_SHOPKEEPER Then
                        ' Check to see if we are following a player or not
                        If Target > 0 Then
                            ' Check if the player is even playing, if so follow'm
                            If IsPlaying(Target) And GetPlayerMap(Target) = Y Then
                                DidWalk = False
I mean the most inside scope, the last one. Now we can start adding our AI. You'll probably have something like this:
Code:
                ' /////////////////////////////////////////////
                ' // This is used for NPC walking/targetting //
                ' /////////////////////////////////////////////
                ' Make sure theres a npc with the map
                If Map(y).Npc(x) > 0 And MapNpc(y, x).Num > 0 Then
                    Target = MapNpc(y, x).Target
                   
                    ' Check to see if its time for the npc to walk
                    If Npc(NpcNum).Behavior <> NPC_BEHAVIOR_SHOPKEEPER Then
                        ' Check to see if we are following a player or not
                        If Target > 0 Then
                            ' Check if the player is even playing, if so follow'm
                            If IsPlaying(Target) And GetPlayerMap(Target) = y Then
                                DidWalk = False
                               
                               
                                ' Check if we can't move and if player is behind something and if we can just switch dirs
                                If Not DidWalk Then
                                    If MapNpc(y, x).x - 1 = GetPlayerX(Target) And MapNpc(y, x).y = GetPlayerY(Target) Then
                                        If MapNpc(y, x).Dir <> DIR_LEFT Then
                                            Call NpcDir(y, x, DIR_LEFT)
                                        End If
                                        DidWalk = True
                                    End If
                                    If MapNpc(y, x).x + 1 = GetPlayerX(Target) And MapNpc(y, x).y = GetPlayerY(Target) Then
                                        If MapNpc(y, x).Dir <> DIR_RIGHT Then
                                            Call NpcDir(y, x, DIR_RIGHT)
                                        End If
                                        DidWalk = True
                                    End If
                                    If MapNpc(y, x).x = GetPlayerX(Target) And MapNpc(y, x).y - 1 = GetPlayerY(Target) Then
                                        If MapNpc(y, x).Dir <> DIR_UP Then
                                            Call NpcDir(y, x, DIR_UP)
                                        End If
                                        DidWalk = True
                                    End If
                                    If MapNpc(y, x).x = GetPlayerX(Target) And MapNpc(y, x).y + 1 = GetPlayerY(Target) Then
                                        If MapNpc(y, x).Dir <> DIR_DOWN Then
                                            Call NpcDir(y, x, DIR_DOWN)
                                        End If
                                        DidWalk = True
                                    End If
                                   
                                    ' We could not move so player must be behind something, walk randomly.
                                    If Not DidWalk Then
                                        i = Int(Rnd * 2)
                                        If i = 1 Then
                                            i = Int(Rnd * 4)
                                            If CanNpcMove(y, x, i) Then
                                                Call NpcMove(y, x, i, MOVING_WALKING)
                                            End If
                                        End If
                                    End If
                                End If
                            Else
                                MapNpc(y, x).Target = 0
                            End If
                        Else
                            i = Int(Rnd * 4)
                            If i = 1 Then
                                i = Int(Rnd * 4)
                                If CanNpcMove(y, x, i) Then
                                    Call NpcMove(y, x, i, MOVING_WALKING)
                                End If
                            End If
                        End If
                    End If
                End If

Now, right after
Code:
DidWalk = False
add this:
Code:
                                CloseToPlayer = False
                                If (GetPlayerY(Target) + 1 = MapNpc(y, x).y) And (GetPlayerX(Target) = MapNpc(y, x).x) Then
                                    CloseToPlayer = True
                                Else
                                    If (GetPlayerY(Target) - 1 = MapNpc(y, x).y) And (GetPlayerX(Target) = MapNpc(y, x).x) Then
                                        CloseToPlayer = True
                                    Else
                                        If (GetPlayerY(Target) = MapNpc(y, x).y) And (GetPlayerX(Target) + 1 = MapNpc(y, x).x) Then
                                            CloseToPlayer = True
                                        Else
                                            If (GetPlayerY(Target) = MapNpc(y, x).y) And (GetPlayerX(Target) - 1 = MapNpc(y, x).x) Then
                                                CloseToPlayer = True
                                            End If
                                        End If
                                    End If
                                End If

Don't forget to declare CloseToPlayer at GameAI headers, like this:
Code:
Dim CloseToPlayer As Boolean
This sequence of If and Else is there only to make sure the npc is not already at the side of the player.
Now add an If to make sure the npc is not close to the player, like this:
Code:
                                If Not CloseToPlayer Then
                                   
                                End If
Now I'll show you how the adjacency matrix really is on a visual mode. I'll use the same image as I did before but I'll finish it.
Image
Here it is. Took me a while of time to make this, with all the numbers xD
Well, now we can perfectly see that the npc(the pink thing) need to go from vertex 153 to vertex 51(the player).
If we where using the old AI it maybe(maybe) could go to vertex 53 but it's random, so it could also go only to 57 and stay there xD. The AI we are making here will literally be a genius. It will find the best path from vertex 153 to 51 and save this path into a vector. A vector? Wait, we didn't declared this vector! We'll need it! So come back to modGeneral's header and add this 3 variables
Code:
Public Marked() As Byte
Public PathLine() As Integer
Public Path() As Integer
We also need to initialize this 3 vectors, so go back to InitServer and under
Code:
    ReDim Mat(0 To NV, 0 To NV) As Byte
Add this:
Code:
    ReDim Marked(0 To NV) As Byte
    ReDim PathLine(0 To NV) As Integer
    ReDim Path(0 To NV) As Integer
Now we have the vector, actually 3 vectors: Marked, PathLine and Path.
Marked vector will store the information about the vertices we've already walked thru(a correct tile, that's part of the algorithm), PathLine will also store information that's part of the algorithm, we always add the tile we found(remember, destiny to origin(B->A)) to the PathLine. When the PathLine(o) is filed with information, doesn't mather when, the first time this is done, then we have the best path(it means we have it all).
That's complicated, it's how the algorithm works.
Now we need to store the information about where we are and where we want to go. For this we create 2 new variables, "o"(Origin) and "d"(Destiny). Create them at the top of GameAI Sub:
Code:
Dim o As Long
Dim d As Long
Now inside that If(If not close to player then) add this:
Code:
                                    o = MapNpc(Y, X).Y * (MAX_MAPX + 1) + MapNpc(Y, X).X
                                    d = GetPlayerY(Target) * (MAX_MAPX + 1) + GetPlayerX(Target)
Our origin is the npcs position, but we need the vertex number that represent that tile, for this we use a little math with mapnpcs x and y together with the map's size. The same for the Destiny, but now we use the player's coordinates. Now we know from which vertex are leaving and the vertex we want to go. Now let's initialize the 3 vectors we are going to use:
Code:
                                    For i = 0 To NV
                                        Marked(i) = 0
                                        PathLine(i) = -1
                                        Path(i) = -1
                                    Next i
We use 0 to Marked and -1 for PathLine and Path because they will store the vertices numbers, 0 to NV, so we use -1. Now that all the Vectors are OK, we need one more thing to really find the path, we still need to fill our adjacency matrix with the tile's block, player's position, npc's position and everything that may block the npc's way. That's a lot of code, here is a little part of it:
Code:
                                    For i = 0 To NV
                                        VY = Int(i / (MAX_MAPX + 1))
                                        VX = i Mod (MAX_MAPX + 1)
                                       
                                        If VX >= 0 And VX < MAX_MAPX Then Mat(i, i + 1) = 1
                                        If VX > 0 And VX <= MAX_MAPX Then Mat(i, i - 1) = 1
                                        If VY >= 0 And VY < MAX_MAPY Then Mat(i, i + MAX_MAPX + 1) = 1
                                        If VY > 0 And VY <= MAX_MAPY Then Mat(i, i - MAX_MAPX - 1) = 1
                                    Next i
This will link all the adjacent tiles and store this connections at the adjacency matrix. We created 2 new variables, VX and VY. Declare them at the header of GameAI Sub, like this:
Code:
Dim VX As Integer
Dim VY As Integer
Now we need to check the map's information and look for any blocked, npcavoid, warp or locked key tile type and make sure there is no tile with a connection with that tile on our adjacency matrix. The same need to be done for other players(not our target) or other mapnpcs(not the attacker). That's a lot of code and I'll re-make that soon to speed it up a little bit, this is not the final tutorial.
Code:
                                    For i = 0 To NV
                                        VY = Int(i / (MAX_MAPX + 1))
                                        VX = i Mod (MAX_MAPX + 1)
                                        If (Map(y).Tile(VX, VY).Type = TILE_TYPE_BLOCKED Or Map(y).Tile(VX, VY).Type = TILE_TYPE_NPCAVOID Or Map(y).Tile(VX, VY).Type = TILE_TYPE_WARP Or (Map(y).Tile(VX, VY).Type = TILE_TYPE_KEY And TempTile(y).DoorOpen(VX, VY) = NO)) Then
                                            For J = 0 To NV
                                                Mat(J, i) = 0
                                                Mat(i, J) = 0
                                            Next J
                                        End If
                                        For J = 1 To MAX_PLAYERS
                                            If IsPlaying(J) Then
                                                If GetPlayerMap(J) = y Then
                                                    If GetPlayerX(J) = VX And GetPlayerY(J) = VY And J <> Target Then
                                                        For K = 0 To NV
                                                            Mat(i, K) = 0
                                                            Mat(K, i) = 0
                                                        Next K
                                                    End If
                                                End If
                                            End If
                                        Next J
                                        For J = 1 To MAX_MAP_NPCS
                                            If Map(y).Npc(J) > 0 And MapNpc(y, J).Num > 0 Then
                                                If MapNpc(y, J).x = VX And MapNpc(y, J).y = VY And J <> x Then
                                                    For K = 0 To NV
                                                        Mat(i, K) = 0
                                                        Mat(K, i) = 0
                                                    Next K
                                                End If
                                            End If
                                        Next J
                                    Next i
Great! But there are still 2 variables declaration needed, J and K. Declare them at GameAI Sub headers, like this:
Code:
Dim J As Integer
Dim K As Integer


OK, now it's time to run your game! Just do it, run and make sure you didn't miss anything. You'll see that the npc looks quite... stupid, that's because we did nothing but initialize the variables, we've found no path yet, and it's always going to that last part of the code, where the npc walks randomly, for no reason(
Code:
' Check if we can't move and if player is behind something and if we can just switch dirs
). That's OK for now. Close the client and the Server. Now here is where the magic happens! This is a lot of code. That's 140 lines of code(with a few comments, really few), and that's the reason I didn't released this tutorial before, I've spent a lot of time on it and I didn't wanted to release that before now. It's hard to understand this part of the code, so make sure you understand ALL OF IT until now. I really mean ALL!!!

21/07/2007
Now we are going to make the magic happens! The search happens inside a while so we need a flag to warn the while to exit the repeating process, a flag to exit the while. We also need two more variables, Start and Finish that stores the information about the first and the last path tile we are at the moment. So declare them all at the header of GameAI Sub, like this:
Code:
Dim Flag As Byte
Dim Start As Long
Dim Finish As Long
I like using byte flags and not booleans, if you want just change it... Now, right after the last thing we did, except for the declaration of the variables, add this:
Code:
                                    Flag = 0
                                    PathLine(0) = d
                                    Start = 0
                                    Finish = 1
This will make the flag false and initialize our algorithm so we can loop. The "PathLine(0) = d" will make us start our search from the Destiny. PathLine is from 0 to NV so it Starts on 0 and Finishes at 1(right now, because we are just initializing). Now, just for preventing bugs, add this if:
Code:
                                    If o <> d Then
                                       
                                    End If
Now, inside this If we are going to start the loop process to find the path. Add this:
Code:
                                        While (PathLine(Start) <> -1 And Flag = 0)
                                           
                                        Wend
Now inside this While, we need to loop thru all the other vertices and see which has a connection to the one that is on the start of the path line. This algorithm works like this, it will calculate the best path from all the vertices that are connected to the destiny(just by looking for them), then, it marks the destiny(so you won't check it again) and now it will find the best path to all the vertices connected to this vertices connected to the destiny(just by looking for them), and it keeps doing that, until it finds the origin. When it does, the path it finds is the best to the origin because it's the first it finds and you are searching one by one, each level one by one. This is done like this:
Code:
                                            For i = 0 To NV
                                                If Mat(PathLine(Start), i) = 1 And PathLine(Start) <> i And Marked(i) = 0 And Flag = 0 Then
                                                    Path(i) = PathLine(Start)
                                                    PathLine(Finish) = i
                                                    Marked(i) = 1
                                                    Finish = Finish + 1
                                                    If PathLine(Finish - 1) = o Then
                                                        Flag = 1
                                                    End If
                                                End If
                                                If i = NV Then
                                                    Marked(PathLine(Start)) = 1
                                                    PathLine(Start) = -1
                                                    Start = Start + 1
                                                End If
                                            Next i
This code is old and I'll post the perfect one soon. Now you have the best path from the origin to the destiny. Next I'll post the finish of this tutorial.

Continuing...
Once again, if you are not understanding what is happening here, RE-MAKE THE TUTORIAL!!!
Now, we can keep going...
We need now a way to make the computer understands that if we need to move from vertex x to x+1 we need to go right and if we want to move from vertex x to x+max_mapx+1 we need to go down, etc... That's quite simple if you understand what you are doing. The AI may not found a path, but only if really there is no path to the player. We need to check this, and for this we use the Flag variable, if it's 1 then we found our path, else we didn't and just walk randomly. Use this If statement :
Code:
                                                                              If Flag = 1 Then
GREAT, now we just need to actually move! Now is the place we found our coordinates, x and y. Use this code inside that If:
Code:
                                            VY = Int(Path(o) / (MAX_MAPX + 1))
                                            VX = Path(o) Mod (MAX_MAPX + 1)
                                            DoEvents
Now only a few If statements and we are finish with this tutorial! Here they are:
Code:
                                            If MapNpc(y, x).y > VY Then
                                                If CanNpcMove(y, x, DIR_UP) Then
                                                    Call NpcMove(y, x, DIR_UP, MOVING_WALKING)
                                                    DidWalk = True
                                                End If
                                            ElseIf MapNpc(y, x).y < VY Then
                                                ' Down
                                                If CanNpcMove(y, x, DIR_DOWN) Then
                                                    Call NpcMove(y, x, DIR_DOWN, MOVING_WALKING)
                                                    DidWalk = True
                                                End If
                                            ElseIf MapNpc(y, x).x > VX Then
                                                ' Left
                                                If CanNpcMove(y, x, DIR_LEFT) Then
                                                    Call NpcMove(y, x, DIR_LEFT, MOVING_WALKING)
                                                    DidWalk = True
                                                End If
                                            ElseIf MapNpc(y, x).x < VX Then
                                                ' Right
                                                If CanNpcMove(y, x, DIR_RIGHT) Then
                                                    Call NpcMove(y, x, DIR_RIGHT, MOVING_WALKING)
                                                    DidWalk = True
                                                End If
                                            End If
DONE! Now it should work, run your game and take a look at the AI. Make a simple puzzle at the map and add a attack on sight npc, with a big range of sight. Just great, it should be working by now! But there really are a lot of improvements that needs to be done, and I really mean it. If you use this code right now, we won't be able to play, I mean, you will, but with a lot of players and a lot of npcs, just impossible, the npcs will have too much lag...
For fixing this, we will improve a LOT this code. what we are going to do is replace the:
Code:
For i = 0 To NV
The, one inside the While and a few more. Since we know how the graph format is, a very specific graph, we can change a lot of things. We know that each vertex has max of 4 connections, never more, so we need to change all this 192(in vanilla MS) loops and replace them with only 4 ;) Much less processing. For this, lets at the top of our AI system code, and take a look at this part of the code :
Code:
For J = 0 To NV
    Mat(J, i) = 0
    Mat(i, J) = 0
Next J
Replace the:
Code:
Mat(J, i) = 0
Mat(i, J) = 0
With this:
Code:
                                            If VX >= 0 And VX < MAX_MAPX Then Mat(i, i + 1) = 0
                                            If VX > 0 And VX <= MAX_MAPX Then Mat(i, i - 1) = 0
                                            If VY >= 0 And VY < MAX_MAPY Then Mat(i, i + MAX_MAPX + 1) = 0
                                            If VY > 0 And VY <= MAX_MAPY Then Mat(i, i - MAX_MAPX - 1) = 0
Replace this with part of code too with code above:
Code:
For K = 0 To NV
    Mat(i, K) = 0
    Mat(K, i) = 0
Next K
Now we are with a lot better speed, but not the best. We need to replace now the code inside the While, and that's the most important part ;)
Replace all the code that's inside the While with this:
Code:
                                            VY = Int(PathLine(Start) / (MAX_MAPX + 1))
                                            VX = PathLine(Start) Mod (MAX_MAPX + 1)
                                            If VY >= 0 And VY < MAX_MAPY Then
                                                If Mat(PathLine(Start), PathLine(Start) + MAX_MAPX + 1) = 1 And Marked(PathLine(Start) + MAX_MAPX + 1) = 0 And Flag = 0 Then
                                                    Path(PathLine(Start) + MAX_MAPX + 1) = PathLine(Start)
                                                    PathLine(Finish) = PathLine(Start) + MAX_MAPX + 1
                                                    Marked(PathLine(Start) + MAX_MAPX + 1) = 1
                                                    Finish = Finish + 1
                                                    If PathLine(Finish - 1) = o Then
                                                        Flag = 1
                                                    End If
                                                End If
                                            End If
                                           
                                            VY = Int(PathLine(Start) / (MAX_MAPX + 1))
                                            VX = PathLine(Start) Mod (MAX_MAPX + 1)
                                            If VX > 0 And VX <= MAX_MAPX Then
                                                If Mat(PathLine(Start), PathLine(Start) - 1) = 1 And Marked(PathLine(Start) - 1) = 0 And Flag = 0 Then
                                                    Path(PathLine(Start) - 1) = PathLine(Start)
                                                    PathLine(Finish) = PathLine(Start) - 1
                                                    Marked(PathLine(Start) - 1) = 1
                                                    Finish = Finish + 1
                                                    If PathLine(Finish - 1) = o Then
                                                        Flag = 1
                                                    End If
                                                End If
                                            End If
                                           
                                            VY = Int(PathLine(Start) / (MAX_MAPX + 1))
                                            VX = PathLine(Start) Mod (MAX_MAPX + 1)
                                            If VX >= 0 And VX < MAX_MAPX Then
                                                If Mat(PathLine(Start), PathLine(Start) + 1) = 1 And Marked(PathLine(Start) + 1) = 0 And Flag = 0 Then
                                                    Path(PathLine(Start) + 1) = PathLine(Start)
                                                    PathLine(Finish) = PathLine(Start) + 1
                                                    Marked(PathLine(Start) + 1) = 1
                                                    Finish = Finish + 1
                                                    If PathLine(Finish - 1) = o Then
                                                        Flag = 1
                                                    End If
                                                End If
                                            End If
                                           
                                            VY = Int(PathLine(Start) / (MAX_MAPX + 1))
                                            VX = PathLine(Start) Mod (MAX_MAPX + 1)
                                            If VY > 0 And VY <= MAX_MAPY Then
                                                If Mat(PathLine(Start), PathLine(Start) - MAX_MAPX - 1) = 1 And Marked(PathLine(Start) - MAX_MAPX - 1) = 0 And Flag = 0 Then
                                                    Path(PathLine(Start) - MAX_MAPX - 1) = PathLine(Start)
                                                    PathLine(Finish) = PathLine(Start) - MAX_MAPX - 1
                                                    Marked(PathLine(Start) - MAX_MAPX - 1) = 1
                                                    Finish = Finish + 1
                                                    If PathLine(Finish - 1) = o Then
                                                        Flag = 1
                                                    End If
                                                End If
                                            End If
                                           
                                            Marked(PathLine(Start)) = 1
                                            PathLine(Start) = -1
                                            Start = Start + 1
Well, that's it, Good luck with it and I would really appreciate credits for this if you add it to your game. Any question you may have, just post here and I'll try to answer it.

FINISHED

_________________
http://www.blackages.com.br
Image
Dave wrote:
GameBoy wrote:
www.FreeMoney.com
I admit I clicked. I immediately closed upon realizing there was, in fact, no free money.
Robin wrote:
I love you and your computer.Marry me.


Last edited by Dragoons Master on Sat Jul 21, 2007 4:26 pm, edited 20 times in total.

Top
 Profile  
 
PostPosted: Fri Jul 20, 2007 6:49 am 
Offline
Newbie
User avatar

Joined: Tue Jul 17, 2007 8:00 pm
Posts: 12
Sexy, it'll be nice to see one of MSs greatest programmers way of doing NPC AI.

_________________
Hello... World?!
Image


Top
 Profile  
 
PostPosted: Sat Jul 21, 2007 2:02 am 
Offline
Pro
User avatar

Joined: Mon May 29, 2006 3:26 pm
Posts: 493
Location: São Paulo, Brasil
Google Talk: blackagesbr@gmail.com
Iluvlamp wrote:
Sexy, it'll be nice to see one of MSs greatest programmers way of doing NPC AI.

Tnx ^^
I've updated the TUT a lot, almost finished, need the final and most important part and I'll make it a little bit faster so there will be less processing needed.

_________________
http://www.blackages.com.br
Image
Dave wrote:
GameBoy wrote:
www.FreeMoney.com
I admit I clicked. I immediately closed upon realizing there was, in fact, no free money.
Robin wrote:
I love you and your computer.Marry me.


Top
 Profile  
 
PostPosted: Sat Jul 21, 2007 9:36 am 
Offline
Submit-Happy
User avatar

Joined: Fri Jun 16, 2006 7:01 am
Posts: 2768
Location: Yorkshire, UK
Mhhh, started reading through and it looks really interesting.

Can't wait to try it out ^_^

_________________
Quote:
Robin:
Why aren't maps and shit loaded up in a dynamic array?
Jacob:
the 4 people that know how are lazy
Robin:
Who are those 4 people?
Jacob:
um
you, me, and 2 others?


Image


Top
 Profile  
 
PostPosted: Sat Jul 21, 2007 12:36 pm 
Offline
Community Leader
User avatar

Joined: Mon May 29, 2006 1:00 pm
Posts: 2538
Location: Sweden
Google Talk: johansson_tk@hotmail.com
Yeah, I'd love to see were this is going. I started a custom AI before, but without these mathematical parts. Was going to use it for k2h since the default ai is kinda lame.

_________________
I'm on Facebook!My Youtube Channel Send me an email
Image


Top
 Profile  
 
PostPosted: Sat Jul 21, 2007 4:31 pm 
Offline
Community Leader
User avatar

Joined: Mon May 29, 2006 1:00 pm
Posts: 2538
Location: Sweden
Google Talk: johansson_tk@hotmail.com
I will for sure add it. Thanks for finishing it :D Ill respond how it goes later.

_________________
I'm on Facebook!My Youtube Channel Send me an email
Image


Top
 Profile  
 
PostPosted: Sat Jul 21, 2007 9:57 pm 
Offline
Submit-Happy
User avatar

Joined: Fri Jun 16, 2006 7:01 am
Posts: 2768
Location: Yorkshire, UK
That was quite possibly both the easiest tutorial ever, and the best addition to mirage ever.

Now I really want to completely understand what's going on ;-;

Dragoons Master, you really are a genius.

I commend you!

_________________
Quote:
Robin:
Why aren't maps and shit loaded up in a dynamic array?
Jacob:
the 4 people that know how are lazy
Robin:
Who are those 4 people?
Jacob:
um
you, me, and 2 others?


Image


Top
 Profile  
 
PostPosted: Sun Jul 22, 2007 4:21 pm 
Offline
Community Leader
User avatar

Joined: Mon May 29, 2006 1:00 pm
Posts: 2538
Location: Sweden
Google Talk: johansson_tk@hotmail.com
As a conclusion, the AI works just as it should. I've noticed my game aint that fast, I will probably need to get a better connection and also improve my RAM with 1 more gb. And probably need byte packets client side too. And gotta fix position modification, and improve more things..

.. Im not 100% sure Im going to keep the AI in my game yet, just feels like its the top of the iceberg on crashing everything. Gotta improve what I already got. And I need to talk to DM more.

_________________
I'm on Facebook!My Youtube Channel Send me an email
Image


Top
 Profile  
 
PostPosted: Thu Jul 26, 2007 5:34 pm 
Offline
Pro
User avatar

Joined: Mon May 29, 2006 3:26 pm
Posts: 493
Location: São Paulo, Brasil
Google Talk: blackagesbr@gmail.com
Has anyone with normal maps(no scrolling) tried this and found any bug?
I'll realy like to find one ^^

_________________
http://www.blackages.com.br
Image
Dave wrote:
GameBoy wrote:
www.FreeMoney.com
I admit I clicked. I immediately closed upon realizing there was, in fact, no free money.
Robin wrote:
I love you and your computer.Marry me.


Top
 Profile  
 
PostPosted: Thu Jul 26, 2007 9:05 pm 
Offline
Submit-Happy
User avatar

Joined: Fri Jun 16, 2006 7:01 am
Posts: 2768
Location: Yorkshire, UK
Not that I could find...

I noticed that sometimes the npcs would stop following, but a tiny bit of debugging found out that you used a different style blocked tile check that usual, so I just needed to edit that and it was fine.

_________________
Quote:
Robin:
Why aren't maps and shit loaded up in a dynamic array?
Jacob:
the 4 people that know how are lazy
Robin:
Who are those 4 people?
Jacob:
um
you, me, and 2 others?


Image


Top
 Profile  
 
PostPosted: Sun Jul 29, 2007 1:23 pm 
Offline
Community Leader
User avatar

Joined: Mon May 29, 2006 1:00 pm
Posts: 2538
Location: Sweden
Google Talk: johansson_tk@hotmail.com
Robin wrote:
Not that I could find...

I noticed that sometimes the npcs would stop following, but a tiny bit of debugging found out that you used a different style blocked tile check that usual, so I just needed to edit that and it was fine.

It looks to work pretty well, I will do more testing ut for now it seems to work.

_________________
I'm on Facebook!My Youtube Channel Send me an email
Image


Top
 Profile  
 
PostPosted: Mon Jul 30, 2007 6:31 pm 
Offline
Newbie

Joined: Mon May 29, 2006 2:18 pm
Posts: 22
Location: Florida
GREAT tutorial, a bit over my head, but it's really useful. Just a quick note for the tile detection thing, npcs can only walk on item attributes, so the check if the door is open is useless. Also, for some reason only like 1 of the attack on sight npcs goes after me, even with multiple routes open to me; the others are as stupid as ever. I'de like to talk to you if you get a chance.


Top
 Profile  
 
PostPosted: Sun Nov 18, 2007 11:39 pm 
Offline
Regular
User avatar

Joined: Tue Oct 09, 2007 1:40 am
Posts: 93
This is genius. I actually had an idea in the back of my mind to create "shortest path finding", but my god.. this is amazing.


Top
 Profile  
 
PostPosted: Sat Dec 08, 2007 7:46 pm 
Offline
Regular
User avatar

Joined: Tue Oct 09, 2007 1:40 am
Posts: 93
I need some help, Ive tryed several times to implement this tutorial but still cant get it to work for Elysium. Heres my code:
Code:
                ' /////////////////////////////////////////////
                ' // This is used for NPC walking/targetting //
                ' /////////////////////////////////////////////
                ' Make sure theres a npc with the map
                If Map(y).Npc(x) > 0 And MapNpc(y, x).Num > 0 Then
                    Target = MapNpc(y, x).Target
                   
                    ' Check to see if its time for the npc to walk
                    If Npc(NpcNum).Behavior <> NPC_BEHAVIOR_SHOPKEEPER Then
                        ' Check to see if we are following a player or not
                        If Target > 0 Then
                            ' Check if the player is even playing, if so follow'm
                            If IsPlaying(Target) And GetPlayerMap(Target) = y Then
                                DidWalk = False
                                CloseToPlayer = False
                                If (GetPlayerY(Target) + 1 = MapNpc(y, x).y) And (GetPlayerX(Target) = MapNpc(y, x).x) Then
                                    CloseToPlayer = True
                                Else
                                    If (GetPlayerY(Target) - 1 = MapNpc(y, x).y) And (GetPlayerX(Target) = MapNpc(y, x).x) Then
                                        CloseToPlayer = True
                                    Else
                                        If (GetPlayerY(Target) = MapNpc(y, x).y) And (GetPlayerX(Target) + 1 = MapNpc(y, x).x) Then
                                            CloseToPlayer = True
                                        Else
                                            If (GetPlayerY(Target) = MapNpc(y, x).y) And (GetPlayerX(Target) - 1 = MapNpc(y, x).x) Then
                                                CloseToPlayer = True
                                            End If
                                        End If
                                    End If
                                End If                               
                                If Not CloseToPlayer Then
                                    o = MapNpc(Y, X).Y * (MAX_MAPX + 1) + MapNpc(Y, X).X
                                    d = GetPlayerY(Target) * (MAX_MAPX + 1) + GetPlayerX(Target)
                                    For i = 0 To NV
                                        VY = Int(i / (MAX_MAPX + 1))
                                        VX = i Mod (MAX_MAPX + 1)
                                        If (Map(y).Tile(VX, VY).Type = TILE_TYPE_BLOCKED Or Map(y).Tile(VX, VY).Type = TILE_TYPE_NPCAVOID Or Map(y).Tile(VX, VY).Type = TILE_TYPE_WARP Or (Map(y).Tile(VX, VY).Type = TILE_TYPE_KEY And TempTile(y).DoorOpen(VX, VY) = NO)) Then
                                            For J = 0 To NV
                                                Mat(J, i) = 0
                                                Mat(i, J) = 0
                                            Next J
                                        End If
                                        For J = 1 To MAX_PLAYERS
                                            If IsPlaying(J) Then
                                                If GetPlayerMap(J) = y Then
                                                    If GetPlayerX(J) = VX And GetPlayerY(J) = VY And J <> Target Then
                                                        For K = 0 To NV
                                                            Mat(i, K) = 0
                                                            Mat(K, i) = 0
                                                        Next K
                                                    End If
                                                End If
                                            End If
                                        Next J
                                        For J = 1 To MAX_MAP_NPCS
                                            If Map(y).Npc(J) > 0 And MapNpc(y, J).Num > 0 Then
                                                If MapNpc(y, J).x = VX And MapNpc(y, J).y = VY And J <> x Then
                                                    For K = 0 To NV
                                                        Mat(i, K) = 0
                                                        Mat(K, i) = 0
                                                    Next K
                                                End If
                                            End If
                                        Next J
                                    Next i
                                    Flag = 0
                                    PathLine(0) = d
                                    Start = 0
                                    Finish = 1
                                    If o <> d Then
                                        While (PathLine(Start) <> -1 And Flag = 0)
                                            VY = Int(PathLine(Start) / (MAX_MAPX + 1))
                                            VX = PathLine(Start) Mod (MAX_MAPX + 1)
                                            If VY >= 0 And VY < MAX_MAPY Then
                                                If Mat(PathLine(Start), PathLine(Start) + MAX_MAPX + 1) = 1 And Marked(PathLine(Start) + MAX_MAPX + 1) = 0 And Flag = 0 Then
                                                    Path(PathLine(Start) + MAX_MAPX + 1) = PathLine(Start)
                                                    PathLine(Finish) = PathLine(Start) + MAX_MAPX + 1
                                                    Marked(PathLine(Start) + MAX_MAPX + 1) = 1
                                                    Finish = Finish + 1
                                                    If PathLine(Finish - 1) = o Then
                                                        Flag = 1
                                                    End If
                                                End If
                                            End If
                                           
                                            VY = Int(PathLine(Start) / (MAX_MAPX + 1))
                                            VX = PathLine(Start) Mod (MAX_MAPX + 1)
                                            If VX > 0 And VX <= MAX_MAPX Then
                                                If Mat(PathLine(Start), PathLine(Start) - 1) = 1 And Marked(PathLine(Start) - 1) = 0 And Flag = 0 Then
                                                    Path(PathLine(Start) - 1) = PathLine(Start)
                                                    PathLine(Finish) = PathLine(Start) - 1
                                                    Marked(PathLine(Start) - 1) = 1
                                                    Finish = Finish + 1
                                                    If PathLine(Finish - 1) = o Then
                                                        Flag = 1
                                                    End If
                                                End If
                                            End If
                                           
                                            VY = Int(PathLine(Start) / (MAX_MAPX + 1))
                                            VX = PathLine(Start) Mod (MAX_MAPX + 1)
                                            If VX >= 0 And VX < MAX_MAPX Then
                                                If Mat(PathLine(Start), PathLine(Start) + 1) = 1 And Marked(PathLine(Start) + 1) = 0 And Flag = 0 Then
                                                    Path(PathLine(Start) + 1) = PathLine(Start)
                                                    PathLine(Finish) = PathLine(Start) + 1
                                                    Marked(PathLine(Start) + 1) = 1
                                                    Finish = Finish + 1
                                                    If PathLine(Finish - 1) = o Then
                                                        Flag = 1
                                                    End If
                                                End If
                                            End If
                                           
                                            VY = Int(PathLine(Start) / (MAX_MAPX + 1))
                                            VX = PathLine(Start) Mod (MAX_MAPX + 1)
                                            If VY > 0 And VY <= MAX_MAPY Then
                                                If Mat(PathLine(Start), PathLine(Start) - MAX_MAPX - 1) = 1 And Marked(PathLine(Start) - MAX_MAPX - 1) = 0 And Flag = 0 Then
                                                    Path(PathLine(Start) - MAX_MAPX - 1) = PathLine(Start)
                                                    PathLine(Finish) = PathLine(Start) - MAX_MAPX - 1
                                                    Marked(PathLine(Start) - MAX_MAPX - 1) = 1
                                                    Finish = Finish + 1
                                                    If PathLine(Finish - 1) = o Then
                                                        Flag = 1
                                                    End If
                                                End If
                                            End If
                                           
                                            Marked(PathLine(Start)) = 1
                                            PathLine(Start) = -1
                                            Start = Start + 1                                           
                                        Wend                                       
                                    End If                                   
                                End If
                                                                              If Flag = 1 Then
                                            VY = Int(Path(o) / (MAX_MAPX + 1))
                                            VX = Path(o) Mod (MAX_MAPX + 1)
                                            DoEvents
                                            If MapNpc(y, x).y > VY Then
                                                If CanNpcMove(y, x, DIR_UP) Then
                                                    Call NpcMove(y, x, DIR_UP, MOVING_WALKING)
                                                    DidWalk = True
                                                End If
                                            ElseIf MapNpc(y, x).y < VY Then
                                                ' Down
                                                If CanNpcMove(y, x, DIR_DOWN) Then
                                                    Call NpcMove(y, x, DIR_DOWN, MOVING_WALKING)
                                                    DidWalk = True
                                                End If
                                            ElseIf MapNpc(y, x).x > VX Then
                                                ' Left
                                                If CanNpcMove(y, x, DIR_LEFT) Then
                                                    Call NpcMove(y, x, DIR_LEFT, MOVING_WALKING)
                                                    DidWalk = True
                                                End If
                                            ElseIf MapNpc(y, x).x < VX Then
                                                ' Right
                                                If CanNpcMove(y, x, DIR_RIGHT) Then
                                                    Call NpcMove(y, x, DIR_RIGHT, MOVING_WALKING)
                                                    DidWalk = True
                                                End If
                                            End If
                                                                              End If
                                ' Check if we can't move and if player is behind something and if we can just switch dirs
                                If Not DidWalk Then
                                    If MapNpc(y, x).x - 1 = GetPlayerX(Target) And MapNpc(y, x).y = GetPlayerY(Target) Then
                                        If MapNpc(y, x).Dir <> DIR_LEFT Then
                                            Call NpcDir(y, x, DIR_LEFT)
                                        End If
                                        DidWalk = True
                                    End If
                                    If MapNpc(y, x).x + 1 = GetPlayerX(Target) And MapNpc(y, x).y = GetPlayerY(Target) Then
                                        If MapNpc(y, x).Dir <> DIR_RIGHT Then
                                            Call NpcDir(y, x, DIR_RIGHT)
                                        End If
                                        DidWalk = True
                                    End If
                                    If MapNpc(y, x).x = GetPlayerX(Target) And MapNpc(y, x).y - 1 = GetPlayerY(Target) Then
                                        If MapNpc(y, x).Dir <> DIR_UP Then
                                            Call NpcDir(y, x, DIR_UP)
                                        End If
                                        DidWalk = True
                                    End If
                                    If MapNpc(y, x).x = GetPlayerX(Target) And MapNpc(y, x).y + 1 = GetPlayerY(Target) Then
                                        If MapNpc(y, x).Dir <> DIR_DOWN Then
                                            Call NpcDir(y, x, DIR_DOWN)
                                        End If
                                        DidWalk = True
                                    End If
                                   
                                    ' We could not move so player must be behind something, walk randomly.
                                    If Not DidWalk Then
                                        i = Int(Rnd * 2)
                                        If i = 1 Then
                                            i = Int(Rnd * 4)
                                            If CanNpcMove(y, x, i) Then
                                                Call NpcMove(y, x, i, MOVING_WALKING)
                                            End If
                                        End If
                                    End If
                                End If
                            Else
                                MapNpc(y, x).Target = 0
                            End If
                        Else
                            i = Int(Rnd * 4)
                            If i = 1 Then
                                i = Int(Rnd * 4)
                                If CanNpcMove(y, x, i) Then
                                    Call NpcMove(y, x, i, MOVING_WALKING)
                                End If
                            End If
                        End If
                    End If
                End If

Ive spent alot of time going through the scenarios and following the pathfinding, my main problem is that Flag never becomes 1. For some reason, my mat() causes subscript out of range. Because the InitServer sub is no longer used, I put this directly after Call SpawnAllMapNpcs in the main sub in modGeneral:
Code:
    NV = (MAX_MAPX + 1) * (MAX_MAPY + 1) - 1
    ReDim Mat(0 To NV, 0 To NV) As Byte
    ReDim Marked(0 To NV) As Byte
    ReDim PathLine(0 To NV) As Integer
    ReDim Path(0 To NV) As Integer

Maybe thats the wrong place for elysium? Hope you can help, thanks!


Top
 Profile  
 
PostPosted: Wed Dec 12, 2007 2:48 am 
Offline
Pro
User avatar

Joined: Mon May 29, 2006 3:26 pm
Posts: 493
Location: São Paulo, Brasil
Google Talk: blackagesbr@gmail.com
I've never used elysium so I have absolutly no idea ><
Sry, can't help... If I had the time I would, but I'm in the last days of the semester here at college and I really need to study...

_________________
http://www.blackages.com.br
Image
Dave wrote:
GameBoy wrote:
www.FreeMoney.com
I admit I clicked. I immediately closed upon realizing there was, in fact, no free money.
Robin wrote:
I love you and your computer.Marry me.


Top
 Profile  
 
PostPosted: Wed Dec 12, 2007 12:54 pm 
Offline
Submit-Happy
User avatar

Joined: Fri Jun 16, 2006 7:01 am
Posts: 2768
Location: Yorkshire, UK
No difference between AI in Elysium and Mirage.

_________________
Quote:
Robin:
Why aren't maps and shit loaded up in a dynamic array?
Jacob:
the 4 people that know how are lazy
Robin:
Who are those 4 people?
Jacob:
um
you, me, and 2 others?


Image


Top
 Profile  
 
PostPosted: Sun Dec 16, 2007 8:25 pm 
Offline
Regular
User avatar

Joined: Tue Oct 09, 2007 1:40 am
Posts: 93
Robin wrote:
No difference between AI in Elysium and Mirage.


InitServer isnt used anymore:
[qoute="Dragoons Master"]Now we need to initialize this matrix, and we'll do it at InitServer Sub.[/qoute]

Ive tryed adding this so many times.


Top
 Profile  
 
PostPosted: Mon Dec 17, 2007 3:10 am 
Offline
Pro
User avatar

Joined: Mon May 29, 2006 3:26 pm
Posts: 493
Location: São Paulo, Brasil
Google Talk: blackagesbr@gmail.com
Just add it anywhere before:
Code:
    'Lets start the server!
    ServerLoop

That MIGHT work, I'm not sure...

_________________
http://www.blackages.com.br
Image
Dave wrote:
GameBoy wrote:
www.FreeMoney.com
I admit I clicked. I immediately closed upon realizing there was, in fact, no free money.
Robin wrote:
I love you and your computer.Marry me.


Top
 Profile  
 
PostPosted: Sat Feb 16, 2008 7:30 am 
Offline
Knowledgeable
User avatar

Joined: Fri Feb 02, 2007 4:50 am
Posts: 263
Location: usa michigan centriville
NVM i fixed it by changing

MapNpc(y, x).Target = 0
To
MapNpc(y, x).Target = 1

So now the NPC can attack right.

_________________
Fuck? I really joined in 2006.
Spirea, Chat Rooms, Discussions, Help. everything you need in one spot.
http://spirean.com
I love my computer, you never ask for more, you can be my princess or be my whore


Top
 Profile  
 
PostPosted: Mon Mar 10, 2008 7:35 pm 
Offline
Newbie

Joined: Wed Jan 09, 2008 12:50 am
Posts: 4
Not wanting to necropost or anything, but I have a problem with this tutorial.

See, the AI was working perfectly, and I used genusis' fix, but for some reason, when I changed the number of maps/items/npcs, the NPCs stopped moving. I can interact, and use the speeches, but they won't follow me to attack. Also, they don't attack back. I was wondering if changing the number of NPCs did something?


Top
 Profile  
 
PostPosted: Thu Mar 20, 2008 12:46 pm 
Offline
Knowledgeable
User avatar

Joined: Fri Feb 02, 2007 4:50 am
Posts: 263
Location: usa michigan centriville
you have to take the admin thing out so they can attack admins haha.

_________________
Fuck? I really joined in 2006.
Spirea, Chat Rooms, Discussions, Help. everything you need in one spot.
http://spirean.com
I love my computer, you never ask for more, you can be my princess or be my whore


Top
 Profile  
 
PostPosted: Thu Mar 20, 2008 9:57 pm 
Offline
Pro
User avatar

Joined: Mon May 29, 2006 3:26 pm
Posts: 493
Location: São Paulo, Brasil
Google Talk: blackagesbr@gmail.com
Ops, sry about that xD

_________________
http://www.blackages.com.br
Image
Dave wrote:
GameBoy wrote:
www.FreeMoney.com
I admit I clicked. I immediately closed upon realizing there was, in fact, no free money.
Robin wrote:
I love you and your computer.Marry me.


Top
 Profile  
 
PostPosted: Mon Mar 31, 2008 7:24 pm 
Offline
Newbie

Joined: Wed Jan 09, 2008 12:50 am
Posts: 4
I wasn't an admin when I tested this. My players have also reported this happening , so..


Top
 Profile  
 
PostPosted: Sat Apr 05, 2008 10:02 pm 
Offline
Pro
User avatar

Joined: Mon May 29, 2006 3:26 pm
Posts: 493
Location: São Paulo, Brasil
Google Talk: blackagesbr@gmail.com
It just does not happen to me, sry.

_________________
http://www.blackages.com.br
Image
Dave wrote:
GameBoy wrote:
www.FreeMoney.com
I admit I clicked. I immediately closed upon realizing there was, in fact, no free money.
Robin wrote:
I love you and your computer.Marry me.


Top
 Profile  
 
PostPosted: Sun Apr 06, 2008 2:50 pm 
Offline
Newbie

Joined: Wed Jan 09, 2008 12:50 am
Posts: 4
Ok, well, thanks for trying Dragoons.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 52 posts ]  Go to page 1, 2, 3  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 6 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB® Forum Software © phpBB Group