[EO2.0]Player movement animations.

Hi guys,

This tutorial will show you how to make a sprite-animation for different actions the player practices, like running, biking or even swimming. The tutorial is out of different parts, you will read them below.

@Content:

Content

1. Needed resources.

2. The plan.

3. Create a work space.

4. New equipment-type == new item-type #1.

5. New equipment-type == new item-type #2.

6. Player <> NPC.

7. Sprite action.

8. Paperdoll action.

9. Download.

10. Questions and Answers.

@NeededResources:

1. Needed resources.

We are going to use those resources, so save them on a place and keep them ready for use.

(I don’t mind if anyone want’s to use them for their own or for whatever else.)

The sprites.

You can choose if you want to use the sized or the unsized versions of the sprites in the tutorial.

[Picture 1] Sized female sprite.

[Picture 2] Sized male sprite.

[Picture 3] Unsized female sprite.

[Picture 4] Unsized male sprite.

Character window.

In this character window you see a new equipment slot, which will be the keyitem.

[Picture 5] Character window replacement.

Items.

A shoes and a bike, 2 items, 2 different speeds, 2 different sprite sheets.

[Picture 6] Shoes.

[Picture 7] Bike.

@ThePlan:

2. The plan.

I will try to explain things carefully, since tutorials may be a good coding experience improvement for some starter coders.

How I will do that? Is by placing a spoiler at each part to explain what we did there.

Some constants, form editing in the frmEditor_Item and placing the needed resources in the client data folder will be done first.

We add a new equipment slot for the bike and the shoes. This requires us to make the item types shoes and bike too.

After this tutorial, players and npc’s will be no longer the same. Since player characters can then perform more body actions.

We will be then making the real work, the player animation.

Then we make the paperdolls work proper with the new sprites.

@CreateAWorkSpace:

3. Create a work space.

Here we start the coding.

But first create the folder “players” inside your “**\EO2.0\client\data files\graphics**” folder.

Place there any or all of of the pictures [Picture 1], [Picture 2], [Picture 3] or [Picture 4].

Go to your “**\EO2.0\client\data files\graphics\items**” folder and place there the pictures [Picture 6] and [Picture 7].

Now replace your actual chataracter.jpg with the one on [Picture 5].

! I will not go too deep into this.
! If you already have more equipments installed, that means you know how to install 1 more equipment slot.
! Well then install one more equipment slot and use “ITEM_TYPE_KEYITEM” as the constant for the new item type wich will be equipped on that slot.
! In your equipments enumeration use “Keyitem” for the new equipment slot enumeration.
! If you have done that, you can skip part 4 of this tutorial.

Now in your client source, open modConstants and add the following constants at the bottom.

(So it’s Client -> modConstants -> bottom) *Lol Dora The Explorer.


' Keyitem type constants ' 

Public Const KEYITEM_TYPE_SHOES As Byte = 0 ' This is the index for the shoes, to check if its equipped. '

Public Const KEYITEM_TYPE_BIKE As Byte = 1 ' This is the index for the bike, to check if its equipped. '

' Player animation '

Public Const SPRITE_TYPE_NPC As Byte = 1 ' This is to tell its an NPC sprite. '

Public Const SPRITE_TYPE_PLAYER As Byte = 2 ' This is to tell its a player sprite. '

Public Const SPRITE_FRAMES As Byte = 20 ' The count of the total frames of a sprite. '

Public Const DIR_UP_LINE As Byte = 0 ' The index number of the UP sprite-line direction of the player sprite. '

Public Const DIR_DOWN_LINE As Byte = 1 ' The index number of the DOWN sprite-line direction of the player sprite. '

Public Const DIR_LEFT_LINE As Byte = 2 ' The index number of the LEFT sprite-line direction of the player sprite. '

Public Const DIR_RIGHT_LINE As Byte = 3 ' The index number of the RIGHT sprite-line direction of the player sprite. '

Public Const WALKING_STOP_FRAME_START As Byte = 0 ' The index number of the first WALKING stop sprite-frame. '

Public Const WALKING_STOP_FRAME_END As Byte = 2 ' The index number of the second WALKING stop sprite-frame. '

Public Const RUNNING_STOP_FRAME_START As Byte = 4 ' The index number of the first RUNNING stop sprite-frame. '

Public Const RUNNING_STOP_FRAME_END As Byte = 6 ' The index number of the second RUNNING stop sprite-frame. '

Public Const BIKING_STOP_FRAME_START As Byte = 8 ' The index number of the first BIKING stop sprite-frame. '

Public Const BIKING_STOP_FRAME_END As Byte = 10 ' The index number of the second BIKING stop sprite-frame. '

Now change the values of the following constants inside your modConstants.


Public Const WALK_SPEED As Byte = 6

Public Const RUN_SPEED As Byte = 7

Now we go Server side, open your modConstants and add the following constants somewhere at the bottom.


' Keyitem type constants '

Public Const KEYITEM_TYPE_SHOES As Byte = 0

Public Const KEYITEM_TYPE_BIKE As Byte = 1

! We need constants to indicate to something in the code. So that’s why we define the constants first, we are gonna use them during the progress.
! Explanation about the constants we added will be told later in the tutorial.
! For now we changed the walking and running speed, that’s because the equipped item will be able to effect the movement speed.
! There is the “SPRITE_TYPE_NPC” and the “SPRITE_TYPE_PLAYER” we added as constants, that’s because we need to say if it is an NPC or a player what will be blitted in the game, as I said NPC’s and Players will no longer be the same.

