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