Mounts and Shields

From VbGORE Visual Basic Online RPG Engine

Here's my next great tutorial of doom! Here's my tutorial about how to add mounts and shields:

Before you do this, back up your code. You add this at your own risk (mwahahaha... *cough cough*)

Resources: Download these http://www.vbgore.com/forums/download/file.php?id=241, and unzip it. Put the grh files into the GRH directory and the dat files into the data directory.

Contents

Database

First thing to do is go to your users table. add a "char_mount" and "char_shield" field. Make their settings identical to "char_weapon". Next add "eq_mount" and "eq_shield" and make their settings identical to "eq_weapon".

Now open up the objects table. add a "sprite_mount" and "sprite_shield" field. Make their settings identical to "sprite_weapon".

Now open the objects table to add two new records: 1) Make a new record with: (Edit the values how u see fit, except the objtype unless you know what u are doing) id: 10 (or whatever the next free id is) name: Horse price: 1000 objtpe: 7 grhIndex: 174 sprite_mount: 1 stat_speed: 10

2) Make another record with: id: 11 (or whatever the next free id) name: Newbie Shield price: 35 objtype: 6 grhindex: 195 sprite_shield: 1 stat_def: 2

Data Files

Just a note, I am working with the default body files (including the armor). So the changes below, just mimic it for all other bodies you have. Also, the grh for the bodies I included have a new row of graphics at the bottom. These are used when riding a mount. make something similar for all body graphics u have.

Open Body.dat and locate body 1. after the a1-a8 lines, add:

<ini>r1=181 r2=183 r3=182 r4=184 r5=181 r6=183 r7=182 r8=184</ini>

and for body 2, after a1-18 lines. add:

<ini>r1=191 r2=193 r3=192 r4=194 r5=191 r6=193 r7=192 r8=194</ini>

Now open the GrhRaw.txt file and locate the "armored body". in the lines of GRH that follow that section, add:

<ini>Grh118=1-100-0-192-32-48-(128) Grh119=1-100-32-192-32-48-(128) Grh120=1-100-64-192-32-48-(128) Grh121=1-100-96-192-32-48-(128) Grh185=1-100-128-192-32-48-(128) Grh186=1-100-160-192-32-48-(128) Grh187=1-100-192-192-32-48-(128) Grh188=1-100-224-192-32-48-(128) Grh189=1-100-192-191-32-48-(128) Grh190=1-100-224-191-32-48-(128)


Grh191=4-187-189-187-189-8-(128) Grh192=4-188-190-188-190-8-(128) Grh193=4-118-119-118-120-8-(128) Grh194=4-121-185-121-186-8-(128)</ini>

This basically adds the animation for riding a mount.

Now locate "Body Naked" and add this to that section of grhs:

<ini>Grh60=1-109-0-192-32-48-(128) Grh61=1-109-32-192-32-48-(128) Grh74=1-109-64-192-32-48-(128) Grh75=1-109-96-192-32-48-(128) Grh175=1-109-128-192-32-48-(128) Grh176=1-109-160-192-32-48-(128) Grh177=1-109-192-192-32-48-(128) Grh178=1-109-224-192-32-48-(128) Grh179=1-109-192-191-32-48-(128) Grh180=1-109-224-191-32-48-(128)


Grh181=4-177-179-177-179-8-(128) Grh182=4-178-180-178-180-8-(128) Grh183=4-60-61-60-74-8-(128) Grh184=4-75-175-75-176-8-(128)</ini>

This will also create the "riding" animation for mounts.

Now add the following to the bottom of your GrhRaw.txt file:

<ini>'**** Shield **** Grh134=1-149-0-0-32-48-(128) Grh135=1-149-32-0-32-48-(128) Grh136=1-149-64-0-32-48-(128) Grh137=1-149-96-0-32-48-(128) Grh138=1-149-0-48-32-48-(128) Grh139=1-149-32-48-32-48-(128) Grh140=1-149-64-48-32-48-(128) Grh141=1-149-96-48-32-48-(128) Grh142=1-149-0-96-32-48-(128) Grh143=1-149-32-96-32-48-(128) Grh144=1-149-64-96-32-48-(128) Grh145=1-149-96-96-32-48-(128) Grh146=1-149-0-144-32-48-(128) Grh147=1-149-32-144-32-48-(128) Grh148=1-149-64-144-32-48-(128) Grh149=1-149-96-144-32-48-(128) Grh150=1-149-128-0-32-48-(128) Grh151=1-149-160-0-32-48-(128) Grh152=1-149-192-0-32-48-(128) Grh153=1-149-224-0-32-48-(128) Grh154=1-149-128-48-32-48-(128) Grh155=1-149-160-48-32-48-(128) Grh156=1-149-192-48-32-48-(128) Grh157=1-149-224-48-32-48-(128) Grh158=1-149-128-96-32-48-(128) Grh159=1-149-160-96-32-48-(128) Grh160=1-149-192-96-32-48-(128) Grh161=1-149-224-96-32-48-(128) Grh162=1-149-128-144-32-48-(128) Grh163=1-149-160-144-32-48-(128) Grh164=1-149-192-144-32-48-(128) Grh165=1-149-224-144-32-48-(128)

Grh166=4-134-135-136-137-8-(128) Grh167=4-138-139-140-141-8-(128) Grh168=4-142-143-144-145-8-(128) Grh169=4-146-147-148-149-8-(128)


Grh195=1-149-26-9-30-30-(128)


'**** Horse **** Grh122=1-148-16-197-71-54-(128) Grh123=1-148-90-196-71-54-(128) Grh124=1-148-166-197-71-54-(128) Grh125=1-148-13-6-71-54-(128) Grh126=1-148-87-5-71-54-(128) Grh127=1-148-163-6-71-54-(128) Grh128=1-148-16-70-71-54-(128) Grh129=1-148-90-69-71-54-(128) Grh130=1-148-166-70-71-54-(128) Grh131=1-148-13-132-71-54-(128) Grh132=1-148-87-131-71-54-(128) Grh133=1-148-163-132-71-54-(128)

Grh170=4-131-132-133-132-8-(128) Grh171=4-128-129-130-129-8-(128) Grh172=4-125-126-127-126-8-(128) Grh173=4-122-123-124-123-8-(128)

Grh174=1-148-180-131-37-54-(128)</ini>