@EquipmentItem1:

4. New equipment-type == new item-type #1

Now we will create a new equipment type.

First we will add the constants we are gonna use in this part.

Client and server side, open modConstants and find there the following comment.


' Item constants

There will be a list under the comment with constants numbered with values from small to large.

Add in the client and server to that list the following constant with the next large number as value, like in my case the list ends with “ITEM_TYPE_SPELL” wich has a value of “8”. That’s why in my case I have to change the “##” into 9, because the last large value for me is “8”.


Public Const ITEM_TYPE_KEYITEM As Byte = ## ' Change the ## to the next large number in the items constants list.

Now in your client, still in modConstants find and change the values of the following constants.


Public Const EqLeft As Long = 4

Public Const EqOffsetX As Long = 6

Public Const EqColumns As Long = 5

Now the enumerations.

In both the client and server, open modEnumerations and find the following comment.


' Equipment used by Players

In the enumeration list “Equipment” in the client and server, add the following enumeration on a new line right afterShield”.


Keyitem

In your Server find the following 3 subs, they should be right after each other.


SendWornEquipment

SendMapEquipment

SendMapEquipmentTo

Add to the subs “SendWornEquipment” and “SendMapEquipment” the following code-line, add to both of them the same code.

Add it under “Buffer.WriteLong GetPlayerEquipment(index, Shield)”.


Buffer.WriteLong GetPlayerEquipment(index, Keyitem)

Now do the same with the sub “SendMapEquipmentTo”, but note there is “index” replaced with “PlayerNum”, do it also under the shield.


Buffer.WriteLong GetPlayerEquipment(PlayerNum, Keyitem)

Now the server sends the equipment slot value of the “Keyitem”, we need to handle it in the client.

In your client search for the handlers of the “SPlayerWornEq” and the “SMapWornEq” messages.

You should do that by looking into your modHandleData on the sub InitMessages, there you should see where the messages get handled.

In the handler of the “SPlayerWornEq” add this code-line, just the same way as you did server side.


Call SetPlayerEquipment(MyIndex, Buffer.ReadLong, Keyitem)

Now on the handler of “SMapWornEq”, do the same, but note you have to change “MyIndex” there…


Call SetPlayerEquipment(playerNum, Buffer.ReadLong, Keyitem)

Now we are almost done with our new equipment slot.

We just need something to be able to equip it on our new slot, a new item type.

This will require us to do some form editing.

Open frmEditor_Item and search for the combobox cmbType, select it and in the properties window search for “List”.

Add at the end of that list the following item.


Keyitem

Well, the Keyitem equipment-type we just added doesn’t have any paperdoll, but we still need to put it in the paperdoll ordering to avoid errors.

So find the sub called “Main” and at the bottom of that sub, there is a list for ordering the paperdolls.

Add to that list a new ordering place for the “Keyitem”.


PaperdollOrder(5) = Equipment.Keyitem

Now we just need to make sure we can equip the new itemtype “Keyitem” on the Keyitem equipment slot.

We equip things by double-clicking the picInventory in frmMain.

If you take a look at “picInventory_DblClick” sub, you will see if we are not in trade, bank or shop, it will call the sub “SendUseItem”.

If you then take a look at that sub, you will see the message what will be sent to the server is “CUseItem”.

Now go to the server and find the handler sub of “CUseItem”, just like you did before on client side with SPlayerWornEq and SMapWornEq.

You will finally end up on the sub “UseItem”.

Now there is a case-statement for each itemtype.

So we just need to add a new case for the “Keyitem” itemtype.

There are some if-statements in some cases to see if the user of the item meets the requirements.

We need those if-statements also.

Add a new case into the case-statement with the if-statements we need.

Then add the actual code to equip the Keyitem.

You will then end up having added this case to the case-statement.


Case ITEM_TYPE_KEYITEM

' stat requirements '

For i = 1 To Stats.Stat_Count - 1

     If GetPlayerRawStat(index, i) < Item(itemnum).Stat_Req(i) Then

         PlayerMsg index, "You do not meet the stat requirements to equip this item.", BrightRed

         Exit Sub

     End If

Next

' level requirement '

If GetPlayerLevel(index) < Item(itemnum).LevelReq Then

     PlayerMsg index, "You do not meet the level requirement to equip this item.", BrightRed

     Exit Sub

End If

' class requirement '

If Item(itemnum).ClassReq > 0 Then

     If Not GetPlayerClass(index) = Item(itemnum).ClassReq Then

         PlayerMsg index, "You do not meet the class requirement to equip this item.", BrightRed

         Exit Sub

     End If

End If

' access requirement '

If Not GetPlayerAccess(index) >= Item(itemnum).AccessReq Then

     PlayerMsg index, "You do not meet the access requirement to equip this item.", BrightRed

     Exit Sub

End If

If GetPlayerEquipment(index, Keyitem) > 0 Then

     tempItem = GetPlayerEquipment(index, Keyitem)

End If

SetPlayerEquipment index, itemnum, Keyitem

PlayerMsg index, "You equip " & CheckGrammar(Item(itemnum).Name), BrightGreen

TakeInvItem index, itemnum, 1

If tempItem > 0 Then

     GiveInvItem index, tempItem, 0 ' give back the stored item '

     tempItem = 0

End If

