Automatic layering system

From VbGORE Visual Basic Online RPG Engine

This was originally part of an upgrade (Version 1.1.0 to be specific), but was omitted due to the complications it would bring to the typical user, and the amount that vbGORE would have to be altered to make it work (such as the help, GUIs, etc).

Pros and Cons

Pros:

  • Automatic layering - The layers are decided based on the Y axis along with the height of the Grh. This prevents having to break up certain graphics (like trees) into "behind" and "front" parts.
  • Faster mapping - Because you don't have to worry about the layers as much, you will be able to map a lot faster.
  • Less Grhs - There will be less Grhs because you won't have to break them into multiple parts.

Cons:

  • Automatic layering - This is also a con, since you have to hope the automatic layering gives you what you want. If it does not, you have to do some cheap hacks to get it to work.
  • Remake maps - Since the maps work completely different, you will have to remake them all.

How it works

Here is a copy-and-paste from the original entry in the upgrade guide:

"Added a new rendering system. How this system works is instead of what is drawn being decided on what layer the Grh is on, there are three tile types. These types are always below (layer 1 and 2), mixed (layer 3 to 5) and always above (layer 6). The always below is used for the ground tiles. Mixed is used for anything that has depth - trees, buildings, chairs, etc. Layer 6 is used for special cases, like birds or clouds, though it is not a very common type to have to use, which is why there is only one layer for it. The mixed layer works by sorting on a pseudo-Z axis calculated by the Y + Height of a Grh. This algorithm is also applied to particle effects (ie bless), Grh effects (ie Spike Field), characters (NPCs and PCs both), blood splatters (from when you hit a NPC / get hit) and projectiles (ie Ninja Star). Because of this new system, previously made maps will not function correctly. Though, you no longer have to split up your trees and have part of it on layer 2/3 and the other part on layer 4/5 just so you can walk in front of it and stand behind it, as the engine will do this for you. This also fixes a lot of issues with putting the shadows on these Grhs, since they are now just one Grh, so they cast just one shadow. For those who are worried about performance, there was no FPS drop when tested against ~500 Grhs on layer 3-5, so performance is not a concern."

Adding guide

Follow this guide just like you would any other upgrade guide, since this is how it was written (which is why it is in 3 parts). Start with the last on the end of the page, and move up to the first.

Fix - Animations

Open GameClient.vbp.

In module TileEngine, add:

<vb> Public Function Engine_GetFrameFromGrh(Grh As Grh) As Long '************************************************************ 'Get a Grh and return the frame (useful for animations) '************************************************************ Dim i As Long

   'Check for a valid GrhIndex
   If Grh.GrhIndex < 1 Then Exit Function
   If Grh.GrhIndex > NumGrhs Then Exit Function
   
   'Round down on the frame counter
   i = Int(Grh.FrameCounter)
   
   'Check for a frame count overflow
   If i > GrhData(Grh.GrhIndex).NumFrames Then Exit Function
   
   'Return the Grh index
   Engine_GetFrameFromGrh = GrhData(Grh.GrhIndex).Frames(Int(Grh.FrameCounter))

End Function</vb>

Find:

<vb>

                           Engine_AddToRenderList_Grh RenderList(), RenderListSize, RenderListIndex, BloodList(j).Grh.GrhIndex, X, Y, _
                               Y + GrhData(BloodList(j).Grh.GrhIndex).pixelHeight, -1, -1, -1, -1, 0, 1, 0</vb>

Replace with:

<vb>

                           Engine_AddToRenderList_Grh RenderList(), RenderListSize, RenderListIndex, Engine_GetFrameFromGrh(BloodList(j).Grh), X, Y, _
                               Y + GrhData(BloodList(j).Grh.GrhIndex).pixelHeight, -1, -1, -1, -1, 0, 1, 0

</vb>

Find:

<vb>

                               Engine_AddToRenderList_Grh RenderList(), RenderListSize, RenderListIndex, OBJList(j).Grh.GrhIndex, X, Y, _
                                   Y + GrhData(OBJList(j).Grh.GrhIndex).pixelHeight, .Light(1), .Light(2), .Light(3), .Light(4), 0, 1, 1</vb>

Replace with:

<vb>

                               Engine_AddToRenderList_Grh RenderList(), RenderListSize, RenderListIndex, Engine_GetFrameFromGrh(OBJList(j).Grh), X, Y, _
                                   Y + GrhData(OBJList(j).Grh.GrhIndex).pixelHeight, .Light(1), .Light(2), .Light(3), .Light(4), 0, 1, 1

</vb>

Find:

<vb>

               Engine_AddToRenderList_Grh RenderList(), RenderListSize, RenderListIndex, MapData(.TileX, .TileY).Graphic(Layer).GrhIndex, _
                   .PixelPosX + PixelOffsetX, .PixelPosY + PixelOffsetY, .PixelPosY + PixelOffsetY + _
                   GrhData(MapData(.TileX, .TileY).Graphic(Layer).GrhIndex).pixelHeight, MapData(.TileX, .TileY).Light(1), _
                   MapData(.TileX, .TileY).Light(2), MapData(.TileX, .TileY).Light(3), MapData(.TileX, .TileY).Light(4), _
                   0, 0, MapData(.TileX, .TileY).Shadow(Layer)

</vb>

Replace with:

<vb>

               Engine_AddToRenderList_Grh RenderList(), RenderListSize, RenderListIndex, Engine_GetFrameFromGrh(MapData(.TileX, .TileY).Graphic(Layer)), _
                   .PixelPosX + PixelOffsetX, .PixelPosY + PixelOffsetY, .PixelPosY + PixelOffsetY + _
                   GrhData(MapData(.TileX, .TileY).Graphic(Layer).GrhIndex).pixelHeight, MapData(.TileX, .TileY).Light(1), _
                   MapData(.TileX, .TileY).Light(2), MapData(.TileX, .TileY).Light(3), MapData(.TileX, .TileY).Light(4), _
                   0, 0, MapData(.TileX, .TileY).Shadow(Layer)

</vb>

Find:

<vb>

                       Engine_AddToRenderList_Grh RenderList(), RenderListSize, RenderListIndex, GrhData(EffectList(j).Grh.GrhIndex).Frames(Int(EffectList(j).Grh.FrameCounter)), X, Y, _
                           Y + GrhData(EffectList(j).Grh.GrhIndex).pixelHeight, -1, -1, -1, -1, EffectList(j).Angle, 0, 1

</vb>

Replace with:

<vb>

                       Engine_AddToRenderList_Grh RenderList(), RenderListSize, RenderListIndex, Engine_GetFrameFromGrh(EffectList(j).Grh), X, Y, _
                           Y + GrhData(EffectList(j).Grh.GrhIndex).pixelHeight, -1, -1, -1, -1, EffectList(j).Angle, 0, 1

</vb>

Find:

<vb>

                           Engine_AddToRenderList_Grh RenderList(), RenderListSize, RenderListIndex, ProjectileList(j).Grh.GrhIndex, _
                               X, Y, Y + GrhData(ProjectileList(j).Grh.GrhIndex).pixelHeight, -1, -1, -1, -1, ProjectileList(j).Rotate, 0, 1

</vb>

Replace with:

<vb>

                           Engine_AddToRenderList_Grh RenderList(), RenderListSize, RenderListIndex, Engine_GetFrameFromGrh(ProjectileList(j).Grh), _
                               X, Y, Y + GrhData(ProjectileList(j).Grh.GrhIndex).pixelHeight, -1, -1, -1, -1, ProjectileList(j).Rotate, 0, 1

</vb>

Open EditorMap.vbp.

In module TileEngine, add:

<vb> Public Function Engine_GetFrameFromGrh(Grh As Grh) As Long '************************************************************ 'Get a Grh and return the frame (useful for animations) '************************************************************ Dim i As Long

   'Check for a valid GrhIndex
   If Grh.GrhIndex < 1 Then Exit Function
   If Grh.GrhIndex > NumGrhs Then Exit Function
   
   'Round down on the frame counter
   i = Int(Grh.FrameCounter)
   
   'Check for a frame count overflow
   If i > GrhData(Grh.GrhIndex).NumFrames Then Exit Function
   
   'Return the Grh index
   Engine_GetFrameFromGrh = GrhData(Grh.GrhIndex).Frames(Int(Grh.FrameCounter))

End Function</vb>

Find:

<vb>

   '************** Layer 3 to 5 **************
   For Layer = 3 To 5
       LightOffset = ((Layer - 1) * 4) + 1
       For j = 1 To TileLayer(Layer).NumTiles
           With TileLayer(Layer).Tile(j)
               Engine_UpdateGrh MapData(.TileX, .TileY).Graphic(Layer), True
               Engine_AddToRenderList_Grh RenderList(), RenderListSize, RenderListIndex, MapData(.TileX, .TileY).Graphic(Layer).GrhIndex, _
                   .PixelPosX + PixelOffsetX, .PixelPosY + PixelOffsetY, .PixelPosY + PixelOffsetY + _
                   GrhData(MapData(.TileX, .TileY).Graphic(Layer).GrhIndex).pixelHeight, MapData(.TileX, .TileY).Light(1), _
                   MapData(.TileX, .TileY).Light(2), MapData(.TileX, .TileY).Light(3), MapData(.TileX, .TileY).Light(4), _
                   0, 0, MapData(.TileX, .TileY).Shadow(Layer)
           End With
       Next j
   Next Layer

