This is my first tutorial, go easy on me :P **Note: This feature uses da_gad_pader's [[EO 2.0]'How to make an attack animation/frame'](http://www.touchofdeathforums.com/smf/index.php/topic,72272.0.html) so other players will be unable to see you punching/kicking, until the issue on that tutorial gets fixed.** Client: In modGameLogic Replace Public Sub CheckAttack with 2 subs ``` Public Sub CheckAttack1() Dim Buffer As clsBuffer Dim attackspeed As Long ' If debug mode, handle error then exit out If Options.Debug = 1 Then On Error GoTo errorhandler If GetKeyState(vbKeyP) < 0 Then If SpellBuffer > 0 Then Exit Sub ' currently casting a spell, can't attack If StunDuration > 0 Then Exit Sub ' stunned, can't attack ' speed from weapon If GetPlayerEquipment(MyIndex, Weapon) > 0 Then attackspeed = Item(GetPlayerEquipment(MyIndex, Weapon)).Speed Else attackspeed = 1000 End If If Player(MyIndex).AttackTimer + attackspeed < GetTickCount Then If Player(MyIndex).Attacking1 = 0 Then With Player(MyIndex) .Attacking1 = 1 .AttackTimer = GetTickCount End With Set Buffer = New clsBuffer Buffer.WriteLong CAttack1 SendData Buffer.ToArray() Set Buffer = Nothing End If End If End If ' Error handler Exit Sub errorhandler: HandleError "CheckAttack1", "modGameLogic", Err.Number, Err.Description, Err.Source, Err.HelpContext Err.Clear Exit Sub End Sub ``` ``` Public Sub CheckAttack2() Dim Buffer As clsBuffer Dim attackspeed As Long ' If debug mode, handle error then exit out If Options.Debug = 1 Then On Error GoTo errorhandler If GetKeyState(vbKeyO) < 0 Then If SpellBuffer > 0 Then Exit Sub ' currently casting a spell, can't attack If StunDuration > 0 Then Exit Sub ' stunned, can't attack ' speed from weapon If GetPlayerEquipment(MyIndex, Weapon) > 0 Then attackspeed = Item(GetPlayerEquipment(MyIndex, Weapon)).Speed Else attackspeed = 1000 End If If Player(MyIndex).AttackTimer + attackspeed < GetTickCount Then If Player(MyIndex).Attacking2 = 0 Then With Player(MyIndex) .Attacking2 = 1 .AttackTimer = GetTickCount End With Set Buffer = New clsBuffer Buffer.WriteLong CAttack2 SendData Buffer.ToArray() Set Buffer = Nothing End If End If End If ' Error handler Exit Sub errorhandler: HandleError "CheckAttack2", "modGameLogic", Err.Number, Err.Description, Err.Source, Err.HelpContext Err.Clear Exit Sub End Sub ``` And in GameLoop ``` Call CheckAttack ' Check to see if player is trying to attack ``` To ``` Call CheckAttack1 ' Check to see if player is trying to attack Call CheckAttack2 ' Check to see if player is trying to attack ``` In ModTypes Private Type PlayerRec ``` Attacking As Byte ``` To ``` Attacking1 As Byte Attacking2 As Byte ``` In ModTypes Private Type MapNpcRec ``` Attacking As Byte ``` To ``` Attacking1 As Byte Attacking2 As Byte ``` In ModDirectDraw7 BltPlayer Add``` Dim AtkTimer As Long ```At the top ``` ' Check for attacking animation If Player(Index).AttackTimer + (attackspeed / 2) > GetTickCount Then If Player(Index).Attacking = 1 Then Anim = 4 End If ```To ``` ' Check for attacking animation If Player(Index).AttackTimer + (attackspeed / 2) > GetTickCount Then If Player(Index).Attacking1 = 1 Then AtkTimer = (GetTickCount - Player(Index).AttackTimer) If AtkTimer < 250 Then Anim = 4 End If If AtkTimer < 500 And AtkTimer >= 250 Then ' Add or remove with same pattern to change frame number Anim = 5 End If If AtkTimer < 750 And AtkTimer >= 500 Then ' Add or remove with same pattern to change frame number Anim = 6 End If If AtkTimer < 1000 And AtkTimer >= 750 Then ' Add or remove with same pattern to change frame number Anim = 7 End If If AtkTimer >= 1000 Then Anim = 0 End If End If If Player(Index).Attacking2 = 1 Then AtkTimer = (GetTickCount - Player(Index).AttackTimer) If AtkTimer < 250 Then Anim = 8 End If If AtkTimer < 500 And AtkTimer >= 250 Then ' Add or remove with same pattern to change frame number Anim = 9 End If If AtkTimer < 750 And AtkTimer >= 500 Then ' Add or remove with same pattern to change frame number Anim = 10 End If If AtkTimer < 1000 And AtkTimer >= 750 Then ' Add or remove with same pattern to change frame number Anim = 11 End If If AtkTimer >= 1000 Then Anim = 0 End If End If ``` And ``` With Player(Index) If .AttackTimer + attackspeed < GetTickCount Then .Attacking = 0 .AttackTimer = 0 End If End With ``` To ``` With Player(Index) If .AttackTimer + attackspeed < GetTickCount Then .Attacking1 = 0 .Attacking2 = 0 .AttackTimer = 0 End If End With ``` And ``` With rec .top = spritetop * (DDSD_Character(Sprite).lHeight / 4) .Bottom = .top + (DDSD_Character(Sprite).lHeight / 4) .Left = Anim * (DDSD_Character(Sprite).lWidth / 4) .Right = .Left + (DDSD_Character(Sprite).lWidth / 4) End With ``` To ``` With rec .top = spritetop * (DDSD_Character(Sprite).lHeight / 4) .Bottom = .top + (DDSD_Character(Sprite).lHeight / 4) .Left = Anim * (DDSD_Character(Sprite).lWidth / 12) ' Number of frames on char sheet .Right = .Left + (DDSD_Character(Sprite).lWidth / 12) ' Number of frames on char sheet End With ``` And ``` ' Calculate the X x = GetPlayerX(Index) * PIC_X + Player(Index).XOffset - ((DDSD_Character(Sprite).lWidth / 4 - 32) / 2) ``` To ``` ' Calculate the X x = GetPlayerX(Index) * PIC_X + Player(Index).XOffset - ((DDSD_Character(Sprite).lWidth / 4 - 96) / 2) ' adjust sprite displacement ``` In ModDirectDraw7 BltNpc Add``` Dim AtkTimer As Long ```At the top ``` ' Check for attacking animation If MapNpc(MapNpcNum).AttackTimer + (attackspeed / 2) > GetTickCount Then If MapNpc(MapNpcNum).Attacking1 = 1 Then Anim = 4 End If ``` To ``` ' Check for attacking animation If MapNpc(MapNpcNum).AttackTimer + (attackspeed / 2) > GetTickCount Then If MapNpc(MapNpcNum).Attacking1 = 1 Then AtkTimer = (GetTickCount - MapNpc(MapNpcNum).AttackTimer) If AtkTimer < 250 Then Anim = 4 End If If AtkTimer < 500 And AtkTimer >= 250 Then ' Add or remove with same pattern to change frame number Anim = 5 End If If AtkTimer < 750 And AtkTimer >= 500 Then ' Add or remove with same pattern to change frame number Anim = 6 End If If AtkTimer < 1000 And AtkTimer >= 750 Then ' Add or remove with same pattern to change frame number Anim = 7 End If If AtkTimer >= 1000 Then Anim = 0 End If End If If MapNpc(MapNpcNum).Attacking2 = 1 Then AtkTimer = (GetTickCount - MapNpc(MapNpcNum).AttackTimer) If AtkTimer < 250 Then Anim = 8 End If If AtkTimer < 500 And AtkTimer >= 250 Then ' Add or remove with same pattern to change frame number Anim = 9 End If If AtkTimer < 750 And AtkTimer >= 500 Then ' Add or remove with same pattern to change frame number Anim = 10 End If If AtkTimer < 1000 And AtkTimer >= 750 Then ' Add or remove with same pattern to change frame number Anim = 11 End If If AtkTimer >= 1000 Then Anim = 0 End If End If ``` And ``` ' Check to see if we want to stop making him attack With MapNpc(MapNpcNum) If .AttackTimer + attackspeed < GetTickCount Then .Attacking = 0 .AttackTimer = 0 End If ``` To ``` With MapNpc(MapNpcNum) If .AttackTimer + attackspeed < GetTickCount Then .Attacking1 = 0 .Attacking2 = 0 .AttackTimer = 0 End If End With ``` And ``` With rec .top = spritetop * (DDSD_Character(Sprite).lHeight / 4) .Bottom = .top + (DDSD_Character(Sprite).lHeight / 4) .Left = Anim * (DDSD_Character(Sprite).lWidth / 4) .Right = .Left + (DDSD_Character(Sprite).lWidth / 4) End With ``` To ``` With rec .top = spritetop * (DDSD_Character(Sprite).lHeight / 4) .Bottom = .top + (DDSD_Character(Sprite).lHeight / 4) .Left = Anim * (DDSD_Character(Sprite).lWidth / 12) ' Number of frames on char sheet .Right = .Left + (DDSD_Character(Sprite).lWidth / 12) ' Number of frames on char sheet End With ``` And ``` ' Calculate the X x = MapNpc(MapNpcNum).x * PIC_X + MapNpc(MapNpcNum).XOffset - ((DDSD_Character(Sprite).lWidth / 4 - 32) / 2) ``` To ``` ' Calculate the X x = MapNpc(MapNpcNum).x * PIC_X + MapNpc(MapNpcNum).XOffset - ((DDSD_Character(Sprite).lWidth / 4 - 96) / 2) ' adjust sprite displacement ``` In modHandleData change Sub HandleAttack to 2 subs ``` Private Sub HandleAttack1(ByVal Index As Long, ByRef Data() As Byte, ByVal StartAddr As Long, ByVal ExtraVar As Long) Dim i As Long Dim Buffer As clsBuffer ' If debug mode, handle error then exit out If Options.Debug = 1 Then On Error GoTo errorhandler Set Buffer = New clsBuffer Buffer.WriteBytes Data() i = Buffer.ReadLong ' Set player to attacking Player(i).Attacking1 = 1 Player(i).AttackTimer = GetTickCount ' Error handler Exit Sub errorhandler: HandleError "HandleAttack", "modHandleData", Err.Number, Err.Description, Err.Source, Err.HelpContext Err.Clear Exit Sub End Sub ``` ``` Private Sub HandleAttack2(ByVal Index As Long, ByRef Data() As Byte, ByVal StartAddr As Long, ByVal ExtraVar As Long) Dim i As Long Dim Buffer As clsBuffer ' If debug mode, handle error then exit out If Options.Debug = 1 Then On Error GoTo errorhandler Set Buffer = New clsBuffer Buffer.WriteBytes Data() i = Buffer.ReadLong ' Set player to attacking Player(i).Attacking2 = 1 Player(i).AttackTimer = GetTickCount ' Error handler Exit Sub errorhandler: HandleError "HandleAttack", "modHandleData", Err.Number, Err.Description, Err.Source, Err.HelpContext Err.Clear Exit Sub End Sub ``` And Sub HandleNpcAttack To ``` Private Sub HandleNpcAttack1(ByVal Index As Long, ByRef Data() As Byte, ByVal StartAddr As Long, ByVal ExtraVar As Long) Dim i As Long Dim Buffer As clsBuffer ' If debug mode, handle error then exit out If Options.Debug = 1 Then On Error GoTo errorhandler Set Buffer = New clsBuffer Buffer.WriteBytes Data() i = Buffer.ReadLong ' Set player to attacking MapNpc(i).Attacking1 = 1 MapNpc(i).AttackTimer = GetTickCount ' Error handler Exit Sub errorhandler: HandleError "HandleNpcAttack", "modHandleData", Err.Number, Err.Description, Err.Source, Err.HelpContext Err.Clear Exit Sub End Sub ``` ``` Private Sub HandleNpcAttack2(ByVal Index As Long, ByRef Data() As Byte, ByVal StartAddr As Long, ByVal ExtraVar As Long) Dim i As Long Dim Buffer As clsBuffer ' If debug mode, handle error then exit out If Options.Debug = 1 Then On Error GoTo errorhandler Set Buffer = New clsBuffer Buffer.WriteBytes Data() i = Buffer.ReadLong ' Set player to attacking MapNpc(i).Attacking2 = 1 MapNpc(i).AttackTimer = GetTickCount ' Error handler Exit Sub errorhandler: HandleError "HandleNpcAttack", "modHandleData", Err.Number, Err.Description, Err.Source, Err.HelpContext Err.Clear Exit Sub End Sub ``` And ``` HandleDataSub(SAttack) = GetAddress(AddressOf HandleAttack) HandleDataSub(SNpcAttack = GetAddress(AddressOf HandleNpcAttack) ``` To ``` HandleDataSub(SAttack1) = GetAddress(AddressOf HandleAttack1) HandleDataSub(SAttack2) = GetAddress(AddressOf HandleAttack2) HandleDataSub(SNpcAttack1) = GetAddress(AddressOf HandleNpcAttack1) HandleDataSub(SNpcAttack2) = GetAddress(AddressOf HandleNpcAttack2) ``` In modEnumerations replaced ``` SAttack SNpcAttack ``` With ``` SAttack1 SAttack2 SNpcAttack1 SNpcAttack2 ``` And ``` CAttack ``` With ``` CAttack1 CAttack2 ``` Server: in modHandleData change ``` HandleDataSub(CAttack) = GetAddress(AddressOf HandleAttack) ``` To ``` HandleDataSub(CAttack1) = GetAddress(AddressOf HandleAttack1) HandleDataSub(CAttack2) = GetAddress(AddressOf HandleAttack2) ``` Sub HandleAttack replaced with 2 subs ``` ' :::::::::::::::::::::::::: ' :: Player attack packet :: ' :::::::::::::::::::::::::: Sub HandleAttack1(ByVal index As Long, ByRef Data() As Byte, ByVal StartAddr As Long, ByVal ExtraVar As Long) Dim i As Long Dim n As Long Dim Damage As Long Dim TempIndex As Long Dim x As Long, y As Long ' can't attack whilst casting If TempPlayer(index).spellBuffer.Spell > 0 Then Exit Sub ' can't attack whilst stunned If TempPlayer(index).StunDuration > 0 Then Exit Sub ' Send this packet so they can see the person attacking 'SendAttack Index ' Try to attack a player For i = 1 To Player_HighIndex TempIndex = i ' Make sure we dont try to attack ourselves If TempIndex index Then TryPlayerAttackPlayer index, i End If Next ' Try to attack a npc For i = 1 To MAX_MAP_NPCS TryPlayerAttackNpc index, i Next ' Check tradeskills Select Case GetPlayerDir(index) Case DIR_UP If GetPlayerY(index) = 0 Then Exit Sub x = GetPlayerX(index) y = GetPlayerY(index) - 1 Case DIR_DOWN If GetPlayerY(index) = Map(GetPlayerMap(index)).MaxY Then Exit Sub x = GetPlayerX(index) y = GetPlayerY(index) + 1 Case DIR_LEFT If GetPlayerX(index) = 0 Then Exit Sub x = GetPlayerX(index) - 1 y = GetPlayerY(index) Case DIR_RIGHT If GetPlayerX(index) = Map(GetPlayerMap(index)).MaxX Then Exit Sub x = GetPlayerX(index) + 1 y = GetPlayerY(index) End Select CheckResource index, x, y End Sub ``` ``` ' :::::::::::::::::::::::::: ' :: Player attack packet :: ' :::::::::::::::::::::::::: Sub HandleAttack2(ByVal index As Long, ByRef Data() As Byte, ByVal StartAddr As Long, ByVal ExtraVar As Long) Dim i As Long Dim n As Long Dim Damage As Long Dim TempIndex As Long Dim x As Long, y As Long ' can't attack whilst casting If TempPlayer(index).spellBuffer.Spell > 0 Then Exit Sub ' can't attack whilst stunned If TempPlayer(index).StunDuration > 0 Then Exit Sub ' Send this packet so they can see the person attacking 'SendAttack Index ' Try to attack a player For i = 1 To Player_HighIndex TempIndex = i ' Make sure we dont try to attack ourselves If TempIndex index Then TryPlayerAttackPlayer index, i End If Next ' Try to attack a npc For i = 1 To MAX_MAP_NPCS TryPlayerAttackNpc index, i Next ' Check tradeskills Select Case GetPlayerDir(index) Case DIR_UP If GetPlayerY(index) = 0 Then Exit Sub x = GetPlayerX(index) y = GetPlayerY(index) - 1 Case DIR_DOWN If GetPlayerY(index) = Map(GetPlayerMap(index)).MaxY Then Exit Sub x = GetPlayerX(index) y = GetPlayerY(index) + 1 Case DIR_LEFT If GetPlayerX(index) = 0 Then Exit Sub x = GetPlayerX(index) - 1 y = GetPlayerY(index) Case DIR_RIGHT If GetPlayerX(index) = Map(GetPlayerMap(index)).MaxX Then Exit Sub x = GetPlayerX(index) + 1 y = GetPlayerY(index) End Select CheckResource index, x, y End Sub ``` In ModEnumerations ``` SAttack SNpcAttack ``` To ``` SAttack1 SAttack2 SNpcAttack1 SNpcAttack2 ``` And ``` CAttack ``` To ``` CAttack1 CAttack2 ``` In ModCombat ``` ' Send this packet so they can see the npc attacking Set Buffer = New clsBuffer Buffer.WriteLong SNpcAttack ``` To``` ' Send this packet so they can see the npc attacking Set Buffer = New clsBuffer Buffer.WriteLong SNpcAttack1 Buffer.WriteLong SNpcAttack2 ```