Call SendWornEquipment(index)

Call SendMapEquipment(index)

' send the sound '

SendPlayerSound index, GetPlayerX(index), GetPlayerY(index), SoundEntity.seItem, itemnum

We are done with part 1 of adding a new equipment.

And guess what, we are even completely done server side with this tutorial.

Now we will be only working client side.

Here is some explanation about somethings we have met during this part.

! Changing the values of EqLeft, EqOffsetX and [background=rgb(248, 248, 248)]EqColumns[/background] in modConstants was necessary since we had a new character.jpg.
! The EqLeft is to indicate where the first equipment slot is from the left to the right.
! The EqOffsetX is to say what is the distance in the width between each slot.
! And the [background=rgb(248, 248, 248)]EqColumns[/background] is to say how many slots we have.
! In the cmbType in frmEditor_Item we had to put “Keyitem” at the end of the list.
! The items of a combobox list are index based, what means the first item has an index of “0”, the next is “1” and so on.
! In modConstants we have put the value for [background=rgb(248, 248, 248)]ITEM_TYPE_KEYITEM[/background] as the largest number of the item types constants.
! The [background=rgb(248, 248, 248)]ITEM_TYPE_KEYITEM[/background] must have the same value as the index value of “Keyitem” inside the cmbType.
! We have also put a new ordering for the paperdoll of the keyitem and actually it doesn’t support paperdolls.
! I said already we did that to avoid errors.
! The standard value of each PaperdollOrder index is “0”, since it’s a long value.
! There is no equipment index “0”, you can see that in the equipments enumeration, it starts with “1”.
! So when it will try to get the value of the equipment type “0”, we will get an error because there is not equipment type “0”.
! We can also avoid this error by ignoring indexes under 1 or above the max equipments, but sometimes we need errors.

If you compile and test now, you will see you are now able to equip your new item type.

@EquipmentItem2:

5. New equipment-type == new item-type #2

So now we have a new equipment type and a new item type to equip.

As I mentioned before, we have no more server side coding, everything will be client side now.

In this part we are gonna make sure that the equipped keyitem can effect the player speed.

But first we are gonna divide the keyitem type into 2 another types, the shoes and the bike.

We need some form editing in frmEditor_Item.

Make sure you add the following objects into your frmEditor_Item

Frame inside frmEditor_Item : fraKeyitem

Combobox inside fraKeyitem : cmbKeyitem –> Change property value of “Style” to “2 - Dropdown List”.

Frame inside fraKeyitem : fraKeyitemFrame –> Change property value of “index” to “0

HScrollBar inside fraKeyitemFrame(0) : scrlKeyitemSpeed –> Change property value of “Index” to “0”, “Min” to “1” and the value of “Max” to “100”.

Frame inside fraKeyitem : fraKeyitemFrame –> Change property value of “index” to “1

HScrollBar inside fraKeyitemFrame(1) : scrlKeyitemSpeed –> Change property value of “Index” to “1”, “Min” to “1” and the value of “Max” to “100”.

If you did it right, you would end up having this inside the spoiler.

!

Now change the property value of “Visible” for the following objects to “False”.

fraKeyitem, fraKeyitemFrame(0) and fraKeyitemFrame(1).

Add the following items to the cmbKeyitem List property.

Make sure they are ordered the same.


Shoes

Bike

We have done form editing, now let’s go back to coding.

Double-click the cmbType inside your frmEditor_Item.

You will come at the sub “cmbType_Click”.

Add there inbetween all the if-statements the following if-statement.


If (cmbType.ListIndex = ITEM_TYPE_KEYITEM) Then

   fraKeyitem.Visible = True

Else

   fraKeyitem.Visible = False

End If

We need this little sub to hide the fraKeyItemFrame(0) and fraKeyItemFrame(1).

Add it anywhere to your project, it would suit placing at the bottom in your modGeneral.

Note if you place it in any other place, edit the error handler.


Public Sub HideKeyitemFrames() ' Player animation '

Dim i As Integer

   ' If debug mode, handle error then exit out '

   If Options.Debug = 1 Then On Error GoTo errorhandler ' I place an error handler instead of ''On Error Resume Next'', since this is really an error catcher sub. '

   ' On Error Resume Next <-- I have commented out this line, because it is a very big mistake. It is necessary to have all indexes ordered without skipping any index. '

   For i = 0 To frmEditor_Item.fraKeyitemFrame.UBound

      frmEditor_Item.fraKeyitemFrame(i).Visible = False

   Next

' Error handler '

Exit Sub

errorhandler:

   HandleError "HideKeyitemFrames", "modGeneral", Err.Number, Err.Description, Err.Source, Err.HelpContext

   Err.Clear

   Exit Sub

End Sub

In your frmEditor_Item source, browse to the cmbKeyitem Click handler.

That will be the sub “cmbKeyitem_Click”.

Make there an error handler if you want, just like all the other subs.

Place the following code in cmbKeyitem_Click.


If EditorIndex = 0 Or EditorIndex > MAX_ITEMS Then Exit Sub

HideKeyitemFrames

fraKeyitemFrame(cmbKeyitem.ListIndex).Visible = True

Item(EditorIndex).Data1 = cmbKeyitem.ListIndex ' Since the item type "Data1" is not used, we will be using it to store what keyitem type we have. '

Now double-click any of the scrlKeyitemSpeed and make sure you are on the sub “scrlKeyitemSpeed_Change(Index As Integer)”.