</vb>

Replace with:

<vb>

   '************** Layer 2 to 5 **************
   For Layer = 2 To 5
       LightOffset = ((Layer - 1) * 4) + 1
       For j = 1 To TileLayer(Layer).NumTiles
           With TileLayer(Layer).Tile(j)
               Engine_UpdateGrh MapData(.TileX, .TileY).Graphic(Layer), True
               Engine_AddToRenderList_Grh RenderList(), RenderListSize, RenderListIndex, Engine_GetFrameFromGrh(MapData(.TileX, .TileY).Graphic(Layer)), _
                   .PixelPosX + PixelOffsetX, .PixelPosY + PixelOffsetY, .PixelPosY + PixelOffsetY + _
                   GrhData(MapData(.TileX, .TileY).Graphic(Layer).GrhIndex).pixelHeight, MapData(.TileX, .TileY).Light(LightOffset), _
                   MapData(.TileX, .TileY).Light(LightOffset + 1), MapData(.TileX, .TileY).Light(LightOffset + 2), MapData(.TileX, .TileY).Light(LightOffset + 3), _
                   0, 0, MapData(.TileX, .TileY).Shadow(Layer)
           End With
       Next j
   Next Layer

</vb>

Fix - Effect rendering

Open GameClient.vbp.

Find:

<vb>

   '************** Grh-Based (Non-Particle) Effects **************

</vb>

Replace the block of code (from For j = ... to Next j) with:

<vb>

   '************** Grh-Based (Non-Particle) Effects **************
   For j = 1 To LastEffect
       If EffectList(j).Grh.GrhIndex Then
           X = Engine_PixelPosX(EffectList(j).Pos.X - minX) + PixelOffsetX + TileBufferOffset
           Y = Engine_PixelPosY(EffectList(j).Pos.Y - minY) + PixelOffsetY + TileBufferOffset
           'Time ran out
           If EffectList(j).Time <> 0 And EffectList(j).Time < timeGetTime Then
               Engine_Effect_Erase j
           'Draw the effect
           ElseIf Y >= -32 And Y <= (ScreenHeight + 32) And X >= -32 And X <= (ScreenWidth + 32) Then
               Engine_UpdateGrh EffectList(j).Grh, False
               If EffectList(j).Animated = 1 Then
                   If EffectList(j).Grh.Started = 0 Then
                       Engine_Effect_Erase j
                       GoTo NextEffect
                   End If
               End If
               If EffectList(j).Grh.FrameCounter >= 1 Then
                   If Int(EffectList(j).Grh.FrameCounter) <= GrhData(EffectList(j).Grh.GrhIndex).NumFrames Then
                       Engine_AddToRenderList_Grh RenderList(), RenderListSize, RenderListIndex, GrhData(EffectList(j).Grh.GrhIndex).Frames(Int(EffectList(j).Grh.FrameCounter)), X, Y, _
                           Y + GrhData(EffectList(j).Grh.GrhIndex).pixelHeight, -1, -1, -1, -1, EffectList(j).Angle, 0, 1
                   End If
               End If
           'Update but not draw
           Else
               Engine_UpdateGrh EffectList(j).Grh, False
               If EffectList(j).Animated = 1 Then
                   If EffectList(j).Grh.Started = 0 Then Engine_Effect_Erase j
               End If
           End If
       End If

NextEffect:

   Next j

</vb>

Add - New rendering system

Open \Data\Head.dat.

At the end of the file, add:

<ini> 'The height is used in the calculation of the overall height of the character for finding the drawing order. 'This is simply just the height of the graphic - the Grh's height is not used because it is often not the 'exact height of the graphic. The height of the head and body are added together. If you have any other 'height contributors (such as large head-wear) I recommend you add height to that layer, too. Height=27 </ini>

Open \Data\Body.dat.

Find:

<ini> [2] </ini>

Before, add:

<ini> 'The height is used in the calculation of the overall height of the character for finding the drawing order. 'This is simply just the height of the graphic - the Grh's height is not used because it is often not the 'exact height of the graphic. The height of the head and body are added together. If you have any other 'height contributors (such as large head-wear) I recommend you add height to that layer, too. Height=34 </ini>

At the end of the file, add:

<ini> Height=34 </ini>

Open GameClient.vbp.

Find:

<vb> Private ChatVA() As TLVERTEX </vb>

After, add:

<vb> 'Render list - used to sort the list of graphics before rendering them Private Type RenderList

   X As Long
   Y As Long
   Z As Integer    'The value used to sort by (Y + Height)
   Grh As Long
   Light(0 To 3) As Long
   Center As Byte
   Shadow As Byte
   Angle As Single
   CharIndex As Long   'If it is a character, this is its index
   ParticleEffectIndex As Byte 'If it is a particle effect, this is its index

End Type </vb>

Find:

<vb> 'Bodies list Public Type BodyData

   Walk(1 To 8) As Grh
   Attack(1 To 8) As Grh
   HeadOffset As Position

End Type </vb>

Replace with:

<vb> 'Bodies list Public Type BodyData

   Walk(1 To 8) As Grh
   Attack(1 To 8) As Grh
   HeadOffset As Position
   Height As Long

End Type </vb>

Find:

<vb> Public Type HeadData

   Head(1 To 8) As Grh
   Blink(1 To 8) As Grh
   AgrHead(1 To 8) As Grh
   AgrBlink(1 To 8) As Grh

End Type </vb>

Replace with:

<vb> 'Heads list Public Type HeadData

   Head(1 To 8) As Grh
   Blink(1 To 8) As Grh
   AgrHead(1 To 8) As Grh
   AgrBlink(1 To 8) As Grh
   Height As Long

End Type </vb>

Find:

<vb>

       BodyData(LoopC).HeadOffset.Y = CLng(Var_Get(DataPath & "Body.dat", LoopC, "HeadOffsetY"))

</vb>

After, add:

<vb>

       BodyData(LoopC).Height = CLng(Var_Get(DataPath & "Body.dat", LoopC, "Height"))

</vb>

Find:

<vb>

   'Fill List
   For LoopC = 1 To NumHeads
       For i = 1 To 8
           Engine_Init_Grh HeadData(LoopC).Head(i), CLng(Var_Get(DataPath & "Head.dat", LoopC, i)), 0
           Engine_Init_Grh HeadData(LoopC).Blink(i), CLng(Var_Get(DataPath & "Head.dat", LoopC, "b" & i)), 0
           Engine_Init_Grh HeadData(LoopC).AgrHead(i), CLng(Var_Get(DataPath & "Head.dat", LoopC, "a" & i)), 0
           Engine_Init_Grh HeadData(LoopC).AgrBlink(i), CLng(Var_Get(DataPath & "Head.dat", LoopC, "ab" & i)), 0
       Next i
   Next LoopC

</vb>

Replace with:

<vb>

   'Fill List
   For LoopC = 1 To NumHeads
       For i = 1 To 8
           Engine_Init_Grh HeadData(LoopC).Head(i), CLng(Var_Get(DataPath & "Head.dat", LoopC, i)), 0
           Engine_Init_Grh HeadData(LoopC).Blink(i), CLng(Var_Get(DataPath & "Head.dat", LoopC, "b" & i)), 0
           Engine_Init_Grh HeadData(LoopC).AgrHead(i), CLng(Var_Get(DataPath & "Head.dat", LoopC, "a" & i)), 0
           Engine_Init_Grh HeadData(LoopC).AgrBlink(i), CLng(Var_Get(DataPath & "Head.dat", LoopC, "ab" & i)), 0
       Next i
       HeadData(LoopC).Height = CLng(Var_Get(DataPath & "Head.dat", LoopC, "Height"))
   Next LoopC

</vb>

Find:

<vb>

           Engine_Init_Grh HeadData(LoopC).AgrBlink(i), CLng(Var_Get(DataPath & "Head.dat", LoopC, "ab" & i)), 0

</vb>

After, add:

<vb>

           HeadData(LoopC).Height = CLng(Var_Get(DataPath & "Head.dat", LoopC, "Height"))

</vb>

Find:

<vb>

       'Grh has a delay, so just update the frame and then leave
       Engine_UpdateGrh Grh, LoopAnim

</vb>

Replace with:

<vb>

       'Grh has a delay, so just update the frame and then leave
       If Animate Then Engine_UpdateGrh Grh, LoopAnim

</vb>

At the end of the TileEngine module, add:

<vb> Private Sub Engine_AddToRenderList_Char(ByRef RenderList() As RenderList, ByRef RenderListSize As Long, ByRef Index As Long, _

   ByVal CharIndex As Long, ByVal X As Long, ByVal Y As Long, ByVal Z As Integer)

'***************************************************************** 'Adds a character to the RenderList() 'More info: http://www.vbgore.com/GameClient.TileEngine.Engine_AddToRenderList_Char '*****************************************************************

   'Increase the index
   Index = Index + 1
   
   'Increase array size if needed
   If Index > RenderListSize Then
       RenderListSize = RenderListSize + 50
       ReDim Preserve RenderList(1 To RenderListSize)
   End If
   
   'Add the components
   With RenderList(Index)
       .CharIndex = CharIndex
       .X = X
       .Y = Y
       .Z = Z
   End With
   

