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

Contents

[edit] 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.

[edit] 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."

[edit] 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.

[edit] Fix - Animations

Open GameClient.vbp.

In module TileEngine, add:

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

Find:

                            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

Replace with:

                            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

Find:

                                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

Replace with:

                                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

Find:

                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)

Replace with:

                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)

Find:

                        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

Replace with:

                        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

Find:

                            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

Replace with:

                            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

Open EditorMap.vbp.

In module TileEngine, add:

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

Find:

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

Replace with:

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

[edit] Fix - Effect rendering

Open GameClient.vbp.

Find:

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

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

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

[edit] Add - New rendering system

Open \Data\Head.dat.

At the end of the file, add:

'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

Open \Data\Body.dat.

Find:

[2]

Before, add:

'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

At the end of the file, add:

Height=34

Open GameClient.vbp.

Find:

Private ChatVA() As TLVERTEX

After, add:

'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

Find:

'Bodies list
Public Type BodyData
    Walk(1 To 8) As Grh
    Attack(1 To 8) As Grh
    HeadOffset As Position
End Type

Replace with:

'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

Find:

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

Replace with:

'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

Find:

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

After, add:

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

Find:

    '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

Replace with:

    '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

Find:

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

After, add:

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

Find:

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

Replace with:

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

At the end of the TileEngine module, add:

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

Find:

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

Replace sub with:

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

Find:

Sub Effect_UpdateAll()

Replace sub with:

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

Open EditorMap.vbp.

Find:

Public InfoLayer As InfoLayer

After, add:

'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

At the end of the TileEngine module, add:

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

Find:

    If TileBufferSize < 2 Then TileBufferSize = 2

After, add:

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

Find:

Public TileBufferSize As Integer

After, add:

Public TileBufferOffset As Long 'Used to calculate offset value in certain cases

Find:

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

After, add:

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

Find:

    '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

Replace with:

    '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

Find:

'Bodies list
Public Type BodyData
    Walk(1 To 8) As Grh
    Attack(1 To 8) As Grh
    HeadOffset As Position
End Type

Replace with:

'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

Find:

'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

Replace with:

'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

Find:

Public Sub Engine_SortIntArray(TheArray() As Integer, TheIndex() As Integer, ByVal LowerBound As Integer, ByVal UpperBound As Integer)

Replace sub with:

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

Find:

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

Replace sub with:

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
Personal tools