Make there an error handler if you want.

Add the following then to the sub “scrlKeyitemSpeed_Change”.


If EditorIndex = 0 Or EditorIndex > MAX_ITEMS Then Exit Sub

fraKeyitemFrame(Index).Caption = "Speed: " & scrlKeyitemSpeed(Index).Value

Item(EditorIndex).Data2 = scrlKeyitemSpeed(Index).Value ' Since the item type "Data2" is not used, we will be using it to store the movement speed the item gives. '

Find the sub “ItemEditorInit”, inside the with-statement place the following inbetween all the other if-statements.


If (frmEditor_Item.cmbType.ListIndex = ITEM_TYPE_KEYITEM) Then

    frmEditor_Item.fraKeyitem.Visible = True

    frmEditor_Item.cmbKeyitem.ListIndex = .Data1

    HideKeyitemFrames

    frmEditor_Item.fraKeyitemFrame(frmEditor_Item.cmbKeyitem.ListIndex).Visible = True

    frmEditor_Item.scrlKeyitemSpeed(frmEditor_Item.cmbKeyitem.ListIndex).Value = .Data2

Else

    frmEditor_Item.fraKeyitem.Visible = False

End If

You can now create a shoes and a bike. With values of speed.

Now we just need to make the speed values actually change the player movement speed.

This will be only working with the sub “ProcessMovement”.

DimKeyItemNum” as a Long value in the sub “ProcessMovement”.


Dim KeyItemNum As Long

Add this code line underIf Options.Debug = 1 Then On Error GoTo errorhandler”.


If GetPlayerEquipment(Index, Keyitem) > 0 And GetPlayerEquipment(Index, Keyitem) <= MAX_ITEMS Then KeyItemNum = GetPlayerEquipment(Index, Keyitem) Else KeyItemNum = 0

Remove the following case-statement from the sub “ProcessMovement”.


Select Case Player(Index).Moving

    Case MOVING_WALKING: MovementSpeed = ((ElapsedTime / 1000) * (RUN_SPEED * SIZE_X))

    Case MOVING_RUNNING: MovementSpeed = ((ElapsedTime / 1000) * (WALK_SPEED * SIZE_X))

    Case Else: Exit Sub

End Select

Now instead of it place this case-statement.


Select Case Player(Index).Moving

    Case MOVING_WALKING ' When walking '

        If KeyItemNum = 0 Then

            MovementSpeed = ((ElapsedTime / 1000) * (WALK_SPEED * SIZE_X)) ' If no keyitem equipped, move with normal speed when walking. '

        Else

            Select Case Item(KeyItemNum).Data1

                Case KEYITEM_TYPE_SHOES

                    MovementSpeed = ((ElapsedTime / 1000) * (WALK_SPEED * SIZE_X)) ' If shoes, move normally when walking. '

                Case KEYITEM_TYPE_BIKE

                    MovementSpeed = ((ElapsedTime / 1000) * (Item(KeyItemNum).Data2 * SIZE_X)) 'If on bike, move with the bike speed even if walking. '

                Case Else

                    MovementSpeed = ((ElapsedTime / 1000) * (WALK_SPEED * SIZE_X)) ' Anything else, move with normal speed wehn walking. '

            End Select

        End If

    Case MOVING_RUNNING ' When running '

        If KeyItemNum = 0 Then

            MovementSpeed = ((ElapsedTime / 1000) * (RUN_SPEED * SIZE_X)) ' If no keyitem equipped, move with normal running speed when running. '

        Else

            Select Case Item(KeyItemNum).Data1

                Case KEYITEM_TYPE_SHOES

                    MovementSpeed = ((ElapsedTime / 1000) * (Item(KeyItemNum).Data2 * SIZE_X)) ' If shoes, move with shoes speed when running. '

                Case KEYITEM_TYPE_BIKE

                    MovementSpeed = ((ElapsedTime / 1000) * (Item(KeyItemNum).Data2 * SIZE_X)) 'If on bike, move with the bike speed even when running. '

                Case Else

                    MovementSpeed = ((ElapsedTime / 1000) * (RUN_SPEED * SIZE_X)) ' Anything else, move with normal speed wehn running. '

            End Select

        End If

    Case Else: Exit Sub

End Select

Well done, now if you compile it and test it you will see the shoes makes you run with it’s speed when holding shift. The bike makes you have high speed with or without shift being down.

@PlayersNPCNotSame:

6. Player <> NPC.

You know the idea of humans and animals are the same?

Well I personally think they are not.

This will now be the case on your project, players no longer are like NPC’s.

Find the following comment inside your modDirectDraw7.


' gfx buffers

In the list under it, add the following line.


Public DDS_PlayerSprites() As DirectDrawSurface7

Now scroll down a little to the list of the following comment.


' descriptions

Add to that list the following line.


Public DDSD_PlayerSprites() As DDSURFACEDESC2

Now scroll one more town down to the list of the timers.

Add this line there.


Public PlayerSpriteTimer() As Long

And in the list of “Number of graphic files” add the following line.


Public NumPlayerSprites As Long

Now we have created the workspace to seperate players from NPC’s, add the following sub at the bottom of your modDatabase.


Public Sub CheckPlayerSprites()