End Sub

Private Sub Engine_AddToRenderList_PE(ByRef RenderList() As RenderList, ByRef RenderListSize As Long, ByRef Index As Long, _

   ByVal ParticleEffectIndex As Long, ByVal Z As Integer)

'***************************************************************** 'Adds a Particle Effect to the RenderList() 'More info: http://www.vbgore.com/GameClient.TileEngine.Engine_AddToRenderList_PE '*****************************************************************

   'Increase the index
   Index = Index + 1
   
   'Increase array size if needed
   If Index > RenderListSize Then
       RenderListSize = RenderListSize + 50
       ReDim Preserve RenderList(1 To RenderListSize)
   End If
   
   'Add the components
   With RenderList(Index)
       .ParticleEffectIndex = ParticleEffectIndex
       .Z = Z
   End With
   

End Sub

Private Sub Engine_AddToRenderList_Grh(ByRef RenderList() As RenderList, ByRef RenderListSize As Long, ByRef Index As Long, _

   ByVal Grh As Long, ByVal X As Long, ByVal Y As Long, ByVal Z As Integer, ByVal Light0 As Long, ByVal Light1 As Long, ByVal Light2 As Long, _
   ByVal Light3 As Long, ByVal Angle As Single, ByVal Center As Byte, ByVal Shadow As Byte)

'***************************************************************** 'Adds a Grh (such as a tile, Grh-based effect, projectile, etc) to the RenderList() 'More info: http://www.vbgore.com/GameClient.TileEngine.Engine_AddToRenderList_Grh '*****************************************************************

   'Increase the index
   Index = Index + 1
   
   'Increase array size if needed
   If Index > RenderListSize Then
       RenderListSize = RenderListSize + 50
       ReDim Preserve RenderList(1 To RenderListSize)
   End If
   
   'Add the components
   With RenderList(Index)
       .Angle = Angle
       .Center = Center
       .Grh = Grh
       .Light(0) = Light0
       .Light(1) = Light1
       .Light(2) = Light2
       .Light(3) = Light3
       .Shadow = Shadow
       .X = X
       .Y = Y
       .Z = Z
   End With
   

End Sub </vb>

Find:

<vb>Sub Engine_Render_Screen(ByVal TileX As Integer, ByVal TileY As Integer, ByVal PixelOffsetX As Integer, ByVal PixelOffsetY As Integer) </vb>

Replace sub with:

<vb> Sub Engine_Render_Screen(ByVal TileX As Integer, ByVal TileY As Integer, ByVal PixelOffsetX As Integer, ByVal PixelOffsetY As Integer) '************************************************************ 'Draw current visible to scratch area based on TileX and TileY 'More info: http://www.vbgore.com/GameClient.TileEngine.Engine_Render_Screen '************************************************************ Dim RenderList() As RenderList Dim RenderListSize As Long Dim RenderListIndex As Long Dim FrameUseMotionBlur As Boolean 'Lets us know if this frame is using motion blur so we don't have to leave support for it on Dim LightOffset As Long Dim Y As Long 'Keeps track of where on map we are Dim X As Long Dim j As Long Dim Angle As Single Dim Layer As Byte Dim pList() As Integer Dim ValueList() As Integer Dim TempGrh As Grh

   'Check for valid positions
   If UserPos.X = 0 Then Exit Sub
   If UserPos.Y = 0 Then Exit Sub
   If UserCharIndex = 0 Then Exit Sub
   
   'Check if we need to update the graphics
   If TileX <> LastTileX Or TileY <> LastTileY Then
   
       'Figure out Ends and Starts of screen
       ScreenMinY = TileY - (WindowTileHeight \ 2)
       ScreenMaxY = TileY + (WindowTileHeight \ 2)
       ScreenMinX = TileX - (WindowTileWidth \ 2)
       ScreenMaxX = TileX + (WindowTileWidth \ 2)
       minY = ScreenMinY - TileBufferSize
       maxY = ScreenMaxY + TileBufferSize
       minX = ScreenMinX - TileBufferSize
       maxX = ScreenMaxX + TileBufferSize
       
       'Update the last position
       LastTileX = TileX
       LastTileY = TileY
       
       'Re-create the tile layers
       Engine_CreateTileLayers
       
   End If
   
   'Calculate the particle offset values
   'Do NOT move this any farther down in the module or you will get "jumps" as the left/top borders on particles
   ParticleOffsetX = (Engine_PixelPosX(ScreenMinX) - PixelOffsetX)
   ParticleOffsetY = (Engine_PixelPosY(ScreenMinY) - PixelOffsetY)
   'Check if we have the device
   If D3DDevice.TestCooperativeLevel <> D3D_OK Then
       
       'The worst we can do at this point is avoid an error we can't fix!
       On Error Resume Next
       
       'Do a loop while device is lost
       If D3DDevice.TestCooperativeLevel = D3DERR_DEVICELOST Then Exit Sub
           
       'Clear all the textures
       LastTexture = -999
       For j = 1 To NumGrhFiles
           Set SurfaceDB(j) = Nothing
           SurfaceTimer(j) = 0
           SurfaceSize(j).X = 0
           SurfaceSize(j).Y = 0
       Next j
       
       'Clear the D3DXSprite
       If AlternateRenderDefault = 1 Or AlternateRenderMap = 1 Or AlternateRenderText = 1 Then
           SpriteBegun = 0
           Set Sprite = Nothing
           Set Sprite = D3DX.CreateSprite(D3DDevice)
       End If
       
       Set DeviceBuffer = Nothing
       Set DeviceStencil = Nothing
       Set BlurStencil = Nothing
       Set BlurTexture = Nothing
       Set BlurSurf = Nothing
       
       'Make sure the scene is ended
       D3DDevice.EndScene
       
       'Reset the device
       D3DDevice.Reset D3DWindow
       
       Set DeviceBuffer = D3DDevice.GetRenderTarget
       Set DeviceStencil = D3DDevice.GetDepthStencilSurface
       Set BlurStencil = D3DDevice.CreateDepthStencilSurface(BufferWidth, BufferHeight, D3DFMT_D16, D3DMULTISAMPLE_NONE)
       Set BlurTexture = D3DX.CreateTexture(D3DDevice, BufferWidth, BufferHeight, 0, D3DUSAGE_RENDERTARGET, DispMode.Format, D3DPOOL_DEFAULT)
       Set BlurSurf = BlurTexture.GetSurfaceLevel(0)
       
       'Reset the render states
       Engine_Init_RenderStates
       
       'Load the particle textures
       Engine_Init_ParticleEngine True
       
       On Error GoTo 0
   Else
   
       'We have to bypass the present the first time through here or else we get an error
       If NotFirstRender Then
       
           'Close off the last sprite
           If SpriteBegun Then
               Sprite.End
               SpriteBegun = 0
               LastTexture = -101
           End If
           With D3DDevice
               
               'End the rendering (scene)
               .EndScene
               
               'Flip the backbuffer to the screen
               .Present ByVal 0, ByVal 0, 0, ByVal 0
               
           End With
               
       Else
       
           'Set NotFirstRender to True so we can start displaying
           NotFirstRender = True
           
       End If
   
   End If
   
   'Check if running (turn on motion blur)
   If UseMotionBlur Then
       If UserCharIndex > 0 Then
           If CharList(UserCharIndex).Moving = 1 And CharList(UserCharIndex).Running Then
               BlurIntensity = 45
           Else
               If BlurIntensity < 255 Then
                   BlurIntensity = BlurIntensity + (ElapsedTime * 0.8)
                   If BlurIntensity > 255 Then BlurIntensity = 255
               End If
           End If
       End If
   End If
   
   'Set the motion blur if needed
   If UseMotionBlur Then
       If BlurIntensity < 255 Or ZoomLevel > 0 Then
           FrameUseMotionBlur = True
           D3DDevice.SetRenderTarget BlurSurf, BlurStencil, 0
       End If
   End If
   'Begin the scene
   D3DDevice.BeginScene
   
   'Clear the screen with a solid color (to prevent artifacts)
   D3DDevice.Clear 0, ByVal 0, D3DCLEAR_TARGET, 0, 1#, 0
   
   '********************************************************
   '************ Update and draw layer 1 and 2 *************
   '********************************************************
   'Set the alternate rendering for the map on / off
   AlternateRender = AlternateRenderMap
   
   'Loop through the lower 2 layers
   For Layer = 1 To 2
       LightOffset = ((Layer - 1) * 4) + 1
       
       'Loop through all the tiles we know we will draw for this layer
       For j = 1 To TileLayer(Layer).NumTiles
           With TileLayer(Layer).Tile(j)
               Engine_UpdateGrh MapData(.TileX, .TileY).Graphic(Layer)
               
               'Check if we have to draw with a shadow or not (slighty changes because we have to animate on the shadow, not the main render)
               If MapData(.TileX, .TileY).Shadow(Layer) = 1 Then
                   Engine_Render_Grh MapData(.TileX, .TileY).Graphic(Layer), .PixelPosX + PixelOffsetX, .PixelPosY + PixelOffsetY, 0, 1, True, ShadowColor, ShadowColor, ShadowColor, ShadowColor, 1
                   Engine_Render_Grh MapData(.TileX, .TileY).Graphic(Layer), .PixelPosX + PixelOffsetX, .PixelPosY + PixelOffsetY, 0, 0, True, MapData(.TileX, .TileY).Light(LightOffset), MapData(.TileX, .TileY).Light(LightOffset + 1), MapData(.TileX, .TileY).Light(LightOffset + 2), MapData(.TileX, .TileY).Light(LightOffset + 3)
               Else
                   Engine_Render_Grh MapData(.TileX, .TileY).Graphic(Layer), .PixelPosX + PixelOffsetX, .PixelPosY + PixelOffsetY, 0, 1, True, MapData(.TileX, .TileY).Light(LightOffset), MapData(.TileX, .TileY).Light(LightOffset + 1), MapData(.TileX, .TileY).Light(LightOffset + 2), MapData(.TileX, .TileY).Light(LightOffset + 3)
               End If
               
           End With
       Next j
       
   Next Layer
   
   'Set the alternate rendering back to what it was before
   AlternateRender = AlternateRenderDefault
   '********************************************************
   '********** Update and draw the ground objects **********
   '********************************************************
   For j = 1 To LastObj
       If OBJList(j).Grh.GrhIndex Then
           X = Engine_PixelPosX(OBJList(j).Pos.X - minX) + PixelOffsetX + OBJList(j).Offset.X + TileBufferOffset
           Y = Engine_PixelPosY(OBJList(j).Pos.Y - minY) + PixelOffsetY + OBJList(j).Offset.Y + TileBufferOffset
           If Y >= -32 Then
               If Y <= (ScreenHeight + 32) Then
                   If X >= -32 Then
                       If X <= (ScreenWidth + 32) Then
                           Engine_UpdateGrh OBJList(j).Grh, True
                           With MapData(OBJList(j).Pos.X, OBJList(j).Pos.Y)
                               Engine_AddToRenderList_Grh RenderList(), RenderListSize, RenderListIndex, OBJList(j).Grh.GrhIndex, X, Y, _
                                   Y + GrhData(OBJList(j).Grh.GrhIndex).pixelHeight, .Light(1), .Light(2), .Light(3), .Light(4), 0, 1, 1
                           End With
                       End If
                   End If
               End If
           End If
       End If
   Next j
   
   '********************************************************
   '****** Start storing graphics in the RenderList() ******
   '****** so it can be sorted by their Y co-ordinate ******
   '********************************************************
   '************** Characters **************
   For j = 1 To LastChar
       If CharList(j).Active Then
           X = Engine_PixelPosX(CharList(j).Pos.X - minX) + PixelOffsetX + TileBufferOffset
           Y = Engine_PixelPosY(CharList(j).Pos.Y - minY) + PixelOffsetY + TileBufferOffset
           If Y >= -32 And Y <= (ScreenHeight + 32) And X >= -32 And X <= (ScreenWidth + 32) Then
               'Update the NPC chat and draw the character
               Engine_NPCChat_Update j
               Engine_AddToRenderList_Char RenderList(), RenderListSize, RenderListIndex, j, X, Y, _
                   Y + CharList(j).Body.Height + CharList(j).Head.Height
           Else
               'Update just the real position
               CharList(j).RealPos.X = X + CharList(j).MoveOffset.X
               CharList(j).RealPos.Y = Y + CharList(j).MoveOffset.Y
           End If
       End If
   Next j
   '************** Layer 3 to 5 **************
   AlternateRender = AlternateRenderMap
   For Layer = 3 To 5
       LightOffset = ((Layer - 1) * 4) + 1
       For j = 1 To TileLayer(Layer).NumTiles
           With TileLayer(Layer).Tile(j)
               Engine_UpdateGrh MapData(.TileX, .TileY).Graphic(Layer), True
               Engine_AddToRenderList_Grh RenderList(), RenderListSize, RenderListIndex, MapData(.TileX, .TileY).Graphic(Layer).GrhIndex, _
                   .PixelPosX + PixelOffsetX, .PixelPosY + PixelOffsetY, .PixelPosY + PixelOffsetY + _
                   GrhData(MapData(.TileX, .TileY).Graphic(Layer).GrhIndex).pixelHeight, MapData(.TileX, .TileY).Light(1), _
                   MapData(.TileX, .TileY).Light(2), MapData(.TileX, .TileY).Light(3), MapData(.TileX, .TileY).Light(4), _
                   0, 0, MapData(.TileX, .TileY).Shadow(Layer)
           End With
       Next j
   Next Layer
   AlternateRender = AlternateRenderDefault
   
   '************** Grh-Based (Non-Particle) Effects **************
   For j = 1 To LastEffect
       If EffectList(j).Grh.GrhIndex Then
           X = Engine_PixelPosX(EffectList(j).Pos.X - minX) + PixelOffsetX + TileBufferOffset
           Y = Engine_PixelPosY(EffectList(j).Pos.Y - minY) + PixelOffsetY + TileBufferOffset
           'Time ran out
           If EffectList(j).Time <> 0 And EffectList(j).Time < timeGetTime Then
               Engine_Effect_Erase j
           'Draw the effect
           ElseIf Y >= -32 And Y <= (ScreenHeight + 32) And X >= -32 And X <= (ScreenWidth + 32) Then
               Engine_UpdateGrh EffectList(j).Grh, False
               If EffectList(j).Animated = 1 Then
                   If EffectList(j).Grh.Started = 0 Then Engine_Effect_Erase j
               End If
               Engine_AddToRenderList_Grh RenderList(), RenderListSize, RenderListIndex, EffectList(j).Grh.GrhIndex, X, Y, _
                   Y + GrhData(EffectList(j).Grh.GrhIndex).pixelHeight, -1, -1, -1, -1, EffectList(j).Angle, 0, 1
           'Update but not draw
           Else
               Engine_UpdateGrh EffectList(j).Grh, False
               If EffectList(j).Animated = 1 Then
                   If EffectList(j).Grh.Started = 0 Then Engine_Effect_Erase j
               End If
           End If
       End If
   Next j
   
   '************** Projectiles **************
   'Check if it is close enough to the target to remove
   For j = 1 To LastProjectile
       If ProjectileList(j).Grh.GrhIndex Then
           If Abs(ProjectileList(j).X - ProjectileList(j).tX) < 20 Then
               If Abs(ProjectileList(j).Y - ProjectileList(j).tY) < 20 Then
                   Engine_Projectile_Erase j
               End If
           End If
       End If
   Next j
   
   For j = 1 To LastProjectile
       If ProjectileList(j).Grh.GrhIndex Then
           'Update the position
           Angle = DegreeToRadian * Engine_GetAngle(ProjectileList(j).X, ProjectileList(j).Y, ProjectileList(j).tX, ProjectileList(j).tY)
           ProjectileList(j).X = ProjectileList(j).X + (Sin(Angle) * ElapsedTime * 0.63)
           ProjectileList(j).Y = ProjectileList(j).Y - (Cos(Angle) * ElapsedTime * 0.63)
           'Update the rotation
           If ProjectileList(j).RotateSpeed > 0 Then
               ProjectileList(j).Rotate = ProjectileList(j).Rotate + (ProjectileList(j).RotateSpeed * ElapsedTime * 0.01)
               Do While ProjectileList(j).Rotate > 360
                   ProjectileList(j).Rotate = ProjectileList(j).Rotate - 360
               Loop
           End If
           'Draw if within range
           X = ((-minX - 1) * 32) + ProjectileList(j).X + PixelOffsetX + TileBufferOffset
           Y = ((-minY - 1) * 32) + ProjectileList(j).Y + PixelOffsetY + TileBufferOffset
           If Y >= -32 Then
               If Y <= (ScreenHeight + 32) Then
                   If X >= -32 Then
                       If X <= (ScreenWidth + 32) Then
                           Engine_UpdateGrh ProjectileList(j).Grh, True
                           Engine_AddToRenderList_Grh RenderList(), RenderListSize, RenderListIndex, ProjectileList(j).Grh.GrhIndex, _
                               X, Y, Y + GrhData(ProjectileList(j).Grh.GrhIndex).pixelHeight, -1, -1, -1, -1, ProjectileList(j).Rotate, 0, 1
                       End If
                   End If
               End If
           End If
       End If
   Next j
   
   '************** Blood Splatters **************
   'Seperate loop to remove the unused - I dont like removing while drawing
   For j = 1 To LastBlood
       If BloodList(j).Grh.GrhIndex Then
           If BloodList(j).Grh.Started = 0 Then Engine_Blood_Erase j
       End If
   Next j
   
   'Loop to do drawing
   For j = 1 To LastBlood
       If BloodList(j).Grh.GrhIndex Then
           X = Engine_PixelPosX(BloodList(j).Pos.X - minX) + PixelOffsetX + TileBufferOffset
           Y = Engine_PixelPosY(BloodList(j).Pos.Y - minY) + PixelOffsetY + TileBufferOffset
           If Y >= -32 Then
               If Y <= (ScreenHeight + 32) Then
                   If X >= -32 Then
                       If X <= (ScreenWidth + 32) Then
                           Engine_UpdateGrh BloodList(j).Grh, True
                           Engine_AddToRenderList_Grh RenderList(), RenderListSize, RenderListIndex, BloodList(j).Grh.GrhIndex, X, Y, _
                               Y + GrhData(BloodList(j).Grh.GrhIndex).pixelHeight, -1, -1, -1, -1, 0, 1, 0
                       End If
                   End If
               End If
           End If
       End If
   Next j
   
   '********************************************************
   '************ Sort the RenderList() by the Z ************
   '*********** value then draw then all in order **********
   '********************************************************
   If RenderListIndex > 0 Then
       
       'Size the array down
       ReDim Preserve RenderList(1 To RenderListIndex)
       RenderListSize = RenderListIndex
   
       'Sort the array
       ReDim ValueList(1 To RenderListIndex)
       ReDim pList(1 To RenderListIndex)
       For j = 1 To RenderListIndex
           ValueList(j) = RenderList(j).Z
           pList(j) = j
       Next j
       Engine_SortIntArray ValueList(), pList(), 1, RenderListIndex
       Erase ValueList()   'Erase the ValueList() - we don't need it anymore
   
       'Create a temporary Grh (one without any animations since we don't need to animate)
       TempGrh.FrameCounter = 1
       TempGrh.LastCount = 0
       TempGrh.Started = 1
       
       'Loop through all the graphics in the RenderList()
       For j = 1 To RenderListIndex
           If RenderList(pList(j)).CharIndex > 0 Then
           
               'Draw a character
               With RenderList(pList(j))
                   Engine_Render_Char .CharIndex, .X, .Y
               End With
               
           ElseIf RenderList(pList(j)).ParticleEffectIndex > 0 Then
           
               'Draw a particle effect
               Effect_Update RenderList(pList(j)).ParticleEffectIndex
               
           Else
           
               'Draw a grh
               With RenderList(pList(j))
                   TempGrh.GrhIndex = .Grh
                   If .Shadow Then Engine_Render_Grh TempGrh, .X, .Y, .Center, 0, False, ShadowColor, ShadowColor, ShadowColor, ShadowColor, 1, .Angle
                   Engine_Render_Grh TempGrh, .X, .Y, .Center, 0, False, .Light(0), .Light(1), .Light(2), .Light(3), 0, .Angle
               End With
               
           End If
       Next j
   
       'Done with the RenderList()
       Erase RenderList
   
   End If
   
   '********************************************************
   '********** Perform the rest of the rendering ***********
   '********************************************************
   '************** Layer 6 **************
   Layer = 6
   LightOffset = ((Layer - 1) * 4) + 1
   For j = 1 To TileLayer(Layer).NumTiles
       With TileLayer(Layer).Tile(j)
           Engine_UpdateGrh MapData(.TileX, .TileY).Graphic(Layer)
           If MapData(.TileX, .TileY).Shadow(Layer) = 1 Then
               Engine_Render_Grh MapData(.TileX, .TileY).Graphic(Layer), .PixelPosX + PixelOffsetX, .PixelPosY + PixelOffsetY, 0, 1, True, ShadowColor, ShadowColor, ShadowColor, ShadowColor, 1
               Engine_Render_Grh MapData(.TileX, .TileY).Graphic(Layer), .PixelPosX + PixelOffsetX, .PixelPosY + PixelOffsetY, 0, 0, True, MapData(.TileX, .TileY).Light(LightOffset), MapData(.TileX, .TileY).Light(LightOffset + 1), MapData(.TileX, .TileY).Light(LightOffset + 2), MapData(.TileX, .TileY).Light(LightOffset + 3)
           Else
               Engine_Render_Grh MapData(.TileX, .TileY).Graphic(Layer), .PixelPosX + PixelOffsetX, .PixelPosY + PixelOffsetY, 0, 1, True, MapData(.TileX, .TileY).Light(LightOffset), MapData(.TileX, .TileY).Light(LightOffset + 1), MapData(.TileX, .TileY).Light(LightOffset + 2), MapData(.TileX, .TileY).Light(LightOffset + 3)
           End If
       End With
   Next j
   '************** Update weather **************
   
   'Do the general weather updating
   Engine_Weather_Update
   '************** Chat bubbles **************
   'Loop through the chars
   For j = 1 To LastChar
       If CharList(j).Active Then
           If LenB(CharList(j).BubbleStr) <> 0 Then
               If CharList(j).RealPos.X > -25 Then
                   If CharList(j).RealPos.X < ScreenWidth + 25 Then
                       If CharList(j).RealPos.Y > -25 Then
                           If CharList(j).RealPos.Y < ScreenHeight + 25 Then
                               Engine_Render_ChatBubble CharList(j).BubbleStr, CharList(j).RealPos.X, CharList(j).RealPos.Y
                               CharList(j).BubbleTime = CharList(j).BubbleTime - ElapsedTime
                               If CharList(j).BubbleTime <= 0 Then
                                   CharList(j).BubbleTime = 0
                                   CharList(j).BubbleStr = vbNullString
                               End If
                           End If
                       End If
                   End If
               End If
           End If
       End If
   Next j
   '************** Damage text **************
   'Loop to do drawing
   For j = 1 To LastDamage
       If DamageList(j).Counter > 0 Then
           DamageList(j).Counter = DamageList(j).Counter - ElapsedTime
           X = (((DamageList(j).Pos.X - minX) - 1) * TilePixelWidth) + PixelOffsetX + TileBufferOffset
           Y = (((DamageList(j).Pos.Y - minY) - 1) * TilePixelHeight) + PixelOffsetY + TileBufferOffset
           If Y >= -32 Then
               If Y <= (ScreenHeight + 32) Then
                   If X >= -32 Then
                       If X <= (ScreenWidth + 32) Then
                           Engine_Render_Text Font_Default, DamageList(j).Value, X, Y, D3DColorARGB(255, 255, 0, 0)
                       End If
                   End If
               End If
           End If
           DamageList(j).Pos.Y = DamageList(j).Pos.Y - (ElapsedTime * 0.001)
       End If
   Next j
   'Seperate loop to remove the unused - I dont like removing while drawing
   For j = 1 To LastDamage
       If DamageList(j).Width Then
           If DamageList(j).Counter <= 0 Then Engine_Damage_Erase j
       End If
   Next j
   '************** Misc Rendering **************
   'Update and render particle effects
   Effect_UpdateAll
   'Clear the shift-related variables
   LastOffsetX = ParticleOffsetX
   LastOffsetY = ParticleOffsetY
   'Render the GUI
   Engine_Render_GUI
   
   '************** Mini-map **************
   Const tS As Single = 3  'Size of the mini-map dots
   
   'Check if the mini-map is being shownquit
   If ShowMiniMap Then
   
       'Make sure the mini-map vertex buffer is valid
       If MiniMapVBSize > 0 Then
           
           'Clear the texture
           LastTexture = 0
           D3DDevice.SetTexture 0, Nothing
           
           'Draw the map outline
           D3DDevice.SetStreamSource 0, MiniMapVB, FVF_Size
           D3DDevice.DrawPrimitive D3DPT_TRIANGLELIST, 0, MiniMapVBSize \ 3
 
           'Draw the characters
           For X = 1 To LastChar
               If CharList(X).Active Then
               
                   'The user's character
                   If X = UserCharIndex Then
                       j = D3DColorARGB(200, 0, 255, 0)    'User's character
                       Engine_Render_Rectangle CharList(X).Pos.X * tS, CharList(X).Pos.Y * tS, tS, tS, 1, 1, 1, 1, 1, 1, 0, 0, j, j, j, j, , False
                       GoTo NextChar
                   End If
                   
                   'Part of the user's group or one of the user's slaves
                   If CharList(X).CharType = ClientCharType_Grouped Or (CharList(X).CharType = ClientCharType_Slave And UserCharIndex = CharList(X).OwnerChar) Then
                       If X <> UserCharIndex Then
                           j = D3DColorARGB(200, 100, 220, 100)    'PC (grouped) or the user's slave
                           Engine_Render_Rectangle CharList(X).Pos.X * tS, CharList(X).Pos.Y * tS, tS, tS, 1, 1, 1, 1, 1, 1, 0, 0, j, j, j, j, , False
                           GoTo NextChar
                       End If
                   End If
               
                   'Check if the character is in screen, since the only characters drawn outside of the screen are grouped characters
                   If CharList(X).Pos.X > ScreenMinX Then
                       If CharList(X).Pos.X < ScreenMaxX Then
                           If CharList(X).Pos.Y > ScreenMinY Then
                               If CharList(X).Pos.Y < ScreenMaxY Then
                                   
                                   'Character is a PC
                                   If CharList(X).CharType = ClientCharType_PC Then
                                       j = D3DColorARGB(200, 0, 255, 255)  'PC (not grouped)
                                   'Character is a NPC
                                   Else
                                       j = D3DColorARGB(200, 0, 150, 150)  'NPC
                                   End If
                                   
                                   'Any character but one part of the user's group
                                   Engine_Render_Rectangle CharList(X).Pos.X * tS, CharList(X).Pos.Y * tS, tS, tS, 1, 1, 1, 1, 1, 1, 0, 0, j, j, j, j, , False
                               End If
                           End If
                       End If
                   End If
                   
               End If
               

