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](http://www.touchofdeathforums.com/community/index.php?/page/index.html/gallery.html/_/other/sprite-sized-female-1-r146). > > **[Picture 2]** [Sized male sprite](http://www.touchofdeathforums.com/community/index.php?/page/index.html/gallery.html/_/other/sprite-sized-male-1-r147). > > **[Picture 3]** [Unsized female sprite](http://www.touchofdeathforums.com/community/index.php?/page/index.html/gallery.html/_/other/sprite-unsized-female-1-r148). > > **[Picture 4]** [Unsized male sprite](http://www.touchofdeathforums.com/community/index.php?/page/index.html/gallery.html/_/other/sprite-unsized-male-1-r149). > > Character window. > > In this character window you see a new equipment slot, which will be the keyitem. > > **[Picture 5]** [Character window replacement](http://www.touchofdeathforums.com/community/index.php?/page/index.html/gallery.html/_/gui/character-window-r152). > > Items. > > A shoes and a bike, 2 items, 2 different speeds, 2 different sprite sheets. > > **[Picture 6]** [Shoes](http://www.touchofdeathforums.com/community/index.php?/page/index.html/gallery.html/_/item/item-shoes-r150). > > **[Picture 7]** [Bike](http://www.touchofdeathforums.com/community/index.php?/page/index.html/gallery.html/_/item/item-bike-r151). @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 **after** "**Shield**". > > ``` > > 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. > > >! ![](http://img841.imageshack.us/img841/2849/examplet.jpg) > > 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 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 > 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 > 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 > 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. > > [![](http://img831.imageshack.us/img831/4153/mediafireicon.png)](http://www.mediafire.com/download.php?g1us4e0o82ikzw2) [![](http://imageshack.us/a/img29/2193/ebutton3.png)](http://www.freemmorpgmaker.com/files/imagehost/pics/69fceb51df822c18b9c261d34b7595b8.rar) 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. ________________________