Dim i As Long

    ' If debug mode, handle error then exit out '

    If Options.Debug = 1 Then On Error GoTo errorhandler

    i = 1

    While FileExist(GFX_PATH & "players\" & i & GFX_EXT)

        NumPlayerSprites = NumPlayerSprites + 1

        i = i + 1

    Wend

    If NumPlayerSprites = 0 Then Exit Sub

    ReDim DDS_PlayerSprites(1 To NumPlayerSprites)

    ReDim DDSD_PlayerSprites(1 To NumPlayerSprites)

    ReDim PlayerSpriteTimer(1 To NumPlayerSprites)

    ' Error handler '

    Exit Sub

errorhandler:

    HandleError "CheckPlayerSprites", "modDatabase", Err.Number, Err.Description, Err.Source, Err.HelpContext

    Err.Clear

    Exit Sub

End Sub

All right, we have the sub, now the caller.

Find the following comment inside your modGeneral.


' DX7 Master Object is already created, early binding

Add to that list the following line.


Call CheckPlayerSprites

Now find the following comment inside your modDirectDraw7.


' Unload DirectDraw

Add there in the list the following code.


    For i = 1 To NumPlayerSprites

        Set DDS_PlayerSprites(i) = Nothing

        ZeroMemory ByVal VarPtr(DDSD_PlayerSprites(i)), LenB(DDSD_PlayerSprites(i))

    Next

Find the following comment inside your modDirectDraw7


' Y-based render. Renders Players, Npcs and Resources based on Y-axis.

Remove the following code from there.


        If NumCharacters > 0 Then

            ' Players '

            For i = 1 To Player_HighIndex

                If IsPlaying(i) And GetPlayerMap(i) = GetPlayerMap(MyIndex) Then

                    If Player(i).y = y Then

                        Call BltPlayer(i)

                    End If

                End If

            Next

            ' Npcs '

            For i = 1 To Npc_HighIndex

                If MapNpc(i).y = y Then

                    Call BltNpc(i)

                End If

            Next

        End If

Instead of it put the following code.


        If NumCharacters > 0 Then

            ' Npcs '

            For i = 1 To Npc_HighIndex

                If MapNpc(i).y = y Then

                    Call BltNpc(i)

                End If

            Next

        End If

        If NumPlayerSprites > 0 Then

            ' Players '

            For i = 1 To Player_HighIndex

                If IsPlaying(i) And GetPlayerMap(i) = GetPlayerMap(MyIndex) Then

                    If Player(i).y = y Then

                        Call BltPlayer(i)

                    End If

                End If

            Next

        End If

Now find the following comment inside your modGameLogic and add the following code between the other codes like it.


            If NumPlayerSprites > 0 Then

                For i = 1 To NumPlayerSprites    'Check to unload surfaces '

                    If PlayerSpriteTimer(i) > 0 Then 'Only update surfaces in use '

                        If PlayerSpriteTimer(i) < Tick Then   'Unload the surface '

                            Call ZeroMemory(ByVal VarPtr(DDSD_PlayerSprites(i)), LenB(DDSD_PlayerSprites(i)))

                            Set DDS_PlayerSprites(i) = Nothing

                            PlayerSpriteTimer(i) = 0

                        End If

                    End If

                Next

            End If

Now find the sub BltSprite and add to it an optional variable “SPRITE_TYPE” as a byte which holds a standard value “SPRITE_TYPE_NPC”.

Just change the head of the sub BltSprite to this one.


Private Sub BltSprite(ByVal Sprite As Long, ByVal x2 As Long, y2 As Long, rec As DxVBLib.RECT, Optional ByVal SPRITE_TYPE As Byte = SPRITE_TYPE_NPC)

Now still in the same sub BltSprite, remove the following line.


If Sprite < 1 Or Sprite > NumCharacters Then Exit Sub

Now place instead of it the following code.


    If SPRITE_TYPE = SPRITE_TYPE_NPC Then

        If Sprite < 1 Or Sprite > NumCharacters Then Exit Sub

    ElseIf SPRITE_TYPE = SPRITE_TYPE_PLAYER Then

        If Sprite < 1 Or Sprite > NumPlayerSprites Then Exit Sub

    End If

Now at the end of the sub BltSprite, find and remove the following code.


    Call Engine_BltFast(x, y, DDS_Character(Sprite), rec, DDBLTFAST_WAIT Or DDBLTFAST_SRCCOLORKEY)

Place instead of it, this code.


    If SPRITE_TYPE = SPRITE_TYPE_NPC Then

        Call Engine_BltFast(x, y, DDS_Character(Sprite), rec, DDBLTFAST_WAIT Or DDBLTFAST_SRCCOLORKEY)

    ElseIf SPRITE_TYPE = SPRITE_TYPE_PLAYER Then

        Call Engine_BltFast(x, y, DDS_PlayerSprites(Sprite), rec, DDBLTFAST_WAIT Or DDBLTFAST_SRCCOLORKEY)

    End If

Now find the sub NewCharacterBltSprite, replace the entire sub with this.


Public Sub NewCharacterBltSprite()

Dim Sprite As Long

Dim sRECT As DxVBLib.RECT

Dim dRECT As DxVBLib.RECT

Dim width As Long, height As Long

    ' If debug mode, handle error then exit out

    If Options.Debug = 1 Then On Error GoTo errorhandler

    If frmMenu.cmbClass.ListIndex = -1 Then Exit Sub

    If frmMenu.optMale.Value = True Then

        Sprite = Class(frmMenu.cmbClass.ListIndex + 1).MaleSprite(newCharSprite)

    Else

        Sprite = Class(frmMenu.cmbClass.ListIndex + 1).FemaleSprite(newCharSprite)

    End If

    If Sprite < 1 Or Sprite > NumPlayerSprites Then

        frmMenu.picSprite.Cls

        Exit Sub

    End If

    PlayerSpriteTimer(Sprite) = GetTickCount + SurfaceTimerMax

    If DDS_PlayerSprites(Sprite) Is Nothing Then

        Call InitDDSurf("players\" & Sprite, DDSD_PlayerSprites(Sprite), DDS_PlayerSprites(Sprite))

    End If

    width = DDSD_PlayerSprites(Sprite).lWidth / SPRITE_FRAMES

    height = DDSD_PlayerSprites(Sprite).lHeight / 4

    frmMenu.picSprite.width = width

    frmMenu.picSprite.height = height

    sRECT.top = DIR_DOWN_LINE * height

    sRECT.Bottom = sRECT.top + height

    sRECT.Left = 0

    sRECT.Right = sRECT.Left + width

    dRECT.top = 0

    dRECT.Bottom = height

    dRECT.Left = 0

    dRECT.Right = width

    Call Engine_BltToDC(DDS_PlayerSprites(Sprite), sRECT, dRECT, frmMenu.picSprite)

    ' Error handler

    Exit Sub

errorhandler:

    HandleError "NewCharacterBltSprite", "modDirectDraw7", Err.Number, Err.Description, Err.Source, Err.HelpContext

    Err.Clear

    Exit Sub

End Sub

Now find the sub DrawPlayerName and remove the following if-statement.


    If GetPlayerSprite(Index) < 1 Or GetPlayerSprite(Index) > NumCharacters Then

        TextY = ConvertMapY(GetPlayerY(Index) * PIC_Y) + Player(Index).YOffset - 16

    Else

        ' Determine location for text

        TextY = ConvertMapY(GetPlayerY(Index) * PIC_Y) + Player(Index).YOffset - (DDSD_Character(GetPlayerSprite(Index)).lHeight / 4) + 16

    End If

Now place instead of it the following one.


    If GetPlayerSprite(Index) < 1 Or GetPlayerSprite(Index) > NumPlayerSprites Then ' Player animation

        TextY = ConvertMapY(GetPlayerY(Index) * PIC_Y) + Player(Index).YOffset - 16

    Else

        ' Determine location for text

        TextY = ConvertMapY(GetPlayerY(Index) * PIC_Y) + Player(Index).YOffset - (DDSD_PlayerSprites(GetPlayerSprite(Index)).lHeight / 4) + 16 ' Player animation

    End If

Now find the sub BltPlayer, inside that sub you are gonna find the following variables and change them with the variables next to them.

NumCharacters –-> NumPlayerSprites

DDS_Character –-> DDS_PlayerSprites

CharacterTimer –-> PlayerSpriteTimer

DDSD_Character –-> DDSD_PlayerSprites

Now find the following code inside the BltPlayer sub and remove it.


    ' render the actual sprite

    Call BltSprite(Sprite, x, y, rec)

Instead of it, place the following.


    ' render the actual sprite

    Call BltSprite(Sprite, x, y, rec, SPRITE_TYPE_PLAYER)

I was in a hurry making this, I hope I didn’t forget anything.

If I didn’t forget anything, now your game should load the player sprites from the “players” folder.

But it still reads it as a 4 framed sprite, so it will look pretty weird with the resources I gave you to place there.

@SpriteAction:

7. Sprite action.

Here we will be doing the real thing.

Find and remove the following from the sub DrawPlayerName.


    If GetPlayerSprite(Index) < 1 Or GetPlayerSprite(Index) > NumCharacters Then

        TextY = ConvertMapY(GetPlayerY(Index) * PIC_Y) + Player(Index).YOffset - 16

    Else

        ' Determine location for text

        TextY = ConvertMapY(GetPlayerY(Index) * PIC_Y) + Player(Index).YOffset - (DDSD_Character(GetPlayerSprite(Index)).lHeight / 4) + 16

    End If

And place instead of it the following.


    If GetPlayerSprite(Index) < 1 Or GetPlayerSprite(Index) > NumPlayerSprites Then ' Player animation

        TextY = ConvertMapY(GetPlayerY(Index) * PIC_Y) + Player(Index).YOffset - 16

    Else

        ' Determine location for text

        TextY = ConvertMapY(GetPlayerY(Index) * PIC_Y) + Player(Index).YOffset - (DDSD_PlayerSprites(GetPlayerSprite(Index)).lHeight / 4) + 16 ' Player animation

    End If

Now find the sub [b/BltPlayer[/b] and dim the following variables there.


Dim KeyItemNum As Long

Dim AnimPlus As Long

Now find and remove the following from BltPlayer.


    ' Reset frame

    If Player(Index).Step = 3 Then

        Anim = 0

    ElseIf Player(Index).Step = 1 Then

        Anim = 2

    End If

Place instead of it, the following.


    KeyItemNum = GetPlayerEquipment(Index, Keyitem)  ' Player animation

    If Player(Index).Moving = MOVING_RUNNING Then ' Player animation

        If KeyItemNum > 0 And KeyItemNum <= MAX_ITEMS Then

            If Item(KeyItemNum).Type = ITEM_TYPE_KEYITEM Then

                Select Case Item(KeyItemNum).Data1

                    Case KEYITEM_TYPE_SHOES

                        ' Reset frame

                        If Player(Index).Step = 3 Then

                            Anim = RUNNING_STOP_FRAME_START

                        ElseIf Player(Index).Step = 1 Then

                            Anim = RUNNING_STOP_FRAME_END

                        End If

                    Case KEYITEM_TYPE_BIKE

                        If Player(Index).Step = 3 Then

                            Anim = BIKING_STOP_FRAME_START

                        ElseIf Player(Index).Step = 1 Then

                            Anim = BIKING_STOP_FRAME_END

                        End If

                End Select

            End If

        Else ' If doesn't equip any keyitem, walk normally.

            If Player(Index).Step = 3 Then

                Anim = WALKING_STOP_FRAME_START

            ElseIf Player(Index).Step = 1 Then

                Anim = WALKING_STOP_FRAME_END

            End If

        End If

    Else ' If not running then we use the walking animation

        If KeyItemNum > 0 And KeyItemNum <= MAX_ITEMS Then

            If Item(KeyItemNum).Type = ITEM_TYPE_KEYITEM Then

                Select Case Item(KeyItemNum).Data1

                    Case KEYITEM_TYPE_SHOES

                        ' Reset frame

                        If Player(Index).Step = 3 Then

                            Anim = WALKING_STOP_FRAME_START

                        ElseIf Player(Index).Step = 1 Then

                            Anim = WALKING_STOP_FRAME_END

                        End If

                    Case KEYITEM_TYPE_BIKE

                        If Player(Index).Step = 3 Then

                            Anim = BIKING_STOP_FRAME_START

                        ElseIf Player(Index).Step = 1 Then

                            Anim = BIKING_STOP_FRAME_END

                        End If

                End Select

            End If

        Else

            If Player(Index).Step = 3 Then

                Anim = WALKING_STOP_FRAME_START

            ElseIf Player(Index).Step = 1 Then

                Anim = WALKING_STOP_FRAME_END

            End If

        End If

    End If

Now find and remove the following from the sub BltPlayer.


    ' Check for attacking animation

    If Player(Index).AttackTimer + (attackspeed / 2) > GetTickCount Then

        If Player(Index).Attacking = 1 Then

            Anim = 3

        End If

    Else

        ' If not attacking, walk normally

        Select Case GetPlayerDir(Index)

            Case DIR_UP

                If (Player(Index).YOffset > 8) Then Anim = Player(Index).Step

            Case DIR_DOWN

                If (Player(Index).YOffset < -8) Then Anim = Player(Index).Step

            Case DIR_LEFT

                If (Player(Index).XOffset > 8) Then Anim = Player(Index).Step

            Case DIR_RIGHT

                If (Player(Index).XOffset < -8) Then Anim = Player(Index).Step

        End Select

    End If

Place instead of it, the following.


    ' Check for attacking animation

    If Player(Index).AttackTimer + (attackspeed / 2) > GetTickCount Then

        If Player(Index).Attacking = 1 Then

            Anim = Anim + 1

        End If

    Else

    ' If not attacking, walk normally

        If KeyItemNum > 0 And KeyItemNum <= MAX_ITEMS Then

            If Item(KeyItemNum).Type = ITEM_TYPE_KEYITEM Then

                Select Case Item(KeyItemNum).Data1

                    Case KEYITEM_TYPE_SHOES

                        If Player(Index).Moving = MOVING_RUNNING Then

                            AnimPlus = RUNNING_STOP_FRAME_START

                        ElseIf Player(Index).Moving = MOVING_WALKING Then

                            AnimPlus = WALKING_STOP_FRAME_START

                        End If

                    Case KEYITEM_TYPE_BIKE

                        If Player(Index).Moving = MOVING_RUNNING Then

                            AnimPlus = BIKING_STOP_FRAME_START

                        ElseIf Player(Index).Moving = MOVING_WALKING Then

                            AnimPlus = BIKING_STOP_FRAME_START

                        End If

                End Select

            End If

        End If

        Select Case GetPlayerDir(Index)

            Case DIR_UP

                If (Player(Index).YOffset > 8) Then Anim = Player(Index).Step + AnimPlus

            Case DIR_DOWN

                If (Player(Index).YOffset < -8) Then Anim = Player(Index).Step + AnimPlus

            Case DIR_LEFT

                If (Player(Index).XOffset > 8) Then Anim = Player(Index).Step + AnimPlus

            Case DIR_RIGHT

                If (Player(Index).XOffset < -8) Then Anim = Player(Index).Step + AnimPlus

        End Select

    End If

Now find and remove the following from the sub BltPlayer.


    ' Set the left

    Select Case GetPlayerDir(Index)

        Case DIR_UP

            spritetop = 3

        Case DIR_RIGHT

            spritetop = 2

        Case DIR_DOWN

            spritetop = 0

        Case DIR_LEFT

            spritetop = 1

    End Select

Place instead of it, the following.


    ' Set the left

    Select Case GetPlayerDir(Index)

        Case DIR_UP

            spritetop = DIR_UP_LINE

        Case DIR_RIGHT

            spritetop = DIR_RIGHT_LINE

        Case DIR_DOWN

            spritetop = DIR_DOWN_LINE

        Case DIR_LEFT

            spritetop = DIR_LEFT_LINE

    End Select

Now find and remove the following from the sub BltPlayer.


    With rec

        .top = spritetop * (DDSD_PlayerSprites(Sprite).lHeight / 4)

        .Bottom = .top + (DDSD_PlayerSprites(Sprite).lHeight / 4)

        .Left = Anim * (DDSD_PlayerSprites(Sprite).lWidth / 4)

        .Right = .Left + (DDSD_PlayerSprites(Sprite).lWidth / 4)

    End With

And place instead of it, the following.


    With rec

        .top = spritetop * (DDSD_PlayerSprites(Sprite).lHeight / 4)

        .Bottom = .top + (DDSD_PlayerSprites(Sprite).lHeight / 4)

        .Left = Anim * (DDSD_PlayerSprites(Sprite).lWidth / SPRITE_FRAMES)

        .Right = .Left + (DDSD_PlayerSprites(Sprite).lWidth / SPRITE_FRAMES)

    End With

Now find and remove the following from the sub BltPlayer.


    ' Calculate the X

    x = GetPlayerX(Index) * PIC_X + Player(Index).XOffset - ((DDSD_PlayerSprites(Sprite).lWidth / 4 - 32) / 2)

Place instead of it, the following.


    ' Calculate the X

    x = GetPlayerX(Index) * PIC_X + Player(Index).XOffset - ((DDSD_PlayerSprites(Sprite).lWidth / SPRITE_FRAMES - 32) / 2)

Now find and remove the following from the sub BltPlayer.


    ' Is the player's height more than 32..?

    If (DDSD_PlayerSprites(Sprite).lHeight) > 32 Then

        ' Create a 32 pixel offset for larger sprites

        y = GetPlayerY(Index) * PIC_Y + Player(Index).YOffset - ((DDSD_PlayerSprites(Sprite).lHeight / 4) - 32)

    Else

        ' Proceed as normal

        y = GetPlayerY(Index) * PIC_Y + Player(Index).YOffset

    End If

Place instead of it, the following.


    ' Is the player's height more than 32..?

    If (DDSD_PlayerSprites(Sprite).lHeight) > 32 Then ' Player animation

        ' Create a 32 pixel offset for larger sprites

        y = GetPlayerY(Index) * PIC_Y + Player(Index).YOffset - ((DDSD_PlayerSprites(Sprite).lHeight / 4) - 32) ' Player animation

    Else

        ' Proceed as normal

        y = GetPlayerY(Index) * PIC_Y + Player(Index).YOffset

    End If

Done.

@PaperdollAction:

8. Paperdoll action.

Now we make the paperdoll work. I did not test this, but I trust that’s all what has to be done about it.

Find and remove the following from BltPaperdoll.


    With rec

        .top = spritetop * (DDSD_Paperdoll(Sprite).lHeight / 4)

        .Bottom = .top + (DDSD_Paperdoll(Sprite).lHeight / 4)

        .Left = Anim * (DDSD_Paperdoll(Sprite).lWidth / 4)

        .Right = .Left + (DDSD_Paperdoll(Sprite).lWidth / 4)

    End With

Place instead of it, the following.


    With rec

        .top = spritetop * (DDSD_Paperdoll(Sprite).lHeight / 4)

        .Bottom = .top + (DDSD_Paperdoll(Sprite).lHeight / 4)

        .Left = Anim * (DDSD_Paperdoll(Sprite).lWidth / SPRITE_FRAMES)

        .Right = .Left + (DDSD_Paperdoll(Sprite).lWidth / SPRITE_FRAMES)

    End With

That’s all I believe.

@Download:

9. Download

Here you can download a vanilla version of EO2.0 with the player animations installed on.

In the source code I have put the following comment on each place I have changed something or added something.


' Player animation

You can download it from this forum or Mediafire, also from the attached file with this topic.

10. Questions and answers

1. Would this also work for attacking animations?

With this you can only make movement animations, an attacking animation is not moving, so no.

2. Would these animations be global? Like if I pressed the “running” button, would everyone see me running?

Yes.


Looks good.

Awesome job,

Thank you.

Would this also work for attacking animations?

I think not because it changes the sprite(picture) if you use an item 😉

If you mean like it makes the character play a sprite sheet without moving(on the same place) then no.

This is just for player movement animation, like running or biking, not for emotes, like waving a hand or attacking with animation.

One more question, would these animations be global? Like if I pressed the “running” button, would everyone see me running?

Yes.

Btw, if you have a problem with your attack animation not being showed to other players, you can fix it with this.

http://www.touchofdeathforums.com/community/index.php?/topic/129156-eoevent-system-3-some-bug-fixes/#entry849195

Yes.

Btw, if you have a problem with your attack animation not being showed to other players, you can fix it with this.

http://www.touchofde…es/#entry849195

Well that’s good to see. I will definitely be using this, thanks!

Also, that’s hilarious! I literally just searched on how to fix that. lol

Yes.

Btw, if you have a problem with your attack animation not being showed to other players, you can fix it with this.

http://www.touchofdeathforums.com/community/index.php?/topic/129156-eoevent-system-3-some-bug-fixes/#entry849195

Sorry about the necropost, but the new “charset” model will only render the “walk”, “run” and “bike”, right? What’s the point in the “fishing” and the pokeball sprites? Couldn’t it be used for the attacking frame on EO2.0? Would be very more useful. And can I have a paperdoll to bike? It would be nice for multiple color bikes. Just clean the sprite to make the bike invisible and add a paperdoll option.

Log in to reply