NextChar:

           Next X
           
       End If
       
   End If
   'Show FPS
   Engine_Render_Text Font_Default, "FPS: " & FPS, ScreenWidth - 80, 2, -1
   'Check if using motion blur / zooming
   If UseMotionBlur Then
       If FrameUseMotionBlur Then
           With D3DDevice
           
               'Perform the zooming calculations
               ' * 1.333... maintains the aspect ratio
               ' ... / 1024 is to factor in the buffer size
               BlurTA(0).tU = ZoomLevel * 1.333333333
               BlurTA(0).tV = ZoomLevel
               BlurTA(1).tU = ((ScreenWidth + 1) / 1024) - (ZoomLevel * 1.333333333)
               BlurTA(1).tV = ZoomLevel
               BlurTA(2).tU = ZoomLevel * 1.333333333
               BlurTA(2).tV = ((ScreenHeight + 1) / 1024) - ZoomLevel
               BlurTA(3).tU = BlurTA(1).tU
               BlurTA(3).tV = BlurTA(2).tV
               
               'Draw what we have drawn thus far since the last .Clear
               LastTexture = -100
               .SetRenderTarget DeviceBuffer, DeviceStencil, 0
               .SetTexture 0, BlurTexture
               .SetRenderState D3DRS_TEXTUREFACTOR, D3DColorARGB(BlurIntensity, 255, 255, 255)
               .SetTextureStageState 0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR
               .DrawPrimitiveUP D3DPT_TRIANGLESTRIP, 2, BlurTA(0), FVF_Size
               .SetTextureStageState 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE
           
           End With
       End If
   End If