This creates the new shield and mount! If the grh numbers interfer with anything you already have, just make the appropriate adjustments (which I'm sorry to say may be a bit of grind).

Now run the ToolGrhDatMaker.exe to update these changes.

Client

Declares.Bat

Locate "Type Cache_Server_MakeChar" and add the following:

<vb> Mount As Integer

   Shield As Integer</vb>


General.bas

Locate "'Load graphic data into memory" and add:

<vb> Engine_Init_ShieldData

   Engine_Init_MountData</vb>


TCP.bas

locate "Data_Server_ChangeChar". in there find "Dim flags As Byte" and add below it:

<vb>Dim CharShield As Integer Dim CharMount As Integer</vb>

now at the end of the function add:

<vb> If flags And 32 Then

       CharMount = rBuf.Get_Integer
       If Not DontSetData Then CharList(CharIndex).Mount = MountData(CharMount)
   End If
   If flags And 64 Then
       CharShield = rBuf.Get_Integer
       If Not DontSetData Then CharList(CharIndex).Shield = ShieldData(CharShield)
   End If</vb>

Now find Data_Server_MakeCharCached. just for your reference if you are editing this later, update the comments to:

<vb>'************************************************************ 'Create a character and set their information '<Flags(I)><Body(I)><Head(I)><Heading(B)><CharIndex(I)><X(B)><Y(B)><Speed(B)><Name(S)><Weapon(I)><Hair(I)><Wings(I)> ' <HP%(B)><MP%(B)><ChatID(B)><CharType(B)><Mount(I)><Shield(I)> (<OwnerCharIndex(I)>) 'More info: http://www.vbgore.com/GameClient.TCP.Data_Server_MakeCharCached '************************************************************</vb>

and among the variables declared at the beginning, add:

<vb>Dim Mount As Integer Dim Shield As Integer</vb>

and at the end of the block of code under "'Retrieve all the information" add this:

<vb> If flags And 16384 Then Mount = rBuf.Get_Integer Else Mount = PacketCache.Server_MakeChar.Mount

   If flags And 32768 Then Shield = rBuf.Get_Integer Else Shield = PacketCache.Server_MakeChar.Shield</vb>

and in the block of code under "'Store the new values for the cache" add:

<vb> .Mount = Mount

       .Shield = Shield</vb>

and replace the line of code under "'Create the character" with this:

<vb>Engine_Char_Make CharIndex, Body, Head, Heading, X, Y, Speed, Name, Weapon, Shield, Mount, Hair, Wings, ChatID, CharType, HP, MP</vb>

locate the function "Data_Server_MakeChar". Change the comments (for future editing) to this:

<vb>'************************************************************ 'Create a character and set their information '<Body(I)><Head(I)><Heading(B)><CharIndex(I)><X(B)><Y(B)><Speed(B)><Name(S)><Weapon(I)><Hair(I)><Wings(I)> ' <HP%(B)><MP%(B)><ChatID(B)><CharType(B)><Mount(I)><Shield(I)> (<OwnerCharIndex(I)>) 'More info: http://www.vbgore.com/GameClient.TCP.Data_Server_MakeChar '************************************************************</vb>

and add to the variable declarations at the beginning this:

<vb>Dim Mount As Integer Dim Shield As Integer</vb>

and add to the end of the block of code under "Retrieve all the information" this

<vb> Mount = rBuf.Get_Integer

   Shield = rBuf.Get_Integer</vb>

and replace the line of code under "'Create the character" with this:

<vb>Engine_Char_Make CharIndex, Body, Head, Heading, X, Y, Speed, Name, Weapon, Shield, Mount, Hair, Wings, ChatID, CharType, HP, MP</vb>

Getting tired yet? get some coffee, there's ton more changes! Ok, find "Data_Server_ChangeChar" and change the comments under it to this:

<vb>'************************************************************ 'Change a character by the character index '<CharIndex(I)><Flags(B)>(<Body(I)><Head(I)><Weapon(I)><Hair(I)><Wings(I)>) 'More info: http://www.vbgore.com/GameClient.TCP.Data_Server_ChangeChar '************************************************************</vb>

And to add to the variables declarations at the beginning this:

<vb>Dim CharShield As Integer Dim CharMount As Integer</vb>

and at the very end of the function, add this:

<vb> If flags And 32 Then

       CharMount = rBuf.Get_Integer
       If Not DontSetData Then CharList(CharIndex).Mount = MountData(CharMount)
   End If
   If flags And 64 Then
       CharShield = rBuf.Get_Integer
       If Not DontSetData Then CharList(CharIndex).Shield = ShieldData(CharShield)
   End If</vb>


TileEngine.bas

locate this:

<vb>'Weapons list Public Type WeaponData

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

End Type</vb>

and under it add this:

<vb>'Shields list Public Type ShieldData

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

End Type

'Mount list Public Type MountData

   Walk(1 To 8) As Grh
   Offset As Position

End Type</vb>

Locate this:

<vb>'Bodies list Public Type BodyData</vb>

and add to it this:

<vb>Ride(1 To 8) As Grh</vb>

locate "Public Type Char" and add this:

<vb> Shield As ShieldData

   Mount As MountData</vb>

locate this:

<vb>'Totals Private NumBodies As Integer 'Number of bodies Private NumHeads As Integer 'Number of heads</vb>

and add this:

<vb>Private NumMounts As Integer 'Number of Mounts Private NumShields As Integer 'Number of Shields</vb>

Now locate this:

<vb>'********** Public ARRAYS *********** Public GrhData() As GrhData 'Holds data for the graphic structure Public SurfaceSize() As TexInfo 'Holds the size of the surfaces for SurfaceDB() Public BodyData() As BodyData 'Holds data about body structure Public HeadData() As HeadData 'Holds data about head structure Public HairData() As HairData 'Holds data about hair structure</vb>

and add this:

<vb>Public MountData() As MountData 'Holds data about Mount structure Public ShieldData() As ShieldData 'Holds data about Shield structure</vb>

Now locate "Engine_Char_Make" and change the sub declaration to this:

<vb>Sub Engine_Char_Make(ByVal CharIndex As Integer, ByVal Body As Integer, ByVal Head As Integer, ByVal Heading As Byte, ByVal X As Integer, ByVal Y As Integer, ByVal Speed As Byte, ByVal Name As String, ByVal Weapon As Integer, ByVal Shield As Integer, ByVal Mount As Integer, ByVal Hair As Integer, ByVal Wings As Integer, ByVal ChatID As Byte, ByVal CharType As Byte, Optional ByVal HP As Byte = 100, Optional ByVal MP As Byte = 100)</vb>

and then locate "'Set the apperances" and add this:

<vb> CharList(CharIndex).Mount = MountData(Mount)

   CharList(CharIndex).Shield = ShieldData(Shield)</vb>

now locate "Engine_Init_BodyData". Inside the loop "For j = 1 To 8" add this:

<vb>Engine_Init_Grh BodyData(LoopC).Ride(j), CLng(Var_Get(DataPath & "Body.dat", LoopC, "r" & j)), 0</vb>

Now add these sub routines (before or after the Engine_Init_BodyData sub):

<vb>Sub Engine_Init_MountData() '***************************************************************** 'Loads Mount.dat '***************************************************************** Dim LoopC As Long Dim j As Long

   'Get number of Mounts
   NumMounts = CLng(Var_Get(DataPath & "Mount.dat", "INIT", "NumMounts"))
  
   'Resize array
   ReDim MountData(0 To NumMounts) As MountData
  
   'Fill list
   For LoopC = 1 To NumMounts
       For j = 1 To 8
           Engine_Init_Grh MountData(LoopC).Walk(j), CLng(Var_Get(DataPath & "Mount.dat", LoopC, j)), 0
       Next j
       MountData(LoopC).Offset.X = CLng(Var_Get(DataPath & "Mount.dat", LoopC, "OffsetX"))
       MountData(LoopC).Offset.Y = CLng(Var_Get(DataPath & "Mount.dat", LoopC, "OffsetY"))
   Next LoopC

End Sub

Sub Engine_Init_ShieldData() '***************************************************************** 'Loads Shield.dat '***************************************************************** Dim LoopC As Long Dim j As Long

   'Get number of Shields
   NumShields = CLng(Var_Get(DataPath & "Shield.dat", "INIT", "NumShields"))
  
   'Resize array
   ReDim ShieldData(0 To NumShields) As ShieldData
  
   'Fill list
   For LoopC = 1 To NumShields
       For j = 1 To 8
           Engine_Init_Grh ShieldData(LoopC).Walk(j), CLng(Var_Get(DataPath & "Shield.dat", LoopC, j)), 0
           Engine_Init_Grh ShieldData(LoopC).Attack(j), CLng(Var_Get(DataPath & "Shield.dat", LoopC, "a" & j)), 1
       Next j
   Next LoopC

End Sub </vb>

Locate "Engine_Init_UnloadTileEngine" and find "'Clear arrays". Add this under it:

<vb> Erase MountData

   Erase ShieldData</vb>

Locate "Engine_Render_Char" and in the variable declarations at the beginning add this:

<vb>Dim MountGrh As Grh Dim ShieldGrh As Grh Dim Offset As Position Dim IsOnMount As Boolean</vb>

Under "'***** Set the variables *****" add this:

<vb> 'Is char on mount?

   If Not CharList(CharIndex).Mount.Walk(CharList(CharIndex).Heading).GrhIndex = 0 Then
       IsOnMount = True
       Offset = CharList(CharIndex).Mount.Offset
   End If</vb>

now under "'***** Render Shadows *****" find "'Draw Body", change that section of code to this:

<vb> If CharList(CharIndex).ActionIndex <= 1 Then

       'Shadow
       If IsOnMount Then
           Engine_Render_Grh CharList(CharIndex).Body.Ride(CharList(CharIndex).Heading), PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, 1, 1, True, ShadowColor, ShadowColor, ShadowColor, ShadowColor, 1
           Engine_Render_Grh CharList(CharIndex).Mount.Walk(CharList(CharIndex).Heading), PixelOffsetX, PixelOffsetY, 1, 1, False, ShadowColor, ShadowColor, ShadowColor, ShadowColor, 1
       Else
           Engine_Render_Grh CharList(CharIndex).Body.Walk(CharList(CharIndex).Heading), PixelOffsetX, PixelOffsetY, 1, 1, True, ShadowColor, ShadowColor, ShadowColor, ShadowColor, 1
           Engine_Render_Grh CharList(CharIndex).Weapon.Walk(CharList(CharIndex).Heading), PixelOffsetX, PixelOffsetY, 1, 1, True, ShadowColor, ShadowColor, ShadowColor, ShadowColor, 1
           Engine_Render_Grh CharList(CharIndex).Shield.Walk(CharList(CharIndex).Heading), PixelOffsetX, PixelOffsetY, 1, 1, True, ShadowColor, ShadowColor, ShadowColor, ShadowColor, 1
       End If
   Else
       'Shadow
       Engine_Render_Grh CharList(CharIndex).Body.Attack(CharList(CharIndex).Heading), PixelOffsetX, PixelOffsetY, 1, 1, False, ShadowColor, ShadowColor, ShadowColor, ShadowColor, 1
       Engine_Render_Grh CharList(CharIndex).Weapon.Attack(CharList(CharIndex).Heading), PixelOffsetX, PixelOffsetY, 1, 1, False, ShadowColor, ShadowColor, ShadowColor, ShadowColor, 1
       Engine_Render_Grh CharList(CharIndex).Shield.Attack(CharList(CharIndex).Heading), PixelOffsetX, PixelOffsetY, 1, 1, False, ShadowColor, ShadowColor, ShadowColor, ShadowColor, 1
       'Check if animation has stopped
       If CharList(CharIndex).Body.Attack(CharList(CharIndex).Heading).Started = 0 Then CharList(CharIndex).ActionIndex = 0
   End If
   'Hair
   Engine_Render_Grh CharList(CharIndex).Hair.Hair(CharList(CharIndex).HeadHeading), PixelOffsetX + CharList(CharIndex).Body.HeadOffset.X + Offset.X, PixelOffsetY + CharList(CharIndex).Body.HeadOffset.Y + Offset.Y, True, False, True, ShadowColor, ShadowColor, ShadowColor, ShadowColor, 1</vb>

and find '***** Render Character *****" and change the code under it to this:

<vb>'***** (When updating this, make sure you copy it to the NPCEditor and MapEditor, too!) *****

   If IsOnMount Then
       CharList(CharIndex).Weapon.Walk(CharList(CharIndex).Heading).FrameCounter = CharList(CharIndex).Mount.Walk(CharList(CharIndex).Heading).FrameCounter
   Else
       CharList(CharIndex).Weapon.Walk(CharList(CharIndex).Heading).FrameCounter = CharList(CharIndex).Body.Walk(CharList(CharIndex).Heading).FrameCounter
   End If
   'The body, weapon, wings, shield, and mount
   If CharList(CharIndex).ActionIndex <= 1 Then
       'Walking
       If IsOnMount Then
           BodyGrh = CharList(CharIndex).Body.Ride(CharList(CharIndex).Heading)
           MountGrh = CharList(CharIndex).Mount.Walk(CharList(CharIndex).Heading)
           
           ' animate weapon/shield
           CharList(CharIndex).Weapon.Walk(CharList(CharIndex).Heading).FrameCounter = CharList(CharIndex).Mount.Walk(CharList(CharIndex).Heading).FrameCounter
           CharList(CharIndex).Shield.Walk(CharList(CharIndex).Heading).FrameCounter = CharList(CharIndex).Mount.Walk(CharList(CharIndex).Heading).FrameCounter
       Else
           BodyGrh = CharList(CharIndex).Body.Walk(CharList(CharIndex).Heading)
           
           ' animate weapon/shield
           CharList(CharIndex).Weapon.Walk(CharList(CharIndex).Heading).FrameCounter = CharList(CharIndex).Body.Walk(CharList(CharIndex).Heading).FrameCounter
           CharList(CharIndex).Shield.Walk(CharList(CharIndex).Heading).FrameCounter = CharList(CharIndex).Body.Walk(CharList(CharIndex).Heading).FrameCounter
           
           WeaponGrh = CharList(CharIndex).Weapon.Walk(CharList(CharIndex).Heading)
           ShieldGrh = CharList(CharIndex).Shield.Walk(CharList(CharIndex).Heading)
       End If
       
       
       WingsGrh = CharList(CharIndex).Wings.Walk(CharList(CharIndex).Heading)
   Else
       'Attacking
       BodyGrh = CharList(CharIndex).Body.Attack(CharList(CharIndex).Heading)
       WeaponGrh = CharList(CharIndex).Weapon.Attack(CharList(CharIndex).Heading)
       WingsGrh = CharList(CharIndex).Wings.Attack(CharList(CharIndex).Heading)
       ShieldGrh = CharList(CharIndex).Shield.Attack(CharList(CharIndex).Heading)
       
       ' animate weapon/shield
       CharList(CharIndex).Weapon.Attack(CharList(CharIndex).Heading).FrameCounter = CharList(CharIndex).Body.Attack(CharList(CharIndex).Heading).FrameCounter
       CharList(CharIndex).Shield.Attack(CharList(CharIndex).Heading).FrameCounter = CharList(CharIndex).Body.Attack(CharList(CharIndex).Heading).FrameCounter
   End If
   
   'The head
   If CharList(CharIndex).Aggressive > 0 Then  'Aggressive
       If CharList(CharIndex).BlinkTimer > 0 Then HeadGrh = CharList(CharIndex).Head.AgrBlink(CharList(CharIndex).HeadHeading) Else HeadGrh = CharList(CharIndex).Head.AgrHead(CharList(CharIndex).HeadHeading)
   Else    'Non-aggressive
       If CharList(CharIndex).BlinkTimer > 0 Then HeadGrh = CharList(CharIndex).Head.Blink(CharList(CharIndex).HeadHeading) Else HeadGrh = CharList(CharIndex).Head.Head(CharList(CharIndex).HeadHeading)
   End If
   
   'The hair
   HairGrh = CharList(CharIndex).Hair.Hair(CharList(CharIndex).HeadHeading)
   
   'Make the paperdoll layering based off the direction they are heading
       
   '*** NORTH / NORTHEAST *** (1.Weapon 2.Body 3.Head 4.Hair 5.Wings)
   If CharList(CharIndex).Heading = NORTH Or CharList(CharIndex).Heading = NORTHEAST Then
       Engine_Render_Grh MountGrh, PixelOffsetX, PixelOffsetY, True, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh WeaponGrh, PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, True, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh ShieldGrh, PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, True, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh BodyGrh, PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, 1, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh HeadGrh, PixelOffsetX + CharList(CharIndex).Body.HeadOffset.X + Offset.X, PixelOffsetY + CharList(CharIndex).Body.HeadOffset.Y + Offset.Y, 1, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh HairGrh, PixelOffsetX + CharList(CharIndex).Body.HeadOffset.X + Offset.X, PixelOffsetY + CharList(CharIndex).Body.HeadOffset.Y + Offset.Y, 1, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh WingsGrh, PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, True, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       
   '*** EAST / SOUTHEAST *** (1.Body 2.Head 3.Hair 4.Wings 5.Weapon)
   ElseIf CharList(CharIndex).Heading = EAST Or CharList(CharIndex).Heading = SOUTHEAST Then
       Engine_Render_Grh MountGrh, PixelOffsetX, PixelOffsetY, True, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh ShieldGrh, PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, True, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh BodyGrh, PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, 1, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh HeadGrh, PixelOffsetX + CharList(CharIndex).Body.HeadOffset.X + Offset.X, PixelOffsetY + CharList(CharIndex).Body.HeadOffset.Y + Offset.Y, 1, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh HairGrh, PixelOffsetX + CharList(CharIndex).Body.HeadOffset.X + Offset.X, PixelOffsetY + CharList(CharIndex).Body.HeadOffset.Y + Offset.Y, 1, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh WingsGrh, PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, True, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh WeaponGrh, PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, True, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       
       
   '*** SOUTH / SOUTHWEST *** (1.Wings 2.Body 3.Head 4.Hair 5.Weapon)
   ElseIf CharList(CharIndex).Heading = SOUTH Or CharList(CharIndex).Heading = SOUTHWEST Then
       Engine_Render_Grh WingsGrh, PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, True, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh BodyGrh, PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, 1, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh HeadGrh, PixelOffsetX + CharList(CharIndex).Body.HeadOffset.X + Offset.X, PixelOffsetY + CharList(CharIndex).Body.HeadOffset.Y + Offset.Y, 1, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh HairGrh, PixelOffsetX + CharList(CharIndex).Body.HeadOffset.X + Offset.X, PixelOffsetY + CharList(CharIndex).Body.HeadOffset.Y + Offset.Y, 1, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh WeaponGrh, PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, True, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh ShieldGrh, PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, True, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh MountGrh, PixelOffsetX, PixelOffsetY, True, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       
   '*** WEST / NORTHWEST *** (1.Weapon 1.Body 2.Head 3.Hair 4.Wings)
   ElseIf CharList(CharIndex).Heading = WEST Or CharList(CharIndex).Heading = NORTHWEST Then
       Engine_Render_Grh WeaponGrh, PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, True, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh MountGrh, PixelOffsetX, PixelOffsetY, True, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh BodyGrh, PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, 1, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh HeadGrh, PixelOffsetX + CharList(CharIndex).Body.HeadOffset.X + Offset.X, PixelOffsetY + CharList(CharIndex).Body.HeadOffset.Y + Offset.Y, 1, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh HairGrh, PixelOffsetX + CharList(CharIndex).Body.HeadOffset.X + Offset.X, PixelOffsetY + CharList(CharIndex).Body.HeadOffset.Y + Offset.Y, 1, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh ShieldGrh, PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, True, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh WingsGrh, PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, True, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
   End If</vb>

... come to think of it, I should have just copied my whole function over... xD

Now, for the code that draws the name:

<vb>'***** Render Extras *****

   'Add Border around name
   Engine_Render_Text Font_Default, CharList(CharIndex).DisplayName, PixelOffsetX + 16 - CharList(CharIndex).NameOffset + Offset.X, PixelOffsetY - 41 + Offset.Y, -16777216
   Engine_Render_Text Font_Default, CharList(CharIndex).DisplayName, PixelOffsetX + 16 - CharList(CharIndex).NameOffset + Offset.X, PixelOffsetY - 39 + Offset.Y, -16777216
   Engine_Render_Text Font_Default, CharList(CharIndex).DisplayName, PixelOffsetX + 15 - CharList(CharIndex).NameOffset + Offset.X, PixelOffsetY - 40 + Offset.Y, -16777216
   Engine_Render_Text Font_Default, CharList(CharIndex).DisplayName, PixelOffsetX + 17 - CharList(CharIndex).NameOffset + Offset.X, PixelOffsetY - 40 + Offset.Y, -16777216
   
   'Draw name over head
   If CharList(CharIndex).HealthPercent = 100 Then
       Engine_Render_Text Font_Default, CharList(CharIndex).DisplayName, PixelOffsetX + 16 - CharList(CharIndex).NameOffset + Offset.X, PixelOffsetY - 40 + Offset.Y, -14104576
   ElseIf CharList(CharIndex).HealthPercent > 90 Then
       Engine_Render_Text Font_Default, CharList(CharIndex).DisplayName, PixelOffsetX + 16 - CharList(CharIndex).NameOffset + Offset.X, PixelOffsetY - 40 + Offset.Y, -11483136
   ElseIf CharList(CharIndex).HealthPercent > 80 Then
       Engine_Render_Text Font_Default, CharList(CharIndex).DisplayName, PixelOffsetX + 16 - CharList(CharIndex).NameOffset + Offset.X, PixelOffsetY - 40 + Offset.Y, -8861696
   ElseIf CharList(CharIndex).HealthPercent > 70 Then
       Engine_Render_Text Font_Default, CharList(CharIndex).DisplayName, PixelOffsetX + 16 - CharList(CharIndex).NameOffset + Offset.X, PixelOffsetY - 40 + Offset.Y, -6240256
   ElseIf CharList(CharIndex).HealthPercent > 50 Then
       Engine_Render_Text Font_Default, CharList(CharIndex).DisplayName, PixelOffsetX + 16 - CharList(CharIndex).NameOffset + Offset.X, PixelOffsetY - 40 + Offset.Y, -3618816
   ElseIf CharList(CharIndex).HealthPercent > 40 Then
       Engine_Render_Text Font_Default, CharList(CharIndex).DisplayName, PixelOffsetX + 16 - CharList(CharIndex).NameOffset + Offset.X, PixelOffsetY - 40 + Offset.Y, -3629056
   ElseIf CharList(CharIndex).HealthPercent > 30 Then
       Engine_Render_Text Font_Default, CharList(CharIndex).DisplayName, PixelOffsetX + 16 - CharList(CharIndex).NameOffset + Offset.X, PixelOffsetY - 40 + Offset.Y, -3639296
   ElseIf CharList(CharIndex).HealthPercent > 20 Then
       Engine_Render_Text Font_Default, CharList(CharIndex).DisplayName, PixelOffsetX + 16 - CharList(CharIndex).NameOffset + Offset.X, PixelOffsetY - 40 + Offset.Y, -3649536
   ElseIf CharList(CharIndex).HealthPercent > 10 Then
       Engine_Render_Text Font_Default, CharList(CharIndex).DisplayName, PixelOffsetX + 16 - CharList(CharIndex).NameOffset + Offset.X, PixelOffsetY - 40 + Offset.Y, -3659776
   ElseIf CharList(CharIndex).HealthPercent > 0 Then
       Engine_Render_Text Font_Default, CharList(CharIndex).DisplayName, PixelOffsetX + 16 - CharList(CharIndex).NameOffset + Offset.X, PixelOffsetY - 40 + Offset.Y, -3670016
   End If</vb>

now, yours may be different because I added to my code the "Name Border" code and the code from the tutorial that changes the color of the name to reflect your health status. The important thing to do in your code for the part that renders the name is add "Offset.X" and "Offset.Y" to the x and y coordinates. That's also what I am doing in the following code...

Now for the code that renders the emoticons, the icons, and health/mana bars, change yours or replace it with this:

<vb> 'Health/Mana bars

   Engine_Render_Rectangle PixelOffsetX - 4 + Offset.X, PixelOffsetY + 34 + Offset.Y, (CharList(CharIndex).HealthPercent / 100) * 40, 4, 1, 1, 1, 1, 1, 1, 0, 0, HealthColor, HealthColor, HealthColor, HealthColor, 0, False
   Engine_Render_Rectangle PixelOffsetX - 4 + Offset.X, PixelOffsetY + 38 + Offset.Y, (CharList(CharIndex).ManaPercent / 100) * 40, 4, 1, 1, 1, 1, 1, 1, 0, 0, ManaColor, ManaColor, ManaColor, ManaColor, 0, False
   'Draw the icons
   If IconCount > 0 Then
       'Calculate the icon offset
       IconOffset = PixelOffsetX + 16 - (IconCount * 8) + Offset.X
       If CharList(CharIndex).CharStatus.Blessed Then
           Engine_Init_Grh TempGrh, 15
           Engine_Render_Grh TempGrh, IconOffset, PixelOffsetY - 50 + Offset.Y, 0, 0, False
           IconOffset = IconOffset + 16
       End If
       If CharList(CharIndex).CharStatus.Protected Then
           Engine_Init_Grh TempGrh, 20
           Engine_Render_Grh TempGrh, IconOffset, PixelOffsetY - 50 + Offset.Y, 0, 0, False
           IconOffset = IconOffset + 16
       End If
       If CharList(CharIndex).CharStatus.Strengthened Then
           Engine_Init_Grh TempGrh, 17
           Engine_Render_Grh TempGrh, IconOffset, PixelOffsetY - 50 + Offset.Y, 0, 0, False
           IconOffset = IconOffset + 16
       End If
       If CharList(CharIndex).CharStatus.Cursed Then
           Engine_Init_Grh TempGrh, 18
           Engine_Render_Grh TempGrh, IconOffset, PixelOffsetY - 50 + Offset.Y, 0, 0, False
           IconOffset = IconOffset + 16
       End If
       If CharList(CharIndex).CharStatus.WarCursed Then
           Engine_Init_Grh TempGrh, 19
           Engine_Render_Grh TempGrh, IconOffset, PixelOffsetY - 50 + Offset.Y, 0, 0, False
           IconOffset = IconOffset + 16
       End If
       If CharList(CharIndex).CharStatus.IronSkinned Then
           Engine_Init_Grh TempGrh, 16
           Engine_Render_Grh TempGrh, IconOffset, PixelOffsetY - 50 + Offset.Y, 0, 0, False
           IconOffset = IconOffset + 16
       End If
       If CharList(CharIndex).CharStatus.Exhausted Then
           Engine_Init_Grh TempGrh, 22
           Engine_Render_Grh TempGrh, IconOffset, PixelOffsetY - 50 + Offset.Y, 0, 0, False
           IconOffset = IconOffset + 16
       End If
   End If
   'Emoticons
   If CharList(CharIndex).EmoDir > 0 Then
       'Fade in
       If CharList(CharIndex).EmoDir = 1 Then
           CharList(CharIndex).EmoFade = CharList(CharIndex).EmoFade + (ElapsedTime * 1.5)
           If CharList(CharIndex).EmoFade >= 255 Then
               CharList(CharIndex).EmoFade = 255
               CharList(CharIndex).EmoDir = 2
           End If
       End If
       'Fade out
       If CharList(CharIndex).Emoticon.Started = 0 Then    'Animation has stopped
           If CharList(CharIndex).EmoDir = 2 Then
               CharList(CharIndex).EmoFade = CharList(CharIndex).EmoFade - (ElapsedTime * 1.5)
               If CharList(CharIndex).EmoFade <= 0 Then
                   CharList(CharIndex).EmoFade = 0
                   CharList(CharIndex).EmoDir = 0
               End If
               'Stop at the last frame, don't roll over to the first
               CharList(CharIndex).Emoticon.FrameCounter = GrhData(CharList(CharIndex).Emoticon.GrhIndex).NumFrames
           End If
       End If
       'Render
       Engine_Render_Grh CharList(CharIndex).Emoticon, PixelOffsetX + 8 + Offset.X, PixelOffsetY - 40 + Offset.Y, 0, 1, False, D3DColorARGB(CharList(CharIndex).EmoFade, 255, 255, 255), D3DColorARGB(CharList(CharIndex).EmoFade, 255, 255, 255), D3DColorARGB(CharList(CharIndex).EmoFade, 255, 255, 255), D3DColorARGB(CharList(CharIndex).EmoFade, 255, 255, 255)
   End If</vb>

Server

Declares.bas

find "Public Type udtObjData" and add to it this:

<vb> SpriteMount As Integer 'Index of the Mount sprite to change to

   SpriteShield As Integer         'Index of the Shield sprite to change to</vb>

Find "Type Char 'Holds data for a user or NPC character" and add this:

<vb> Mount As Integer 'Mount index

   Shield As Integer           'Shield index</vb>

Find "Type Cache_Server_MakeChar" and add this:

<vb> Shield As Integer

   Mount As Integer</vb>

Find "Type User 'Holds data for a user" and add this:

<vb> ShieldEqpObjIndex As Integer 'The index of the equipted Shield

   ShieldEqpSlot As Byte           'Slot of the equipted Shield
   MountEqpObjIndex As Integer     'The index of the equipted Mount
   MountEqpSlot As Byte           'Slot of the equipted Mount</vb>

Find this:

<vb>'Object types Public Const OBJTYPE_USEONCE As Byte = 1 'Objects that can be used only once Public Const OBJTYPE_WEAPON As Byte = 2 'Weapons of all types Public Const OBJTYPE_ARMOR As Byte = 3 'Body armors Public Const OBJTYPE_WINGS As Byte = 4 'Wings Public Const OBJTYPE_USEINFINITE As Byte = 5 'USEONCE object, minus the removal after usage</vb>

and add to the bottom of it this:

<vb>Public Const OBJTYPE_SHIELD As Byte = 6 'Shields Public Const OBJTYPE_MOUNT As Byte = 7 'Mount</vb>


FileIO.bas

Now find "Save_NPCs_Temp" and in it find "With NPCList (1)" and add this:

<vb> .Char.Mount = Val(DB_RS!char_mount)

           .Char.Shield = Val(DB_RS!char_shield)</vb>

Find Load_Objs and in it find "With TempObjData". add to it this:

<vb> .SpriteMount = Val(DB_RS!sprite_mount)

           .SpriteShield = Val(DB_RS!sprite_shield)</vb>

Find "Load_User" and find "UserList(UserIndex).Char.Weapon = Val(!char_weapon)" and add below it this:

<vb> UserList(UserIndex).Char.Mount = Val(!char_mount)

       UserList(UserIndex).Char.Shield = Val(!char_shield)
       UserList(UserIndex).MountEqpSlot = Val(!eq_mount)
       UserList(UserIndex).ShieldEqpSlot = Val(!eq_shield)</vb>

Find in the same function this "'Equipt items" and add below it this:

<vb> If UserList(UserIndex).MountEqpSlot > 0 Then UserList(UserIndex).MountEqpObjIndex = UserList(UserIndex).Object(UserList(UserIndex).MountEqpSlot).ObjIndex

   If UserList(UserIndex).ShieldEqpSlot > 0 Then UserList(UserIndex).ShieldEqpObjIndex = UserList(UserIndex).Object(UserList(UserIndex).WeaponEqpSlot).ObjIndex</vb>

Find "Save_User" and find "DB_RS!char_weapon = .Char.Weapon" and below it add this:

<vb> DB_RS!char_mount = .Char.Mount

       DB_RS!char_shield = .Char.Shield
       DB_RS!eq_mount = .MountEqpSlot
       DB_RS!eq_shield = .ShieldEqpSlot</vb>

Find "Save_NPCs_Temp" and in it find ".Char.Weapon = Val(DB_RS!char_weapon)' and below that add this:

<vb> .Char.Mount = Val(DB_RS!char_mount)

           .Char.Shield = Val(DB_RS!char_shield)</vb>


NPCs.bas

Find NPC_ChangeChar and change the sub declaration to this:

<vb>Private Sub NPC_ChangeChar(ByVal sndRoute As Byte, ByVal sndIndex As Integer, ByVal NPCIndex As Integer, Optional ByVal Body As Integer = -1, Optional ByVal Head As Integer = -1, Optional ByVal Weapon As Integer = -1, Optional ByVal Mount As Integer = -1, Optional ByVal Shield As Integer = -1, Optional ByVal Hair As Integer = -1, Optional ByVal Wings As Integer = -1)</vb>

then find this:

<vb>If Weapon > -1 Then

           If .Weapon <> Weapon Then
               .Weapon = Weapon
               ChangeFlags = ChangeFlags Or 4
               FlagSizes = FlagSizes + 2
           End If
       End If</vb>

and below it add this:

<vb> If Mount > -1 Then

           NPCList(NPCIndex).Attackable = 0
           If .Mount <> Mount Then
               .Mount = Mount
               ChangeFlags = ChangeFlags Or 4
               FlagSizes = FlagSizes + 2
           End If
       End If
       If Shield > -1 Then
           If .Shield <> Shield Then
               .Shield = Shield
               ChangeFlags = ChangeFlags Or 4
               FlagSizes = FlagSizes + 2
           End </vb>

then find "If ChangeFlags And 16 Then ConBuf.Put_Integer Wings" and below it add this:

<vb> If ChangeFlags And 32 Then ConBuf.Put_Integer Mount

   If ChangeFlags And 64 Then ConBuf.Put_Integer Shield</vb>

Find NPC_MakeChar and find this:

<vb>If NPCList(NPCIndex).OwnerIndex > 0 Then

               If ClientCharType_Slave <> .CharType Then
                   Flags = Flags Or 8192
                   .CharType = ClientCharType_Slave
                   PacketSize = PacketSize + 1
               End If
           Else
               If ClientCharType_NPC <> .CharType Then
                   Flags = Flags Or 8192
                   .CharType = ClientCharType_NPC
                   PacketSize = PacketSize + 1
               End If
           End If</vb>

and below it add this:

<vb>If NPCList(NPCIndex).Char.Mount <> .Mount Then

               Flags = Flags Or 16384
               .Mount = NPCList(NPCIndex).Char.Mount
               
               If (.Mount > 0) Then
                   NPCList(NPCIndex).Attackable = 0
               End If
               
               PacketSize = PacketSize + 2
           End If
           If NPCList(NPCIndex).Char.Shield <> .Shield Then
               Flags = Flags Or 32768
               .Shield = NPCList(NPCIndex).Char.Shield
               PacketSize = PacketSize + 2
           End If</vb>

Now in the if statement "If sndRoute = ToIndex Then" find "If NPCList(NPCIndex).OwnerIndex > 0 Then ... End If" and replace that section of code with this:

<vb> If NPCList(NPCIndex).OwnerIndex > 0 Then

           If Flags And 8192 Then ConBuf.Put_Byte ClientCharType_Slave
           If Flags And 16384 Then ConBuf.Put_Byte NPCList(NPCIndex).Char.Mount
           If Flags And 32768 Then ConBuf.Put_Byte NPCList(NPCIndex).Char.Shield
           ConBuf.Put_Integer UserList(NPCList(NPCIndex).OwnerIndex).Char.CharIndex
       Else
           If Flags And 8192 Then ConBuf.Put_Byte ClientCharType_NPC
           If Flags And 16384 Then ConBuf.Put_Byte NPCList(NPCIndex).Char.Mount
           If Flags And 32768 Then ConBuf.Put_Byte NPCList(NPCIndex).Char.Shield
       End If</vb>

Now for the same if statement "If NPCList(NPCIndex).OwnerIndex > 0 Then ... End If", go to the ELSE statement and find "If NPCList(NPCIndex).OwnerIndex > 0 Then" and replace that block of code with this:

<vb> If NPCList(NPCIndex).OwnerIndex > 0 Then

           ConBuf.Put_Byte ClientCharType_Slave
           ConBuf.Put_Integer NPCList(NPCIndex).Char.Mount
           ConBuf.Put_Integer NPCList(NPCIndex).Char.Shield
           ConBuf.Put_Integer UserList(NPCList(NPCIndex).OwnerIndex).Char.CharIndex
       Else
           ConBuf.Put_Byte ClientCharType_NPC
           ConBuf.Put_Integer NPCList(NPCIndex).Char.Mount
           ConBuf.Put_Integer NPCList(NPCIndex).Char.Shield
       End If</vb>


TCP.bas

find Data_User_ChangeInvSlot and in that find:

<vb>If UserList(UserIndex).WeaponEqpSlot = SrcSlot Then

       UserList(UserIndex).WeaponEqpSlot = DestSlot
   ElseIf UserList(UserIndex).WeaponEqpSlot = DestSlot Then
       UserList(UserIndex).WeaponEqpSlot = SrcSlot
   End If</vb>

and below that add this:

<vb>If UserList(UserIndex).MountEqpSlot = SrcSlot Then

       UserList(UserIndex).MountEqpSlot = DestSlot
   ElseIf UserList(UserIndex).MountEqpSlot = DestSlot Then
       UserList(UserIndex).MountEqpSlot = SrcSlot
   End If
   If UserList(UserIndex).ShieldEqpSlot = SrcSlot Then
       UserList(UserIndex).ShieldEqpSlot = DestSlot
   ElseIf UserList(UserIndex).ShieldEqpSlot = DestSlot Then
       UserList(UserIndex).ShieldEqpSlot = SrcSlot
   End If</vb>

Now find Data_User_Attack. At the end of this function, add: <vb>

   'Dismount when attacking
   For i = 1 To MAX_INVENTORY_SLOTS
       If ObjData.ObjType(UserList(UserIndex).Object(i).ObjIndex) = 7 Then
           Call User_RemoveInvItem(UserIndex, i, True)
           Exit For
       End If
   Next i

</vb>

Users.bas

Find User_ChangeChar and change the sub declaration to this:

<vb>Public Sub User_ChangeChar(ByVal sndRoute As Byte, ByVal sndIndex As Integer, ByVal UserIndex As Integer, Optional ByVal Body As Integer = -1, Optional ByVal Head As Integer = -1, Optional ByVal Weapon As Integer = -1, Optional ByVal Hair As Integer = -1, Optional ByVal Wings As Integer = -1, Optional ByVal Mount As Integer = -1, Optional ByVal Shield As Integer = -1)</vb>

now change the comment section to this:

<vb>'***************************************************************** 'Changes a user char's head,body, shield, mount, and heading 'More info: http://www.vbgore.com/GameServer.Users.User_ChangeChar '*****************************************************************</vb>

and now change the "Log" calls at the beginning to this:

<vb>Log "Call User_ChangeChar(" & sndRoute & "," & sndIndex & "," & UserIndex & "," & Body & "," & Head & "," & Weapon & "," & Hair & "," & Wings & "," & Mount & "," & Shield & ")", CodeTracker '//\\LOGLINE//\\

   'Check for invalid values
   If UserIndex > MaxUsers Then
       Log "User_ChangeChar: UserIndex > MaxUsers - aborting", CodeTracker '//\\LOGLINE//\\
       Exit Sub
   End If
   If UserIndex <= 0 Then
       Log "User_ChangeChar: UserIndex <= 0 - aborting", CodeTracker '//\\LOGLINE//\\
       Exit Sub
   End If</vb>

now find this:

<vb> If Wings > -1 Then

           If .Wings <> Wings Then
               .Wings = Wings
               ChangeFlags = ChangeFlags Or 16
               FlagSizes = FlagSizes + 2
           End If
       End If</vb>

and below it add this:

<vb> If Mount > -1 Then

           If .Mount <> Mount Then
               .Mount = Mount
               ChangeFlags = ChangeFlags Or 32
               FlagSizes = FlagSizes + 2
           End If
       End If
       If Shield > -1 Then
           If .Shield <> Shield Then
               .Shield = Shield
               ChangeFlags = ChangeFlags Or 64
               FlagSizes = FlagSizes + 2
           End If
       End If</vb>

Now find "If ChangeFlags And 16 Then ConBuf.Put_Integer Wings" and below it add this:

<vb> If ChangeFlags And 32 Then ConBuf.Put_Integer Mount

   If ChangeFlags And 64 Then ConBuf.Put_Integer Shield</vb>

Find User_MakeChar and find this:

<vb> If UserList(UserIndex).GroupIndex > 0 And UserList(sndIndex).GroupIndex = UserList(UserIndex).GroupIndex Then

       ConBuf.Put_Byte ClientCharType_Grouped
   Else
       ConBuf.Put_Byte ClientCharType_PC
   End If</vb>

and below it add this:

<vb> ConBuf.Put_Integer UserList(UserIndex).Char.Mount

   ConBuf.Put_Integer UserList(UserIndex).Char.Shield</vb>

Find User_RemoveInvItem and find this:

<vb>'Check for weapon

       Case OBJTYPE_WEAPON
           Log "User_RemoveInvItem: Object type OBJTYPE_WEAPON", CodeTracker '//\\LOGLINE//\\
           
           If Slot = UserList(UserIndex).WeaponEqpSlot Then
           
               'Update the weapon distance on the client
               ConBuf.PreAllocate 2
               ConBuf.Put_Byte DataCode.User_SetWeaponRange
               ConBuf.Put_Byte 0
               Data_Send ToIndex, UserIndex, ConBuf.Get_Buffer
               
               'Unequip
               UserList(UserIndex).Object(Slot).Equipped = 0
               UserList(UserIndex).WeaponEqpObjIndex = 0
               UserList(UserIndex).WeaponEqpSlot = 0
               UserList(UserIndex).WeaponType = Hand
               
               'Set the paper-dolling
               User_ChangeChar ToMap, UserIndex, UserIndex, , , 0
           
               'Update user's stats and inventory
               If UpdateInv Then User_UpdateInv False, UserIndex, Slot
           
           End If</vb>

Below that add this:

<vb> 'Check for mount

       Case OBJTYPE_MOUNT
           Log "User_RemoveInvItem: Object type OBJTYPE_MOUNT", CodeTracker '//\\LOGLINE//\\
           
           If Slot = UserList(UserIndex).MountEqpSlot Then
               'Unequip
               UserList(UserIndex).Object(Slot).Equipped = 0
               UserList(UserIndex).MountEqpObjIndex = 0
               UserList(UserIndex).MountEqpSlot = 0
               
               'Set the paper-dolling
               User_ChangeChar ToMap, UserIndex, UserIndex, , , , , , 0
           
               'Update user's stats and inventory
               If UpdateInv Then User_UpdateInv False, UserIndex, Slot
           
           End If
           
           'Check for shield
       Case OBJTYPE_SHIELD
           Log "User_RemoveInvItem: Object type OBJTYPE_SHIELD", CodeTracker '//\\LOGLINE//\\
           
           If Slot = UserList(UserIndex).ShieldEqpSlot Then
               'Unequip
               UserList(UserIndex).Object(Slot).Equipped = 0
               UserList(UserIndex).ShieldEqpObjIndex = 0
               UserList(UserIndex).ShieldEqpSlot = 0
               
               'Set the paper-dolling
               User_ChangeChar ToMap, UserIndex, UserIndex, , , , , , , 0
           
               'Update user's stats and inventory
               If UpdateInv Then User_UpdateInv False, UserIndex, Slot
           
           End If</vb>

Find User_UpdateModStats and add to the variable declarations at the beginning this:

<vb>Dim MountObj As Integer Dim ShieldObj As Integer</vb>

Then find "If UserList(UserIndex).WeaponEqpObjIndex > 0 Then WeaponObj = UserList(UserIndex).WeaponEqpObjIndex" and after it add this:

<vb> If UserList(UserIndex).MountEqpObjIndex > 0 Then MountObj = UserList(UserIndex).MountEqpObjIndex

   If UserList(UserIndex).ShieldEqpObjIndex > 0 Then ShieldObj = UserList(UserIndex).ShieldEqpObjIndex</vb>

Now find "'Equipted items" and replace the block of code under it with this:

<vb> For i = FirstModStat To NumStats

           Log "User_UpdateModStats: Updating ModStat ID " & i, CodeTracker '//\\LOGLINE//\\
           .ModStat(i) = .BaseStat(i) + ObjData.AddStat(WeaponObj, i) + ObjData.AddStat(MountObj, i) + ObjData.AddStat(ShieldObj, i) + ObjData.AddStat(ArmorObj, i) + ObjData.AddStat(WingsObj, i)
       Next i</vb>

Find EACH "'Set the paper-doll" section in this function and replace the code under them with this:

<vb>User_ChangeChar ToMap, UserIndex, UserIndex, ObjData.SpriteBody(ObjIndex), ObjData.SpriteHead(ObjIndex), ObjData.SpriteWeapon(ObjIndex), ObjData.SpriteHair(ObjIndex), ObjData.SpriteWings(ObjIndex), ObjData.SpriteMount(ObjIndex), ObjData.SpriteShield(ObjIndex)</vb>

(basically it adds the mount and shield sprite parameters to the User_ChangeChar calls)

Now add this code below to the Select Case structure in this function:

<vb> Case OBJTYPE_MOUNT

           Log "User_UseInvItem: ObjType = OBJTYPE_MOUNT", CodeTracker '//\\LOGLINE//\\
   
           'If currently equipped remove instead
           If UserList(UserIndex).Object(Slot).Equipped Then
               User_RemoveInvItem UserIndex, Slot
               Exit Sub
           End If
   
           'Remove old item if exists
           If UserList(UserIndex).MountEqpObjIndex > 0 Then User_RemoveInvItem UserIndex, UserList(UserIndex).MountEqpSlot
   
           'Equip
           UserList(UserIndex).Object(Slot).Equipped = 1
           UserList(UserIndex).MountEqpObjIndex = UserList(UserIndex).Object(Slot).ObjIndex
           UserList(UserIndex).MountEqpSlot = Slot
           
           'Set the paper-doll
           User_ChangeChar ToMap, UserIndex, UserIndex, ObjData.SpriteBody(ObjIndex), ObjData.SpriteHead(ObjIndex), ObjData.SpriteWeapon(ObjIndex), ObjData.SpriteHair(ObjIndex), ObjData.SpriteWings(ObjIndex), ObjData.SpriteMount(ObjIndex), ObjData.SpriteShield(ObjIndex)
       Case OBJTYPE_SHIELD
           Log "User_UseInvItem: ObjType = OBJTYPE_SHIELD", CodeTracker '//\\LOGLINE//\\
   
           'If currently equipped remove instead
           If UserList(UserIndex).Object(Slot).Equipped Then
               User_RemoveInvItem UserIndex, Slot
               Exit Sub
           End If
   
           'Remove old item if exists
           If UserList(UserIndex).ShieldEqpObjIndex > 0 Then User_RemoveInvItem UserIndex, UserList(UserIndex).ShieldEqpSlot
   
           'Equip
           UserList(UserIndex).Object(Slot).Equipped = 1
           UserList(UserIndex).ShieldEqpObjIndex = UserList(UserIndex).Object(Slot).ObjIndex
           UserList(UserIndex).ShieldEqpSlot = Slot
           
           'Set the paper-doll
           User_ChangeChar ToMap, UserIndex, UserIndex, ObjData.SpriteBody(ObjIndex), ObjData.SpriteHead(ObjIndex), ObjData.SpriteWeapon(ObjIndex), ObjData.SpriteHair(ObjIndex), ObjData.SpriteWings(ObjIndex), ObjData.SpriteMount(ObjIndex), ObjData.SpriteShield(ObjIndex)</vb>


ObjData.cls

Add this code:

<vb>Public Property Get SpriteMount(ByVal Index As Integer) As Integer

   If Index > 0 Then
       If Index <= MaxDatas Then
           ReadyObj Index
           SpriteMount = cData(ObjIndexToDataIndex(Index)).SpriteMount
       End If
   End If

End Property

Public Property Get SpriteShield(ByVal Index As Integer) As Integer

   If Index > 0 Then
       If Index <= MaxDatas Then
           ReadyObj Index
           SpriteShield = cData(ObjIndexToDataIndex(Index)).SpriteShield
       End If
   End If

End Property</vb>


Go to TCP.bas Go to Data_User_Attack and add this to the end of the function: <vb>

   'Dismount when attacking
   For i = 1 To MAX_INVENTORY_SLOTS
       If ObjData.ObjType(UserList(UserIndex).Object(i).ObjIndex) = 7 Then
           Call User_RemoveInvItem(UserIndex, i, True)
           Exit For
       End If
   Next i

</vb>

Map Editor

General.bas

Find SetTile and find "'Check to place/erase a NPC" and replace the section of code under it with this:

<vb> If frmNPCs.Visible Then

       If Button = vbLeftButton Then
           If tY > 1 Then  'Dont place NPCs on tiles y = 1, since their head goes onto tile 0, then uhoh! :o
               If Not Shift Then
                   If frmNPCs.SetOpt.Value Then
                       If MapData(tX, tY).NPCIndex = 0 Then
                           DB_RS.Open "SELECT * FROM npcs WHERE id=" & frmNPCs.NPCList.ListIndex + 1, DB_Conn, adOpenStatic, adLockOptimistic
                           Engine_Char_Make NextOpenCharIndex, DB_RS!char_body, DB_RS!char_head, DB_RS!char_heading, tX, tY, Trim$(DB_RS!Name), DB_RS!char_weapon, DB_RS!char_mount, DB_RS!chr_shield, DB_RS!char_hair, DB_RS!char_wings, DB_RS!id
                           DB_RS.Close
                           AB = 1
                       End If
                   End If
                   If frmNPCs.EraseOpt.Value Then
                       If MapData(tX, tY).NPCIndex <> 0 Then
                           Engine_Char_Erase MapData(tX, tY).NPCIndex
                           AB = 1
                       End If
                   End If
               End If
           End If
       End If
   End If</vb>

Find Game_Map_Switch and find " 'Load NPC". Replace the section of code under it with this:

<vb> If BxFlags And 2 Then

               Get #InfNum, , TempInt
               'Set up pos and startup pos
               DB_RS.Open "SELECT * FROM npcs WHERE id=" & TempInt, DB_Conn, adOpenStatic, adLockOptimistic
               Engine_Char_Make NextOpenCharIndex, DB_RS!char_body, DB_RS!char_head, DB_RS!char_heading, X, Y, Trim$(DB_RS!Name), DB_RS!char_weapon, DB_RS!char_mount, DB_RS!char_shield, DB_RS!char_hair, DB_RS!char_wings, DB_RS!id
               DB_RS.Close
       
           End If</vb>


TileEngine.bas

Find this:

<vb>'Weapons list Public Type WeaponData

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

End Type</vb>

and below it add this:

<vb>'Shields list Public Type ShieldData

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

End Type

'Mount list Public Type MountData

   Walk(1 To 8) As Grh
   Offset As Position

End Type</vb>

Find "Public Type Char" and add to it this:

<vb> Shield As ShieldData

   Mount As MountData</vb>

Find "Type CharShort" and add to it this:

<vb> Mount As Integer 'Mount index

   Shield As Integer       'Shield index</vb>

Find this:

<vb>'Totals Private NumBodies As Integer 'Number of bodies Private NumWings As Integer 'Number of wings Private NumHeads As Integer 'Number of heads Private NumHairs As Integer 'Number of hairs Private NumWeapons As Integer 'Number of weapons</vb>

and add to it this:

<vb>Private NumMounts As Integer 'Number of Mounts Private NumShields As Integer 'Number of Shields</vb>

Find "'********** Public ARRAYS ***********" and add to it this:

<vb>Public MountData() As MountData 'Holds data about Mount structure Public ShieldData() As ShieldData 'Holds data about Shield structure</vb>

Find Engine_Char_Make and replace the sub declaration with this:

<vb>Sub Engine_Char_Make(ByVal CharIndex As Integer, ByVal Body As Integer, ByVal Head As Integer, ByVal Heading As Byte, ByVal X As Integer, ByVal Y As Integer, ByVal Name As String, ByVal Weapon As Integer, ByVal Mount As Integer, ByVal Shield As Integer, ByVal Hair As Integer, ByVal Wings As Integer, ByVal NPCNumber As Integer)</vb>

Find "'Set the apperances" and add to it this:

<vb> CharList(CharIndex).Mount = MountData(Mount)

   CharList(CharIndex).Shield = ShieldData(Shield)</vb>

Find Engine_Init_TileEngine and find in it "'Load graphic data into memory" and add to that this:

<vb> Engine_Init_MountData

   Engine_Init_ShieldData</vb>

Find Engine_Init_BodyData and in the loop "For j = 1 To 8" add this:

<vb>Engine_Init_Grh BodyData(LoopC).Ride(j), CLng(Var_Get(DataPath & "Body.dat", LoopC, "r" & j)), 0</vb>

Outside that sub, either above or below it, add these subs:

<vb>Sub Engine_Init_MountData() '***************************************************************** 'Loads Mount.dat '***************************************************************** Dim LoopC As Long Dim j As Long

   'Get number of Mounts
   NumMounts = CLng(Var_Get(DataPath & "Mount.dat", "INIT", "NumMounts"))
  
   'Resize array
   ReDim MountData(0 To NumMounts) As MountData
  
   'Fill list
   For LoopC = 1 To NumMounts
       For j = 1 To 8
           Engine_Init_Grh MountData(LoopC).Walk(j), CLng(Var_Get(DataPath & "Mount.dat", LoopC, j)), 0
       Next j
       MountData(LoopC).Offset.X = CLng(Var_Get(DataPath & "Mount.dat", LoopC, "OffsetX"))
       MountData(LoopC).Offset.Y = CLng(Var_Get(DataPath & "Mount.dat", LoopC, "OffsetY"))
   Next LoopC

End Sub

Sub Engine_Init_ShieldData() '***************************************************************** 'Loads Shield.dat '***************************************************************** Dim LoopC As Long Dim j As Long

   'Get number of Shields
   NumShields = CLng(Var_Get(DataPath & "Shield.dat", "INIT", "NumShields"))
  
   'Resize array
   ReDim ShieldData(0 To NumShields) As ShieldData
  
   'Fill list
   For LoopC = 1 To NumShields
       For j = 1 To 8
           Engine_Init_Grh ShieldData(LoopC).Walk(j), CLng(Var_Get(DataPath & "Shield.dat", LoopC, j)), 0
           Engine_Init_Grh ShieldData(LoopC).Attack(j), CLng(Var_Get(DataPath & "Shield.dat", LoopC, "a" & j)), 1
       Next j
   Next LoopC

End Sub</vb>

Find Engine_Render_Char and replace the whole sub with this (There's so many changes, this is the fast and easy way. You can pick out what's different from your code and make only the changes you want of course)

<vb>Private Sub Engine_Render_Char(ByVal CharIndex As Long, ByVal PixelOffsetX As Single, ByVal PixelOffsetY As Single)

'*************************************************** 'Draw a character to the screen by the CharIndex 'First variables are set, then all shadows drawn, then character drawn, then extras (emoticons, icons, etc) 'Any variables not handled in "Set the variables" are set in Shadow calls - do not call a second time in the 'normal character rendering calls '***************************************************

Dim TempGrh As Grh Dim Moved As Boolean Dim IconCount As Byte Dim IconOffset As Integer Dim LoopC As Byte Dim Green As Byte Dim RenderColor(1 To 4) As Long Dim TempBlock As MapBlock Dim TempBlock2 As MapBlock Dim HeadGrh As Grh Dim BodyGrh As Grh Dim WeaponGrh As Grh Dim MountGrh As Grh Dim ShieldGrh As Grh Dim HairGrh As Grh Dim WingsGrh As Grh Dim Offset As Position Dim IsOnMount As Boolean

   '***** Set the variables *****
   
   'Is char on mount?
   If Not CharList(CharIndex).Mount.Walk(CharList(CharIndex).Heading).GrhIndex = 0 Then
       IsOnMount = True
       Offset = CharList(CharIndex).Mount.Offset
   End If
   'Set the map block the char is on to the TempBlock, and the block above the user as TempBlock2
   TempBlock = MapData(CharList(CharIndex).Pos.X, CharList(CharIndex).Pos.Y)
   If CharList(CharIndex).Pos.Y > 1 Then TempBlock2 = MapData(CharList(CharIndex).Pos.X, CharList(CharIndex).Pos.Y - 1)
   RenderColor(1) = TempBlock2.Light(1)
   RenderColor(2) = TempBlock2.Light(2)
   RenderColor(3) = TempBlock.Light(3)
   RenderColor(4) = TempBlock.Light(4)
   If CharList(CharIndex).Moving Then
       'If needed, move left and right
       If CharList(CharIndex).ScrollDirectionX <> 0 Then
           CharList(CharIndex).MoveOffset.X = CharList(CharIndex).MoveOffset.X + ScrollPixelsPerFrameX * Sgn(CharList(CharIndex).ScrollDirectionX) * TickPerFrame
           'Start animation
           If IsOnMount Then
               'Is Riding Mount
               CharList(CharIndex).Mount.Walk(CharList(CharIndex).Heading).Started = 1
               CharList(CharIndex).Body.Walk(CharList(CharIndex).Heading).Started = 0
               CharList(CharIndex).Body.Ride(CharList(CharIndex).Heading).Started = 1
           Else
               'Is using their own legs
               CharList(CharIndex).Body.Walk(CharList(CharIndex).Heading).Started = 1
           End If
           'Char moved
           Moved = True
           'Check if we already got there
           If (Sgn(CharList(CharIndex).ScrollDirectionX) = 1 And CharList(CharIndex).MoveOffset.X >= 0) Or (Sgn(CharList(CharIndex).ScrollDirectionX) = -1 And CharList(CharIndex).MoveOffset.X <= 0) Then
               CharList(CharIndex).MoveOffset.X = 0
               CharList(CharIndex).ScrollDirectionX = 0
           End If
       End If
       'If needed, move up and down
       If CharList(CharIndex).ScrollDirectionY <> 0 Then
           CharList(CharIndex).MoveOffset.Y = CharList(CharIndex).MoveOffset.Y + ScrollPixelsPerFrameY * Sgn(CharList(CharIndex).ScrollDirectionY) * TickPerFrame
           'Start animation
           If IsOnMount Then
               'Is Riding Mount
               CharList(CharIndex).Mount.Walk(CharList(CharIndex).Heading).Started = 1
               CharList(CharIndex).Body.Walk(CharList(CharIndex).Heading).Started = 0
               CharList(CharIndex).Body.Ride(CharList(CharIndex).Heading).Started = 1
           Else
               'Is using their own legs
               CharList(CharIndex).Body.Walk(CharList(CharIndex).Heading).Started = 1
           End If
           'Char moved
           Moved = True
           'Check if we already got there
           If (Sgn(CharList(CharIndex).ScrollDirectionY) = 1 And CharList(CharIndex).MoveOffset.Y >= 0) Or (Sgn(CharList(CharIndex).ScrollDirectionY) = -1 And CharList(CharIndex).MoveOffset.Y <= 0) Then
               CharList(CharIndex).MoveOffset.Y = 0
               CharList(CharIndex).ScrollDirectionY = 0
           End If
       End If
   End If
   'Update movement reset timer
   If CharList(CharIndex).ScrollDirectionX = 0 Or CharList(CharIndex).ScrollDirectionY = 0 Then
       'If done moving stop animation
       If Not Moved Then
           If CharList(CharIndex).Body.Walk(CharList(CharIndex).Heading).Started Then
               'Stop animation
               If IsOnMount Then
                   'Is Riding Mount
                   CharList(CharIndex).Mount.Walk(CharList(CharIndex).Heading).Started = 0
                   CharList(CharIndex).Mount.Walk(CharList(CharIndex).Heading).FrameCounter = 1
                   CharList(CharIndex).Body.Ride(CharList(CharIndex).Heading).Started = 0
                   CharList(CharIndex).Body.Ride(CharList(CharIndex).Heading).FrameCounter = 1
               Else
                   'Is using own legs
                   CharList(CharIndex).Body.Walk(CharList(CharIndex).Heading).Started = 0
                   CharList(CharIndex).Body.Walk(CharList(CharIndex).Heading).FrameCounter = 1
               End If
               CharList(CharIndex).Moving = False
               If CharList(CharIndex).ActionIndex = 1 Then CharList(CharIndex).ActionIndex = 0
           End If
       End If
   End If
   'Set the pixel offset
   PixelOffsetX = PixelOffsetX + CharList(CharIndex).MoveOffset.X
   PixelOffsetY = PixelOffsetY + CharList(CharIndex).MoveOffset.Y
   'Save the values in the realpos variable
   CharList(CharIndex).RealPos.X = PixelOffsetX
   CharList(CharIndex).RealPos.Y = PixelOffsetY
   '***** Render Shadows *****
   'Draw Body
   If CharList(CharIndex).ActionIndex <= 1 Then
       'Shadow
       If IsOnMount Then
           Engine_Render_Grh CharList(CharIndex).Body.Ride(CharList(CharIndex).Heading), PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, 1, 1, True, ShadowColor, ShadowColor, ShadowColor, ShadowColor, 1
           Engine_Render_Grh CharList(CharIndex).Mount.Walk(CharList(CharIndex).Heading), PixelOffsetX, PixelOffsetY, 1, 1, False, ShadowColor, ShadowColor, ShadowColor, ShadowColor, 1
       Else
           Engine_Render_Grh CharList(CharIndex).Body.Walk(CharList(CharIndex).Heading), PixelOffsetX, PixelOffsetY, 1, 1, True, ShadowColor, ShadowColor, ShadowColor, ShadowColor, 1
           Engine_Render_Grh CharList(CharIndex).Weapon.Walk(CharList(CharIndex).Heading), PixelOffsetX, PixelOffsetY, 1, 1, True, ShadowColor, ShadowColor, ShadowColor, ShadowColor, 1
           Engine_Render_Grh CharList(CharIndex).Shield.Walk(CharList(CharIndex).Heading), PixelOffsetX, PixelOffsetY, 1, 1, True, ShadowColor, ShadowColor, ShadowColor, ShadowColor, 1
       End If
   Else
       'Start attack animation
       CharList(CharIndex).Body.Attack(CharList(CharIndex).Heading).Started = 0
       CharList(CharIndex).Weapon.Attack(CharList(CharIndex).Heading).FrameCounter = 1
       'Shadow
       Engine_Render_Grh CharList(CharIndex).Body.Attack(CharList(CharIndex).Heading), PixelOffsetX, PixelOffsetY, 1, 1, False, ShadowColor, ShadowColor, ShadowColor, ShadowColor, , 1
       Engine_Render_Grh CharList(CharIndex).Weapon.Attack(CharList(CharIndex).Heading), PixelOffsetX, PixelOffsetY, True, True, False, ShadowColor, ShadowColor, ShadowColor, ShadowColor, , 1
       'Check if animation has stopped
       If CharList(CharIndex).Body.Attack(CharList(CharIndex).Heading).Started = 0 Then CharList(CharIndex).ActionIndex = 0
   End If
   'Draw Head
   If CharList(CharIndex).Aggressive > 0 Then
       'Aggressive
       If CharList(CharIndex).BlinkTimer > 0 Then
           CharList(CharIndex).BlinkTimer = CharList(CharIndex).BlinkTimer - ElapsedTime
           'Blinking
           Engine_Render_Grh CharList(CharIndex).Head.AgrBlink(CharList(CharIndex).HeadHeading), PixelOffsetX + CharList(CharIndex).Body.HeadOffset.X, PixelOffsetY + CharList(CharIndex).Body.HeadOffset.Y, True, False, True, ShadowColor, ShadowColor, ShadowColor, ShadowColor, 1
       Else
           'Normal
           Engine_Render_Grh CharList(CharIndex).Head.AgrHead(CharList(CharIndex).HeadHeading), PixelOffsetX + CharList(CharIndex).Body.HeadOffset.X, PixelOffsetY + CharList(CharIndex).Body.HeadOffset.Y, True, False, True, ShadowColor, ShadowColor, ShadowColor, ShadowColor, 1
       End If
   Else
       'Not Aggressive
       If CharList(CharIndex).BlinkTimer > 0 Then
           CharList(CharIndex).BlinkTimer = CharList(CharIndex).BlinkTimer - ElapsedTime
           'Blinking
           Engine_Render_Grh CharList(CharIndex).Head.Blink(CharList(CharIndex).HeadHeading), PixelOffsetX + CharList(CharIndex).Body.HeadOffset.X + Offset.X, PixelOffsetY + CharList(CharIndex).Body.HeadOffset.Y + Offset.Y, True, False, True, ShadowColor, ShadowColor, ShadowColor, ShadowColor, 1
       Else
           'Normal
           Engine_Render_Grh CharList(CharIndex).Head.Head(CharList(CharIndex).HeadHeading), PixelOffsetX + CharList(CharIndex).Body.HeadOffset.X + Offset.X, PixelOffsetY + CharList(CharIndex).Body.HeadOffset.Y + Offset.Y, True, False, True, ShadowColor, ShadowColor, ShadowColor, ShadowColor, 1
       End If
   End If
   'Hair
   Engine_Render_Grh CharList(CharIndex).Hair.Hair(CharList(CharIndex).HeadHeading), PixelOffsetX + CharList(CharIndex).Body.HeadOffset.X, PixelOffsetY + CharList(CharIndex).Body.HeadOffset.Y, True, False, True, ShadowColor, ShadowColor, ShadowColor, ShadowColor, , 1
   '***** Render Character *****
   '***** (When updating this, make sure you copy it to the NPCEditor and MapEditor, too!) *****
   If IsOnMount Then
       CharList(CharIndex).Weapon.Walk(CharList(CharIndex).Heading).FrameCounter = CharList(CharIndex).Mount.Walk(CharList(CharIndex).Heading).FrameCounter
   Else
       CharList(CharIndex).Weapon.Walk(CharList(CharIndex).Heading).FrameCounter = CharList(CharIndex).Body.Walk(CharList(CharIndex).Heading).FrameCounter
   End If
   'The body, weapon and wings
   If CharList(CharIndex).ActionIndex <= 1 Then
       'Walking
       If IsOnMount Then
           BodyGrh = CharList(CharIndex).Body.Ride(CharList(CharIndex).Heading)
           MountGrh = CharList(CharIndex).Mount.Walk(CharList(CharIndex).Heading)
           
           ' animate weapon/shield
           CharList(CharIndex).Weapon.Walk(CharList(CharIndex).Heading).FrameCounter = CharList(CharIndex).Mount.Walk(CharList(CharIndex).Heading).FrameCounter
           CharList(CharIndex).Shield.Walk(CharList(CharIndex).Heading).FrameCounter = CharList(CharIndex).Mount.Walk(CharList(CharIndex).Heading).FrameCounter
       Else
           BodyGrh = CharList(CharIndex).Body.Walk(CharList(CharIndex).Heading)
           
           ' animate weapon/shield
           CharList(CharIndex).Weapon.Walk(CharList(CharIndex).Heading).FrameCounter = CharList(CharIndex).Body.Walk(CharList(CharIndex).Heading).FrameCounter
           CharList(CharIndex).Shield.Walk(CharList(CharIndex).Heading).FrameCounter = CharList(CharIndex).Body.Walk(CharList(CharIndex).Heading).FrameCounter
           
           WeaponGrh = CharList(CharIndex).Weapon.Walk(CharList(CharIndex).Heading)
           ShieldGrh = CharList(CharIndex).Shield.Walk(CharList(CharIndex).Heading)
       End If
       
       
       WingsGrh = CharList(CharIndex).Wings.Walk(CharList(CharIndex).Heading)
   Else
       'Attacking
       BodyGrh = CharList(CharIndex).Body.Attack(CharList(CharIndex).Heading)
       WeaponGrh = CharList(CharIndex).Weapon.Attack(CharList(CharIndex).Heading)
       WingsGrh = CharList(CharIndex).Wings.Attack(CharList(CharIndex).Heading)
       
       CharList(CharIndex).Weapon.Attack(CharList(CharIndex).Heading).FrameCounter = CharList(CharIndex).Body.Attack(CharList(CharIndex).Heading).FrameCounter
       CharList(CharIndex).Shield.Attack(CharList(CharIndex).Heading).FrameCounter = CharList(CharIndex).Body.Attack(CharList(CharIndex).Heading).FrameCounter
   End If
   
   'The head
   If CharList(CharIndex).Aggressive > 0 Then  'Aggressive
       If CharList(CharIndex).BlinkTimer > 0 Then HeadGrh = CharList(CharIndex).Head.AgrBlink(CharList(CharIndex).HeadHeading) Else HeadGrh = CharList(CharIndex).Head.AgrHead(CharList(CharIndex).HeadHeading)
   Else    'Non-aggressive
       If CharList(CharIndex).BlinkTimer > 0 Then HeadGrh = CharList(CharIndex).Head.Blink(CharList(CharIndex).HeadHeading) Else HeadGrh = CharList(CharIndex).Head.Head(CharList(CharIndex).HeadHeading)
   End If
   
   'The hair
   HairGrh = CharList(CharIndex).Hair.Hair(CharList(CharIndex).HeadHeading)
       
   '*** NORTH / NORTHEAST *** (1.Weapon 2.Body 3.Head 4.Hair 5.Wings)
   If CharList(CharIndex).Heading = NORTH Or CharList(CharIndex).Heading = NORTHEAST Then
       Engine_Render_Grh MountGrh, PixelOffsetX, PixelOffsetY, True, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh WeaponGrh, PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, True, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh ShieldGrh, PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, True, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh BodyGrh, PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, 1, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh HeadGrh, PixelOffsetX + CharList(CharIndex).Body.HeadOffset.X + Offset.X, PixelOffsetY + CharList(CharIndex).Body.HeadOffset.Y + Offset.Y, 1, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh HairGrh, PixelOffsetX + CharList(CharIndex).Body.HeadOffset.X + Offset.X, PixelOffsetY + CharList(CharIndex).Body.HeadOffset.Y + Offset.Y, 1, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh WingsGrh, PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, True, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       
   '*** EAST / SOUTHEAST *** (1.Body 2.Head 3.Hair 4.Wings 5.Weapon)
   ElseIf CharList(CharIndex).Heading = EAST Or CharList(CharIndex).Heading = SOUTHEAST Then
       Engine_Render_Grh MountGrh, PixelOffsetX, PixelOffsetY, True, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh ShieldGrh, PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, True, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh BodyGrh, PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, 1, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh HeadGrh, PixelOffsetX + CharList(CharIndex).Body.HeadOffset.X + Offset.X, PixelOffsetY + CharList(CharIndex).Body.HeadOffset.Y + Offset.Y, 1, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh HairGrh, PixelOffsetX + CharList(CharIndex).Body.HeadOffset.X + Offset.X, PixelOffsetY + CharList(CharIndex).Body.HeadOffset.Y + Offset.Y, 1, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh WingsGrh, PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, True, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh WeaponGrh, PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, True, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       
       
   '*** SOUTH / SOUTHWEST *** (1.Wings 2.Body 3.Head 4.Hair 5.Weapon)
   ElseIf CharList(CharIndex).Heading = SOUTH Or CharList(CharIndex).Heading = SOUTHWEST Then
       Engine_Render_Grh WingsGrh, PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, True, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh BodyGrh, PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, 1, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh HeadGrh, PixelOffsetX + CharList(CharIndex).Body.HeadOffset.X + Offset.X, PixelOffsetY + CharList(CharIndex).Body.HeadOffset.Y + Offset.Y, 1, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh HairGrh, PixelOffsetX + CharList(CharIndex).Body.HeadOffset.X + Offset.X, PixelOffsetY + CharList(CharIndex).Body.HeadOffset.Y + Offset.Y, 1, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh WeaponGrh, PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, True, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh ShieldGrh, PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, True, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh MountGrh, PixelOffsetX, PixelOffsetY, True, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       
   '*** WEST / NORTHWEST *** (1.Weapon 1.Body 2.Head 3.Hair 4.Wings)
   ElseIf CharList(CharIndex).Heading = WEST Or CharList(CharIndex).Heading = NORTHWEST Then
       Engine_Render_Grh WeaponGrh, PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, True, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh MountGrh, PixelOffsetX, PixelOffsetY, True, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh BodyGrh, PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, 1, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh HeadGrh, PixelOffsetX + CharList(CharIndex).Body.HeadOffset.X + Offset.X, PixelOffsetY + CharList(CharIndex).Body.HeadOffset.Y + Offset.Y, 1, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh HairGrh, PixelOffsetX + CharList(CharIndex).Body.HeadOffset.X + Offset.X, PixelOffsetY + CharList(CharIndex).Body.HeadOffset.Y + Offset.Y, 1, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh ShieldGrh, PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, True, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
       Engine_Render_Grh WingsGrh, PixelOffsetX + Offset.X, PixelOffsetY + Offset.Y, True, 0, True, RenderColor(1), RenderColor(2), RenderColor(3), RenderColor(4)
   End If
   
   '***** Render Extras *****
   'Check to draw the health or not
   If CharList(CharIndex).HealthPercent > 0 Then
       'Draw name/health over head
       Engine_Render_Text CharList(CharIndex).Name & " " & CharList(CharIndex).HealthPercent & "%", PixelOffsetX - 32 + Offset.X, PixelOffsetY - 36 + Offset.Y, 96, RenderColor(1), DT_TOP Or DT_CENTER
   Else
       'Draw name over head
       Engine_Render_Text CharList(CharIndex).Name, PixelOffsetX - 32 + Offset.X, PixelOffsetY - 36 + Offset.Y, 96, RenderColor(1), DT_TOP Or DT_CENTER
   End If

End Sub</vb>

Optional: Sound

Optional stuff here. If you want a sound to play when you mount or ride your mount, add this to the code above:

in the client, open TileEngine.bas

find this:

<vb>'Mount list Public Type MountData</vb>

add this:

<vb> MoveSndNum As Integer

   EquipSndNum As Integer
   MoveSnd As DirectSoundSecondaryBuffer8
   EquipSnd As DirectSoundSecondaryBuffer8</vb>

find Engine_Init_MountData and add this to the 'Fill List loop

<vb> MountData(LoopC).MoveSndNum = CLng(Var_Get(DataPath & "Mount.dat", LoopC, "MoveSnd"))

       MountData(LoopC).EquipSndNum = CLng(Var_Get(DataPath & "Mount.dat", LoopC, "EquipSnd"</vb>

Find Engine_Init_TileEngine and add this above "'Start the engine"

<vb> 'Set Mount Sounds

   Dim i As Integer
   For i = 0 To UBound(MountData)
       Sound_Set MountData(i).MoveSnd, MountData(i).MoveSndNum
       Sound_Set MountData(i).EquipSnd, MountData(i).EquipSndNum
   Next i</vb>

find Engine_Render_Char and locate this:

<vb>If CharList(CharIndex).Moving Then</vb>

further down find:

<vb> 'Start animation

           If IsOnMount Then</vb>

right above the ELSE that follows it, add this:

<vb> 'Play Mount Movement Sound

               If (Not CharList(CharIndex).Mount.MoveSnd.GetStatus = DSBSTATUS_PLAYING) Then
                   Sound_Play CharList(CharIndex).Mount.MoveSnd, DSBPLAY_DEFAULT
               End If</vb>

further down find "'If needed, move up and down" and below that find "If IsOnMount Then" and right above the ELSE that follows it add this:

<vb> 'Play Mount Movement Sound

               If (Not CharList(CharIndex).Mount.MoveSnd.GetStatus = DSBSTATUS_PLAYING) Then
                   Sound_Play CharList(CharIndex).Mount.MoveSnd, DSBPLAY_DEFAULT
               End If</vb>

Now go to Data_Server_ChangeChar and find

<vb>If Not DontSetData Then CharList(CharIndex).Mount = MountData(CharMount)</vb>

and below that add this:

<vb> If (Not CharMount = 0) Then

           Sound_Play MountData(CharMount).EquipSnd, DSBPLAY_DEFAULT
       End If</vb>

Now open the Mount.dat file and add this to the bottom:

<vb>MoveSnd=10 EquipSnd=9 </vb>

Now download the sounds below and put them in the Sfx directory. Update the Sfx.ini file to "NumSfx=10"

Sounds: http://www.vbgore.com/forums/download/file.php?id=243

If the you have sound files by the name of 9 and 10, then change the above code to the next two free numbers and adjust Sfx.ini accordingly.

Now your horse will make an impressive sound when you mount and while you ride!

End

Ok, unless I missed something, that should be it. You now have shields and mounts. Ok, what I didn't mention before is that your character sprite (while riding the mount) is animated. He will "bounce" and such. Also, you do gain a speed boost with the mount. (in the database part of the tutorial, it is set with "stat_speed"). I designed it so that you can't attack while on the mount, and your weapon/shield are removed while on the mount (until you get back off). You will dismount automatically when attacking. Hope you like!

This tutorial is made by: GoreMania Corrected by: -

Personal tools