End Sub </vb>

Find:

<vb> Sub Effect_UpdateAll() </vb>

Replace sub with:

<vb> Sub Effect_UpdateAll() '***************************************************************** 'Updates all of the effects and renders them - a wrapper for Effect_Update to update all effects 'More info: http://www.vbgore.com/CommonCode.Particles.Effect_UpdateAll '***************************************************************** Dim LoopC As Long

   'Make sure we have effects
   If NumEffects = 0 Then Exit Sub
   'Update every effect in use
   For LoopC = 1 To NumEffects
       If LoopC <> WeatherEffectIndex Then Effect_Update LoopC
   Next

End Sub

Sub Effect_Update(ByVal EffectIndex As Byte) '***************************************************************** 'Updates an effect and renders it 'More info: http://www.vbgore.com/CommonCode.Particles.Effect_Update '*****************************************************************

   'Make sure the effect is in use
   If Effect(EffectIndex).Used Then
           
       'Set the render state for the particle effects
       D3DDevice.SetRenderState D3DRS_DESTBLEND, D3DBLEND_ONE
   
       'Update the effect position if the screen has moved
       Effect_UpdateOffset EffectIndex
   
       'Update the effect position if it is binded
       Effect_UpdateBinding EffectIndex
   
       'Find out which effect is selected, then update it
       If Effect(EffectIndex).EffectNum = EffectNum_Fire Then Effect_Fire_Update EffectIndex
       If Effect(EffectIndex).EffectNum = EffectNum_Snow Then Effect_Snow_Update EffectIndex
       If Effect(EffectIndex).EffectNum = EffectNum_Heal Then Effect_Heal_Update EffectIndex
       If Effect(EffectIndex).EffectNum = EffectNum_Bless Then Effect_Bless_Update EffectIndex
       If Effect(EffectIndex).EffectNum = EffectNum_Protection Then Effect_Protection_Update EffectIndex
       If Effect(EffectIndex).EffectNum = EffectNum_Strengthen Then Effect_Strengthen_Update EffectIndex
       If Effect(EffectIndex).EffectNum = EffectNum_Rain Then Effect_Rain_Update EffectIndex
       If Effect(EffectIndex).EffectNum = EffectNum_EquationTemplate Then Effect_EquationTemplate_Update EffectIndex
       If Effect(EffectIndex).EffectNum = EffectNum_Waterfall Then Effect_Waterfall_Update EffectIndex
       If Effect(EffectIndex).EffectNum = EffectNum_Summon Then Effect_Summon_Update EffectIndex
       
       'Render the effect
       Effect_Render EffectIndex, False
               
       'Set the render state back for normal rendering
       D3DDevice.SetRenderState D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA
       
   End If

End Sub </vb>

Open EditorMap.vbp.

Find:

<vb> Public InfoLayer As InfoLayer </vb>

After, add:

<vb> 'Render list - used to sort the list of graphics before rendering them Private Type RenderList

   X As Long
   Y As Long
   Z As Integer    'The value used to sort by (Y + Height)
   Grh As Long
   Light(0 To 3) As Long
   Center As Byte
   Shadow As Byte
   Angle As Single
   CharIndex As Long   'If it is a character, this is its index
   ParticleEffectIndex As Byte 'If it is a particle effect, this is its index

End Type </vb>

At the end of the TileEngine module, add:

<vb> Private Sub Engine_AddToRenderList_Char(ByRef RenderList() As RenderList, ByRef RenderListSize As Long, ByRef Index As Long, _

   ByVal CharIndex As Long, ByVal X As Long, ByVal Y As Long, ByVal Z As Integer)

'***************************************************************** 'Adds a character to the RenderList() 'More info: http://www.vbgore.com/GameClient.TileEngine.Engine_AddToRenderList_Char '*****************************************************************

   'Increase the index
   Index = Index + 1
   
   'Increase array size if needed
   If Index > RenderListSize Then
       RenderListSize = RenderListSize + 50
       ReDim Preserve RenderList(1 To RenderListSize)
   End If
   
   'Add the components
   With RenderList(Index)
       .CharIndex = CharIndex
       .X = X
       .Y = Y
       .Z = Z
   End With
   

End Sub

Private Sub Engine_AddToRenderList_PE(ByRef RenderList() As RenderList, ByRef RenderListSize As Long, ByRef Index As Long, _

   ByVal ParticleEffectIndex As Long, ByVal Z As Integer)

'***************************************************************** 'Adds a Particle Effect to the RenderList() 'More info: http://www.vbgore.com/GameClient.TileEngine.Engine_AddToRenderList_PE '*****************************************************************

   'Increase the index
   Index = Index + 1
   
   'Increase array size if needed
   If Index > RenderListSize Then
       RenderListSize = RenderListSize + 50
       ReDim Preserve RenderList(1 To RenderListSize)
   End If
   
   'Add the components
   With RenderList(Index)
       .ParticleEffectIndex = ParticleEffectIndex
       .Z = Z
   End With
   

End Sub

Private Sub Engine_AddToRenderList_Grh(ByRef RenderList() As RenderList, ByRef RenderListSize As Long, ByRef Index As Long, _

   ByVal Grh As Long, ByVal X As Long, ByVal Y As Long, ByVal Z As Integer, ByVal Light0 As Long, ByVal Light1 As Long, ByVal Light2 As Long, _
   ByVal Light3 As Long, ByVal Angle As Single, ByVal Center As Byte, ByVal Shadow As Byte)

'***************************************************************** 'Adds a Grh (such as a tile, Grh-based effect, projectile, etc) to the RenderList() 'More info: http://www.vbgore.com/GameClient.TileEngine.Engine_AddToRenderList_Grh '*****************************************************************

   'Increase the index
   Index = Index + 1
   
   'Increase array size if needed
   If Index > RenderListSize Then
       RenderListSize = RenderListSize + 50
       ReDim Preserve RenderList(1 To RenderListSize)
   End If
   
   'Add the components
   With RenderList(Index)
       .Angle = Angle
       .Center = Center
       .Grh = Grh
       .Light(0) = Light0
       .Light(1) = Light1
       .Light(2) = Light2
       .Light(3) = Light3
       .Shadow = Shadow
       .X = X
       .Y = Y
       .Z = Z
   End With
   

End Sub </vb>

Find:

<vb>

   If TileBufferSize < 2 Then TileBufferSize = 2

</vb>

After, add:

<vb>

   'Cache the TileBufferOffset value to prevent always having to calculate it on the fly
   TileBufferOffset = ((10 - TileBufferSize) * 32)

</vb>

Find:

<vb> Public TileBufferSize As Integer </vb>

After, add:

<vb> Public TileBufferOffset As Long 'Used to calculate offset value in certain cases </vb>

Find:

<vb>

       BodyData(LoopC).HeadOffset.Y = CLng(Var_Get(DataPath & "Body.dat", Str$(LoopC), "HeadOffsetY"))

</vb>

After, add:

<vb>

       BodyData(LoopC).Height = CLng(Var_Get(DataPath & "Body.dat", LoopC, "Height"))

</vb>

Find:

<vb>

   'Fill List
   For LoopC = 1 To NumHeads
       For i = 1 To 8
           Engine_Init_Grh HeadData(LoopC).Head(i), CLng(Var_Get(DataPath & "Head.dat", Str$(LoopC), Str(i))), 0
           Engine_Init_Grh HeadData(LoopC).Blink(i), CLng(Var_Get(DataPath & "Head.dat", Str$(LoopC), "b" & i)), 0
           Engine_Init_Grh HeadData(LoopC).AgrHead(i), CLng(Var_Get(DataPath & "Head.dat", Str$(LoopC), "a" & i)), 0
           Engine_Init_Grh HeadData(LoopC).AgrBlink(i), CLng(Var_Get(DataPath & "Head.dat", Str$(LoopC), "ab" & i)), 0
       Next i
   Next LoopC

</vb>

Replace with:

<vb>

   'Fill List
   For LoopC = 1 To NumHeads
       For i = 1 To 8
           Engine_Init_Grh HeadData(LoopC).Head(i), CLng(Var_Get(DataPath & "Head.dat", Str$(LoopC), Str(i))), 0
           Engine_Init_Grh HeadData(LoopC).Blink(i), CLng(Var_Get(DataPath & "Head.dat", Str$(LoopC), "b" & i)), 0
           Engine_Init_Grh HeadData(LoopC).AgrHead(i), CLng(Var_Get(DataPath & "Head.dat", Str$(LoopC), "a" & i)), 0
           Engine_Init_Grh HeadData(LoopC).AgrBlink(i), CLng(Var_Get(DataPath & "Head.dat", Str$(LoopC), "ab" & i)), 0
       Next i
       HeadData(LoopC).Height = CLng(Var_Get(DataPath & "Head.dat", LoopC, "Height"))
   Next LoopC

</vb>

Find:

<vb> 'Bodies list Public Type BodyData

   Walk(1 To 8) As Grh
   Attack(1 To 8) As Grh
   HeadOffset As Position

End Type </vb>

Replace with:

<vb> 'Bodies list Public Type BodyData

   Walk(1 To 8) As Grh
   Attack(1 To 8) As Grh
   HeadOffset As Position
   Height As Long

End Type </vb>

Find:

<vb> 'Heads list Public Type HeadData

   Head(1 To 8) As Grh
   Blink(1 To 8) As Grh
   AgrHead(1 To 8) As Grh
   AgrBlink(1 To 8) As Grh

End Type </vb>

Replace with:

<vb> 'Heads list Public Type HeadData

   Head(1 To 8) As Grh
   Blink(1 To 8) As Grh
   AgrHead(1 To 8) As Grh
   AgrBlink(1 To 8) As Grh
   Height As Long

End Type </vb>

Find:

<vb> Public Sub Engine_SortIntArray(TheArray() As Integer, TheIndex() As Integer, ByVal LowerBound As Integer, ByVal UpperBound As Integer) </vb>

Replace sub with:

<vb> Public Sub Engine_SortIntArray(TheArray() As Integer, TheIndex() As Integer, ByVal LowerBound As Integer, ByVal UpperBound As Integer) '***************************************************************** 'Sort an array of integers 'More info: http://www.vbgore.com/GameClient.TileEngine.Engine_SortIntArray '***************************************************************** Dim indxt As Long 'Stored index Dim swp As Integer 'Swap variable Dim i As Integer 'Subarray Low Scan Index Dim j As Integer 'Subarray High Scan Index

   For j = LowerBound + 1 To UpperBound
       indxt = TheIndex(j)
       swp = TheArray(indxt)
       For i = j - 1 To LowerBound Step -1
           If TheArray(TheIndex(i)) <= swp Then Exit For
           TheIndex(i + 1) = TheIndex(i)
       Next i
       TheIndex(i + 1) = indxt
   Next j

End Sub </vb>

Find:

<vb> Sub Engine_Render_Screen(ByVal TileX As Integer, ByVal TileY As Integer, ByVal PixelOffsetX As Integer, ByVal PixelOffsetY As Integer) </vb>

Replace sub with:

<vb> Sub Engine_Render_Screen(ByVal TileX As Integer, ByVal TileY As Integer, ByVal PixelOffsetX As Integer, ByVal PixelOffsetY As Integer)

'*********************************************** 'Draw current visible to scratch area based on TileX and TileY '*********************************************** Dim LightOffset As Long Dim RenderList() As RenderList Dim RenderListSize As Long Dim RenderListIndex As Long Dim ScreenX As Integer 'Keeps track of where to place tile on screen Dim ScreenY As Integer Dim Grh As Grh Dim x2 As Long Dim y2 As Long Dim Y As Long 'Keeps track of where on map we are Dim X As Long Dim j As Long Dim Layer As Byte Dim pList() As Integer Dim ValueList() As Integer Dim TempGrh As Grh

   minXOffset = 0
   minYOffset = 0
   'Check if we need to update the graphics
   If TileX <> LastTileX Or TileY <> LastTileY Then
   
       'Figure out Ends and Starts of screen
       ScreenMinY = TileY - (WindowTileHeight \ 2)
       ScreenMaxY = TileY + (WindowTileHeight \ 2)
       ScreenMinX = TileX - (WindowTileWidth \ 2)
       ScreenMaxX = TileX + (WindowTileWidth \ 2)
       minY = ScreenMinY - TileBufferSize
       maxY = ScreenMaxY + TileBufferSize
       minX = ScreenMinX - TileBufferSize
       maxX = ScreenMaxX + TileBufferSize
       
       'Update the last position
       LastTileX = TileX
       LastTileY = TileY
       
       'Re-create the tile layers
       Engine_CreateTileLayers
       
   End If
   'Calculate the particle offset values
   'Do NOT move this any farther down in the module or you will get "jumps" as the left/top borders on particles
   ParticleOffsetX = (Engine_PixelPosX(ScreenMinX) - PixelOffsetX) * 1
   ParticleOffsetY = (Engine_PixelPosY(ScreenMinY) - PixelOffsetY) * 1
   
   'Check if we have the device
   If Not Engine_ValidateDevice Then Exit Sub
   
   Engine_EndScreenRender
   
   D3DDevice.Clear 0, ByVal 0, D3DCLEAR_TARGET, 0, 1#, 0
   D3DDevice.BeginScene
   
   DrawingGameScreen = True
   
   '********************************************************
   '************ Update and draw layer 1 and 2 *************
   '********************************************************
   'Loop through the lower 2 layers
   For Layer = 1 To 2
       LightOffset = ((Layer - 1) * 4) + 1
       
       'Loop through all the tiles we know we will draw for this layer
       For j = 1 To TileLayer(Layer).NumTiles
           With TileLayer(Layer).Tile(j)
               Engine_UpdateGrh MapData(.TileX, .TileY).Graphic(Layer)
               
               'Check if we have to draw with a shadow or not (slighty changes because we have to animate on the shadow, not the main render)
               If MapData(.TileX, .TileY).Shadow(Layer) = 1 Then
                   Engine_Render_Grh MapData(.TileX, .TileY).Graphic(Layer), .PixelPosX + PixelOffsetX, .PixelPosY + PixelOffsetY, 0, 1, True, ShadowColor, ShadowColor, ShadowColor, ShadowColor, 1
                   Engine_Render_Grh MapData(.TileX, .TileY).Graphic(Layer), .PixelPosX + PixelOffsetX, .PixelPosY + PixelOffsetY, 0, 0, True, MapData(.TileX, .TileY).Light(LightOffset), MapData(.TileX, .TileY).Light(LightOffset + 1), MapData(.TileX, .TileY).Light(LightOffset + 2), MapData(.TileX, .TileY).Light(LightOffset + 3)
               Else
                   Engine_Render_Grh MapData(.TileX, .TileY).Graphic(Layer), .PixelPosX + PixelOffsetX, .PixelPosY + PixelOffsetY, 0, 1, True, MapData(.TileX, .TileY).Light(LightOffset), MapData(.TileX, .TileY).Light(LightOffset + 1), MapData(.TileX, .TileY).Light(LightOffset + 2), MapData(.TileX, .TileY).Light(LightOffset + 3)
               End If
               
           End With
       Next j
       
       'Tile preview
       If frmSetTile.Visible Then
           If DrawLayer = Layer Then
               Grh.FrameCounter = 1
               Grh.GrhIndex = Val(frmSetTile.GrhTxt.Text)
               j = D3DColorARGB(200, 255, 255, 255)
               If frmSetTile.ShadowChk.Value = 1 Then
                   If Val(frmSetTile.ShadowTxt.Text) = 1 Then Engine_Render_Grh Grh, Engine_PixelPosX(minXOffset + (HovertX - minX)) + TileBufferOffset + PixelOffsetX, Engine_PixelPosY(minYOffset + (HovertY - minY)) + TileBufferOffset + PixelOffsetY, 0, 0, False, ShadowColor, ShadowColor, ShadowColor, ShadowColor, 1
               End If
               Engine_Render_Grh Grh, Engine_PixelPosX(minXOffset + (HovertX - minX)) + TileBufferOffset + PixelOffsetX, Engine_PixelPosY(minYOffset + (HovertY - minY)) + TileBufferOffset + PixelOffsetY, 0, 0, False, j, j, j, j, 0
           End If
       End If
       
   Next Layer
   
   '********************************************************
   '****** Start storing graphics in the RenderList() ******
   '****** so it can be sorted by their Y co-ordinate ******
   '********************************************************
   '************** Characters **************
   For j = 1 To LastChar
       If CharList(j).Active Then
           X = Engine_PixelPosX(CharList(j).Pos.X - minX) + PixelOffsetX + TileBufferOffset
           Y = Engine_PixelPosY(CharList(j).Pos.Y - minY) + PixelOffsetY + TileBufferOffset
           If Y >= -32 And Y <= (ScreenHeight + 32) And X >= -32 And X <= (ScreenWidth + 32) Then
               'Update the NPC chat and draw the character
               'Engine_NPCChat_Update j
               Engine_AddToRenderList_Char RenderList(), RenderListSize, RenderListIndex, j, X, Y, _
                   Y + CharList(j).Body.Height + CharList(j).Head.Height
           Else
               'Update just the real position
               CharList(j).RealPos.X = X + CharList(j).MoveOffset.X
               CharList(j).RealPos.Y = Y + CharList(j).MoveOffset.Y
           End If
       End If
   Next j
   '************** Layer 3 to 5 **************
   For Layer = 3 To 5
       LightOffset = ((Layer - 1) * 4) + 1
       For j = 1 To TileLayer(Layer).NumTiles
           With TileLayer(Layer).Tile(j)
               Engine_UpdateGrh MapData(.TileX, .TileY).Graphic(Layer), True
               Engine_AddToRenderList_Grh RenderList(), RenderListSize, RenderListIndex, MapData(.TileX, .TileY).Graphic(Layer).GrhIndex, _
                   .PixelPosX + PixelOffsetX, .PixelPosY + PixelOffsetY, .PixelPosY + PixelOffsetY + _
                   GrhData(MapData(.TileX, .TileY).Graphic(Layer).GrhIndex).pixelHeight, MapData(.TileX, .TileY).Light(1), _
                   MapData(.TileX, .TileY).Light(2), MapData(.TileX, .TileY).Light(3), MapData(.TileX, .TileY).Light(4), _
                   0, 0, MapData(.TileX, .TileY).Shadow(Layer)
           End With
       Next j
   Next Layer
   
   '************** Tile preview **************
   If frmSetTile.Visible Then
       j = D3DColorARGB(200, 255, 255, 255)
       If Val(frmSetTile.GrhTxt.Text) > 0 Then
           If Val(frmSetTile.GrhTxt.Text) < NumGrhs Then
               Engine_AddToRenderList_Grh RenderList, RenderListSize, RenderListIndex, Val(frmSetTile.GrhTxt.Text), _
                   Engine_PixelPosX(minXOffset + (HovertX - minX)) + TileBufferOffset + PixelOffsetX, Engine_PixelPosY(minYOffset + (HovertY - minY)) + TileBufferOffset + PixelOffsetY, _
                   Engine_PixelPosY(minYOffset + (HovertY - minY)) + TileBufferOffset + PixelOffsetY + GrhData(Val(frmSetTile.GrhTxt.Text)).pixelHeight, _
                   j, j, j, j, 0, 0, 0
           End If
       End If
   End If
   
   '********************************************************
   '************ Sort the RenderList() by the Z ************
   '*********** value then draw then all in order **********
   '********************************************************
   If RenderListIndex > 0 Then
       'Size the array down
       ReDim Preserve RenderList(1 To RenderListIndex)
       RenderListSize = RenderListIndex
   
       'Sort the array
       ReDim ValueList(1 To RenderListIndex)
       ReDim pList(1 To RenderListIndex)
       For j = 1 To RenderListIndex
           ValueList(j) = RenderList(j).Z
           pList(j) = j
       Next j
       Engine_SortIntArray ValueList(), pList(), 1, RenderListIndex
       Erase ValueList()   'Erase the ValueList() - we don't need it anymore
   
       'Create a temporary Grh (one without any animations since we don't need to animate)
       TempGrh.FrameCounter = 1
       TempGrh.LastCount = 0
       TempGrh.Started = 1
       
       'Loop through all the graphics in the RenderList()
       For j = 1 To RenderListIndex
           If RenderList(pList(j)).CharIndex > 0 Then
           
               'Draw a character
               With RenderList(pList(j))
                   Engine_Render_Char .CharIndex, .X, .Y
               End With
               
           ElseIf RenderList(pList(j)).ParticleEffectIndex > 0 Then
           
               'Draw a particle effect
               Effect_Update RenderList(pList(j)).ParticleEffectIndex
               
           Else
           
               'Draw a grh
               With RenderList(pList(j))
                   TempGrh.GrhIndex = .Grh
                   If .Shadow Then Engine_Render_Grh TempGrh, .X, .Y, .Center, 0, False, ShadowColor, ShadowColor, ShadowColor, ShadowColor, 1, .Angle
                   Engine_Render_Grh TempGrh, .X, .Y, .Center, 0, False, .Light(0), .Light(1), .Light(2), .Light(3), 0, .Angle
               End With
               
           End If
       Next j
   
       'Done with the RenderList()
       Erase RenderList
   End If
   
   '********************************************************
   '********** Perform the rest of the rendering ***********
   '********************************************************
   
   '************** Layer 6 **************
   Layer = 6
   LightOffset = ((Layer - 1) * 4) + 1
   For j = 1 To TileLayer(Layer).NumTiles
       With TileLayer(Layer).Tile(j)
           Engine_UpdateGrh MapData(.TileX, .TileY).Graphic(Layer)
           If MapData(.TileX, .TileY).Shadow(Layer) = 1 Then
               Engine_Render_Grh MapData(.TileX, .TileY).Graphic(Layer), .PixelPosX + PixelOffsetX, .PixelPosY + PixelOffsetY, 0, 1, True, ShadowColor, ShadowColor, ShadowColor, ShadowColor, 1
               Engine_Render_Grh MapData(.TileX, .TileY).Graphic(Layer), .PixelPosX + PixelOffsetX, .PixelPosY + PixelOffsetY, 0, 0, True, MapData(.TileX, .TileY).Light(LightOffset), MapData(.TileX, .TileY).Light(LightOffset + 1), MapData(.TileX, .TileY).Light(LightOffset + 2), MapData(.TileX, .TileY).Light(LightOffset + 3)
           Else
               Engine_Render_Grh MapData(.TileX, .TileY).Graphic(Layer), .PixelPosX + PixelOffsetX, .PixelPosY + PixelOffsetY, 0, 1, True, MapData(.TileX, .TileY).Light(LightOffset), MapData(.TileX, .TileY).Light(LightOffset + 1), MapData(.TileX, .TileY).Light(LightOffset + 2), MapData(.TileX, .TileY).Light(LightOffset + 3)
           End If
       End With
   Next j
   
   '************** Info **************
   If InfoChkValue = 1 Then
       For X = 1 To InfoLayer.NumTiles
           For Y = 1 To InfoLayer.Tile(X).NumGrhs
               With InfoLayer.Tile(X).Grh(Y)
                   Engine_Render_Grh .Grh, .PixelPosX + PixelOffsetX, .PixelPosY + PixelOffsetY, 0, 0, False
               End With
           Next Y
       Next X
   End If
   
   '************** Grid **************
   If GridChkValue = 1 Then
       j = D3DColorARGB(25, 255, 255, 255)
       Grh.GrhIndex = 2
       Grh.FrameCounter = 1
       Grh.Started = 0
       ScreenY = minYOffset
       For Y = minY To maxY
           ScreenX = minXOffset
           For X = minX To maxX
               Engine_Render_Grh Grh, Engine_PixelPosX(ScreenX) + PixelOffsetX + TileBufferOffset, Engine_PixelPosY(ScreenY) + PixelOffsetY + TileBufferOffset, 0, 0, , j, j, j, j
               ScreenX = ScreenX + 1
           Next X
           ScreenY = ScreenY + 1
       Next Y
   End If
   '************** Update weather **************
   If WeatherChkValue = 1 Then
   
       'Make sure the right weather is going on
       Engine_Weather_Update
       
   Else
   
       If WeatherEffectIndex > 0 Then
           If Effect(WeatherEffectIndex).Used Then Effect_Kill WeatherEffectIndex
       End If
       
       'Change the light of all the tiles back
       If FlashTimer > 0 Then
           For X = 1 To MapInfo.Width
               For Y = 1 To MapInfo.Height
                   For x2 = 1 To 4
                       MapData(X, Y).Light(x2) = SaveLightBuffer(X, Y).Light(x2)
                   Next x2
               Next Y
           Next X
           FlashTimer = 0
       End If
       
   End If
   
   '************** Misc Rendering **************
   'Update and render particle effects
   Effect_UpdateAll
   'Clear the shift-related variables
   LastOffsetX = ParticleOffsetX
   LastOffsetY = ParticleOffsetY
   
   '************** Mini-map **************
   Const tS As Single = 2  'Size of the mini-map dots
   
   If ShowMiniMap Then
   
       'Draw the map outline
       For X = 1 To NumMiniMapTiles
           Engine_Render_Rectangle MiniMapTile(X).X * tS, MiniMapTile(X).Y * tS, tS, tS, 1, 1, 1, 1, 1, 1, 0, 0, MiniMapTile(X).Color, MiniMapTile(X).Color, MiniMapTile(X).Color, MiniMapTile(X).Color
       Next X
       
       'Draw the characters
       j = D3DColorARGB(200, 0, 255, 255)
       For X = 1 To LastChar
           Engine_Render_Rectangle CharList(X).Pos.X * tS, CharList(X).Pos.Y * tS, tS, tS, 1, 1, 1, 1, 1, 1, 0, 0, j, j, j, j
       Next X
       
       'Draw the position indicator
       j = D3DColorARGB(200, 0, 255, 0)
       Engine_Render_Rectangle UserPos.X * tS, UserPos.Y * tS, tS, tS, 1, 1, 1, 1, 1, 1, 0, 0, j, j, j, j
       
   End If

End Sub </vb>

Personal tools