Jump to content
Search In
  • More options...
Find results that contain...
Find results in...

[EO] Lightning's Pet System [Completely Bug-Free!]


Yxxe
 Share

Recommended Posts

**Lightning's Pet System**

Hello, and welcome to my tutorial on creating a Basic Pet System. When this tutorial is over, you should have created a solid Pet System base to work on further, which also includes a few key features for any pet system. Before you get started, please make sure you have the following:

* Visual Basic 6 Professional/Enterprise
* Client/Server Source Files
* Basic understanding of the use of the VB6 IDE and Language
* A brain

**Compatable with: Eclipse Origins 2.0.0**

**Translations:**
Below are translations of this tutorial.

[Lightning's Pet System in German by EisKeks](http://www.touchofdeathforums.com/smf/index.php/topic,71065.new.html#new) (OUTDATED)

**Optional Mods:**
Below are modifications other users have created for this pet system. It is recommended for most mods that you follow this tutorial first, then go and mod afterwards. I have also given the tutorial a star rating (out of five) and a brief review. Please do not PM me for support of these mods, they are not created by me, and questions should be asked to the respective creators.

>! [Multiple Pets (Author - RyokuHasu)](http://www.touchofdeathforums.com/smf/index.php/topic,69925.0.html)
This tutorial will help if you have a specific class that requires summoning different pets. It's a fairly necessary addition, simple to add, but fairly limited in its use.  :bstar: :bstar: :bstar: :rstar: :rstar: (3/5)
>! [Modifications 2.5 Nova (Author - Richy)](http://www.touchofdeathforums.com/smf/index.php/topic,69078.0.html)
Not a tutorial, but a very good mod if Visual Basic 6 is not available to you. Richy has taken my Base Pet System and modded it to his and others' needs. It also comes with other various features, which I will not go in to.  :bstar: :bstar: :bstar: :bstar: :rstar: (4/5)
>! Multiple Items and Percentile Drops Addition (Author - Xlithan)
>! >! For anybody who has added Multiple Item Drops and Percentiles, Find:
>! ```
' Drop the goods if they get it
```in NPCAttackNPC sub, and change to this:
>!      ```
' Drop the goods if they get it
        For n = 1 To MAX_NPC_DROPS
            If Npc(Victim).DropItem(n) = 0 Then Exit For
            If Rnd <= Npc(Victim).DropChance(n) Then
                Call SpawnItem(Npc(Victim).DropItem(n), Npc(Victim).DropItemValue(n), MapNum, MapNpc(MapNum).Npc(Victim).x, MapNpc(MapNum).Npc(Victim).y)
            End If
        Next
```

**Outcome**

At the end of this tutorial, you should be able to use a pet, maybe something like this:
![](http://i801.photobucket.com/albums/yy294/Adrammelech_2009/SummonedPet.png)
![](http://i801.photobucket.com/albums/yy294/Adrammelech_2009/PetCombat.png)

**Client Side**

First, we will work on the client side code. This is mainly sending commands to the server to control your pet. These commands include:

* Calling your Pet
* Attack a Target
* Simple NPC Following
* Letting your pet wander around the map
* Disbanding your pet.

First of all, you will need to work your way to modGameLogic.

Scroll to the bottom of the module and paste these five procedures:

```
Sub SpawnPet(ByVal Index As Long)
    Dim Buffer As clsBuffer

    Set Buffer = New clsBuffer

    Buffer.WriteLong CSpawnPet

    SendData Buffer.ToArray()

    Set Buffer = Nothing

End Sub

Sub PetFollow(ByVal Index As Long)
    Dim Buffer As clsBuffer

    Set Buffer = New clsBuffer

    Buffer.WriteLong CPetFollowOwner

    SendData Buffer.ToArray()

    Set Buffer = Nothing
End Sub

Sub PetAttack(ByVal Index As Long)
    Dim Buffer As clsBuffer

    Set Buffer = New clsBuffer

    Buffer.WriteLong CPetAttackTarget

    SendData Buffer.ToArray()

    Set Buffer = Nothing
End Sub

Sub PetWander(ByVal Index As Long)
    Dim Buffer As clsBuffer

    Set Buffer = New clsBuffer

    Buffer.WriteLong CPetWander

    SendData Buffer.ToArray()

    Set Buffer = Nothing
End Sub

Sub PetDisband(ByVal Index As Long)
    Dim Buffer As clsBuffer

    Set Buffer = New clsBuffer

    Buffer.WriteLong CPetDisband

    SendData Buffer.ToArray()

    Set Buffer = Nothing
End Sub
```
These procedures are the commands for controlling your pet. Note the names of the procedures are named appropriately for each command.

Next, you will need to open up modEnumerations.
Scroll to the bottom of the client-side enumerations (The ones beginning with a "C"), and paste this above CMSG_COUNT:

```
CSpawnPet
CPetFollowOwner
CPetAttackTarget
CPetWander
CPetDisband
```
Next, go to modHandleData and replace "Sub HandleSpawnNpc" with this:

```
Private Sub HandleSpawnNpc(ByVal Index As Long, ByRef Data() As Byte, ByVal StartAddr As Long, ByVal ExtraVar As Long)
Dim n 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()
    n = Buffer.ReadLong

    With MapNpc(n)
        .Num = Buffer.ReadLong
        .x = Buffer.ReadLong
        .y = Buffer.ReadLong
        .Dir = Buffer.ReadLong
        .IsPet = Buffer.ReadByte
        .PetData.Name = Buffer.ReadString
        .PetData.Owner = Buffer.ReadLong
        ' Client use only
        .XOffset = 0
        .YOffset = 0
        .Moving = 0
    End With

    ' Error handler
    Exit Sub
errorhandler:
    HandleError "HandleSpawnNpc", "modHandleData", Err.Number, Err.Description, Err.Source, Err.HelpContext
    Err.Clear
    Exit Sub
End Sub
```
After you have done this, you will need to create five buttons or labels to trigger each of the commands.

Place them in the options menu, or in any other menu you wish. After you have created them, they should look something like this:

![](http://i801.photobucket.com/albums/yy294/Adrammelech_2009/Commands.png)

You will then need to call each of the procedures earlier for each of their respective functions. The parameter you will need to pass into them will be "MyIndex" for each.

Next, go to modHandleData and add this procedure at the bottom:

```
Private Sub HandleNPCCache(ByVal Index As Long, ByRef Data() As Byte, ByVal StartAddr As Long, ByVal ExtraVar As Long)
    Dim Buffer As clsBuffer
    Dim PIndex As Long
    Dim MapNum As Long
    Dim NPCNum As Long

    Dim i As Long

    Set Buffer = New clsBuffer

    Buffer.WriteBytes Data()

    MapNum = Buffer.ReadLong
    NPCNum = Buffer.ReadLong

    Map.Npc(NPCNum) = Buffer.ReadLong
    MapNpc(NPCNum).Num = Buffer.ReadLong

    SaveMap (MapNum)

    Set Buffer = Nothing

End Sub
```
Go to Sub InitMessages in modHandleData still, and add this just above "Exit Sub":

```
HandleDataSub(SNPCCache) = GetAddress(AddressOf HandleNPCCache)
```
Finally, you will need to add the code below to the bottom of "MapNpcRec" in modTypes:

```
  'Pet Data
    IsPet As Byte
    PetData As PetRec
```
Below "Dir As Byte" in PlayerRec, add this:

```
Pet As PetRec
```
and add this custom type above PlayerRec:

```
Public Type PetRec
    SpriteNum As Byte
    Name As String * 50
    Owner As Long
End Type
```

**Server Side**

We can now move on to the more complicated server-side code. The server-side code mainly handles the spawning and de-spawning of the pet, and handling combat.

Firstly, go to "Sub JoinGame" and add this piece of code below "Call PlayerWarp(…)":

```
'View Current Pets on Map
    If PetMapCache(Player(Index).Map).UpperBound > 0 Then
        For j = 1 To PetMapCache(Player(Index).Map).UpperBound
            Call NPCCache_Create(Index, Player(Index).Map, PetMapCache(Player(Index).Map).Pet(j))
        Next
    End If
```
Place this at the top of "Sub JoinGame"

```
Dim i As Long, j As Long
```
This sends the pre-cached Pets to the new player to "synchronise" it with the server.

Next, add this wherever you see fit:

```
Public Type PetCache
    Pet(1 To MAX_MAP_NPCS) As Long
    UpperBound As Long
End Type

Public PetMapCache(1 To MAX_MAPS) As PetCache
```

This caches NPCs for new players logging on.

Next, you will need to open up modEnumerations.
Scroll to the bottom of the client-side enumerations (The ones beginning with a "C"), and paste this above CMSG_COUNT:

```
CSpawnPet
CPetFollowOwner
CPetAttackTarget
CPetWander
CPetDisband

```
Next, move to modHandleData and look for "Public Sub InitMessages()". Scroll to the bottom of the procedure and add:

```
    'Pet System
    HandleDataSub(CSpawnPet) = GetAddress(AddressOf HandleSpawnPet)
    HandleDataSub(CPetFollowOwner) = GetAddress(AddressOf HandlePetFollowOwner)
    HandleDataSub(CPetAttackTarget) = GetAddress(AddressOf HandlePetAttackTarget)
    HandleDataSub(CPetWander) = GetAddress(AddressOf HandlePetWander)
    HandleDataSub(CPetDisband) = GetAddress(AddressOf HandlePetDisband)
```
These five lines will call their respective procedures when the correct packet is recieved. Once you have pasted these lines in, scroll to the bottom of modHandleData and add these five procedures:

```
Public Sub HandleSpawnPet(ByVal Index As Long, ByRef Data() As Byte, ByVal StartAddr As Long, ByVal ExtraVar As Long)
    SpawnPet Index, GetPlayerMap(Index)
End Sub

Public Sub HandlePetFollowOwner(ByVal Index As Long, ByRef Data() As Byte, ByVal StartAddr As Long, ByVal ExtraVar As Long)
    Dim Buffer As clsBuffer

    PetFollowOwner Index
End Sub

Public Sub HandlePetAttackTarget(ByVal Index As Long, ByRef Data() As Byte, ByVal StartAddr As Long, ByVal ExtraVar As Long)
    Dim Buffer As clsBuffer

    If TempPlayer(Index).TempPetSlot < 1 Then Exit Sub

    MapNpc(GetPlayerMap(Index)).Npc(TempPlayer(Index).TempPetSlot).targetType = TempPlayer(Index).targetType
    MapNpc(GetPlayerMap(Index)).Npc(TempPlayer(Index).TempPetSlot).target = TempPlayer(Index).target
End Sub

Public Sub HandlePetWander(ByVal Index As Long, ByRef Data() As Byte, ByVal StartAddr As Long, ByVal ExtraVar As Long)
    Dim Buffer As clsBuffer

    PetWander Index
End Sub

Public Sub HandlePetDisband(ByVal Index As Long, ByRef Data() As Byte, ByVal StartAddr As Long, ByVal ExtraVar As Long)
    Dim Buffer As clsBuffer

    PetDisband Index, GetPlayerMap(Index)
    SendMap Index, GetPlayerMap(Index)
    PlayerWarp Index, GetPlayerMap(Index), GetPlayerX(Index), GetPlayerY(Index)
End Sub
```

After that, move to modGameLogic and add these procedures to the bottom of it:

```
'makes the pet follow its owner
Sub PetFollowOwner(ByVal Index As Long)
    If TempPlayer(Index).TempPetSlot < 1 Then Exit Sub

    MapNpc(GetPlayerMap(Index)).Npc(TempPlayer(Index).TempPetSlot).targetType = 1
    MapNpc(GetPlayerMap(Index)).Npc(TempPlayer(Index).TempPetSlot).target = Index
End Sub

'makes the pet wander around the map
Sub PetWander(ByVal Index As Long)
    If TempPlayer(Index).TempPetSlot < 1 Then Exit Sub

    MapNpc(GetPlayerMap(Index)).Npc(TempPlayer(Index).TempPetSlot).targetType = TARGET_TYPE_NONE
    MapNpc(GetPlayerMap(Index)).Npc(TempPlayer(Index).TempPetSlot).target = 0
End Sub

'Clear the npc from the map
Sub PetDisband(ByVal index As Long, ByVal MapNum As Long)
    Dim i As Long
    Dim j As Long

    If TempPlayer(index).TempPetSlot < 1 Then Exit Sub

    'Cache the Pets for players logging on [Remove Number from array]
    'THIS IS KINDA SLOW (EVEN WITHOUT TESTING, LOL), MAY HAVE TO CONVERT TO LINKED LIST FOR SPEED
    For i = 1 To PetMapCache(MapNum).UpperBound
        If PetMapCache(MapNum).Pet(i) = TempPlayer(index).TempPetSlot Then
            If PetMapCache(MapNum).UpperBound > 1 Then
                For j = PetMapCache(MapNum).UpperBound To i Step -1
                    PetMapCache(MapNum).Pet(j - 1) = PetMapCache(MapNum).Pet(j)
                Next
            Else
                PetMapCache(MapNum).Pet(1) = 0
            End If

            PetMapCache(MapNum).UpperBound = PetMapCache(MapNum).UpperBound - 1
            Exit For
        End If
    Next

    Call ClearSingleMapNpc(TempPlayer(index).TempPetSlot, MapNum)
    Map(GetPlayerMap(index)).Npc(TempPlayer(index).TempPetSlot) = 0
    TempPlayer(index).TempPetSlot = 0

    're-warp the players on the map
    For i = 1 To Player_HighIndex
        If IsPlaying(i) Then
            If GetPlayerMap(i) = GetPlayerMap(index) Then
                Call PlayerWarp(i, GetPlayerMap(i), GetPlayerX(i), GetPlayerY(i))
                SendPlayerData index
            End If
        End If
    Next
End Sub

Sub SpawnPet(ByVal Index As Long, ByVal MapNum As Long)
    Dim PlayerMap As Long
    Dim I As Integer
    Dim PetSlot As Byte

    'Prevent multiple pets for the same owner
    If TempPlayer(Index).TempPetSlot > 0 Then Exit Sub

    PlayerMap = GetPlayerMap(Index)
    PetSlot = 0

    For i = 1 To MAX_MAP_NPCS
        'If Map(PlayerMap).Npc(i) = 0 Then
        If MapNpc(PlayerMap).Npc(i).SpawnWait = 0 And MapNpc(PlayerMap).Npc(i).Num = 0 Then
            PetSlot = i
            Exit For
        End If
    Next

    If PetSlot = 0 Then
        Call PlayerMsg(Index, "The map is too crowded for you to call on your pet!", Red)
        Exit Sub
    End If

    'create the pet for the map
    Map(PlayerMap).Npc(PetSlot) = #
    MapNpc(PlayerMap).Npc(PetSlot).Num = #
    'set its Pet Data
    MapNpc(PlayerMap).Npc(PetSlot).IsPet = YES
    MapNpc(PlayerMap).Npc(PetSlot).PetData.Name = GetPlayerName(Index) & "'s " & Npc(#).Name
    MapNpc(PlayerMap).Npc(PetSlot).PetData.Owner = Index

    'If Pet doesn't exist with player, link it to the player
    If Player(Index).Pet.SpriteNum <> # Then
        Player(Index).Pet.SpriteNum = #
        Player(Index).Pet.Name = GetPlayerName(Index) & "'s " & Npc(#).Name
    End If

    TempPlayer(Index).TempPetSlot = PetSlot

    'cache the map for sending
    Call MapCache_Create(PlayerMap)

    'Cache the Pets for players logging on [Add new Number to array]
    PetMapCache(PlayerMap).UpperBound = PetMapCache(PlayerMap).UpperBound + 1
    PetMapCache(PlayerMap).Pet(PetMapCache(PlayerMap).UpperBound) = PetSlot

    If PetMapCache(Player(Index).Map).UpperBound > 0 Then
        For i = 1 To PetMapCache(Player(Index).Map).UpperBound
            Call NPCCache_Create(Index, Player(Index).Map, PetMapCache(Player(Index).Map).Pet(i))
        Next
    End If

    Select Case GetPlayerDir(Index)
        Case DIR_UP
            Call SpawnNpc(PetSlot, PlayerMap, GetPlayerX(Index), GetPlayerY(Index) - 1)
        Case DIR_DOWN
            Call SpawnNpc(PetSlot, PlayerMap, GetPlayerX(Index), GetPlayerY(Index) + 1)
        Case DIR_LEFT
            Call SpawnNpc(PetSlot, PlayerMap, GetPlayerX(Index) + 1, GetPlayerY(Index))
        Case DIR_RIGHT
            Call SpawnNpc(PetSlot, PlayerMap, GetPlayerX(Index), GetPlayerY(Index) - 1)
    End Select

    're-warp the players on the map
    For I = 1 To Player_HighIndex
        If IsPlaying(I) Then
            If GetPlayerMap(I) = GetPlayerMap(Index) Then
                Call PlayerWarp(i, PlayerMap, GetPlayerX(i), GetPlayerY(i))
            End If
        End If
    Next

End Sub
```
The names of the procedures clearly explain their function. The code should also be easy to follow. Replace the hashes with your desired NPC number.

Staying in modGameLogic, you will need to navigate your way to Sub SpawnNpc. Delete that procedure, and replace it with this:

```
Public Sub SpawnNpc(ByVal mapNpcNum As Long, ByVal MapNum As Long, Optional ByVal SetX As Long, Optional ByVal SetY As Long)
    Dim Buffer As clsBuffer
    Dim npcNum As Long
    Dim I As Long
    Dim x As Long
    Dim y As Long
    Dim Spawned As Boolean

    ' Check for subscript out of range
    If mapNpcNum <= 0 Or mapNpcNum > MAX_MAP_NPCS Or MapNum <= 0 Or MapNum > MAX_MAPS Then Exit Sub
    npcNum = Map(MapNum).Npc(mapNpcNum)

    If npcNum > 0 Then

        MapNpc(MapNum).Npc(mapNpcNum).Num = npcNum
        MapNpc(MapNum).Npc(mapNpcNum).target = 0
        MapNpc(MapNum).Npc(mapNpcNum).targetType = 0 ' clear

        MapNpc(MapNum).Npc(mapNpcNum).Vital(Vitals.HP) = GetNpcMaxVital(npcNum, Vitals.HP)
        MapNpc(MapNum).Npc(mapNpcNum).Vital(Vitals.MP) = GetNpcMaxVital(npcNum, Vitals.MP)

        MapNpc(MapNum).Npc(mapNpcNum).Dir = Int(Rnd * 4)

        'Check if theres a spawn tile for the specific npc
        For x = 0 To Map(MapNum).MaxX
            For y = 0 To Map(MapNum).MaxY
                If Map(MapNum).Tile(x, y).Type = TILE_TYPE_NPCSPAWN Then
                    If Map(MapNum).Tile(x, y).Data1 = mapNpcNum Then
                        MapNpc(MapNum).Npc(mapNpcNum).x = x
                        MapNpc(MapNum).Npc(mapNpcNum).y = y
                        MapNpc(MapNum).Npc(mapNpcNum).Dir = Map(MapNum).Tile(x, y).Data2
                        Spawned = True
                        Exit For
                    End If
                End If
            Next y
        Next x

        If Not Spawned Then

            ' Well try 100 times to randomly place the sprite
            For I = 1 To 100

                If SetX = 0 And SetY = 0 Then
                    x = Random(0, Map(MapNum).MaxX)
                    y = Random(0, Map(MapNum).MaxY)
                Else
                    x = SetX
                    y = SetY
                End If

                If x > Map(MapNum).MaxX Then x = Map(MapNum).MaxX
                If y > Map(MapNum).MaxY Then y = Map(MapNum).MaxY

                ' Check if the tile is walkable
                If NpcTileIsOpen(MapNum, x, y) Then
                    MapNpc(MapNum).Npc(mapNpcNum).x = x
                    MapNpc(MapNum).Npc(mapNpcNum).y = y
                    Spawned = True
                    Exit For
                End If

            Next

        End If

        ' Didn't spawn, so now we'll just try to find a free tile
        If Not Spawned Then

            For x = 0 To Map(MapNum).MaxX
                For y = 0 To Map(MapNum).MaxY

                    If NpcTileIsOpen(MapNum, x, y) Then
                        MapNpc(MapNum).Npc(mapNpcNum).x = x
                        MapNpc(MapNum).Npc(mapNpcNum).y = y
                        Spawned = True
                    End If

                Next
            Next

        End If

        ' If we suceeded in spawning then send it to everyone
        If Spawned Then
            Set Buffer = New clsBuffer
            Buffer.WriteLong SSpawnNpc
            Buffer.WriteLong mapNpcNum
            Buffer.WriteLong MapNpc(MapNum).Npc(mapNpcNum).Num
            Buffer.WriteLong MapNpc(MapNum).Npc(mapNpcNum).x
            Buffer.WriteLong MapNpc(MapNum).Npc(mapNpcNum).y
            Buffer.WriteLong MapNpc(MapNum).Npc(mapNpcNum).Dir
            Buffer.WriteByte MapNpc(MapNum).Npc(mapNpcNum).IsPet
            Buffer.WriteString MapNpc(MapNum).Npc(mapNpcNum).PetData.Name
            Buffer.WriteLong MapNpc(MapNum).Npc(mapNpcNum).PetData.Owner
            SendDataToMap MapNum, Buffer.ToArray()
            Set Buffer = Nothing
        End If

        SendMapNpcVitals MapNum, mapNpcNum
    End If

End Sub
```
Another parameter to this procedure could easily be added for various NPC numbers, triggered by using an item.

Now move to modCombat. Add these procedures to the bottom of the module. They are TryNpcAttackNpc and CanNpcAttackNpc. These are basically ripped from an old version of EO with a few modifications by me, so credits go to Robin for them. They are used in this tutorial for Pet vs. Other NPC combat.

```
Function CanNpcAttackNpc(ByVal MapNum As Long, ByVal Attacker As Long, ByVal Victim As Long) As Boolean
    Dim aNpcNum As Long
    Dim vNpcNum As Long
    Dim VictimX As Long
    Dim VictimY As Long
    Dim AttackerX As Long
    Dim AttackerY As Long

    CanNpcAttackNpc = False

    ' Check for subscript out of range
    If Attacker <= 0 Or Attacker > MAX_MAP_NPCS Then
        Exit Function
    End If

    If Victim <= 0 Or Victim > MAX_MAP_NPCS Then
        Exit Function
    End If

    ' Check for subscript out of range
    If MapNpc(MapNum).Npc(Attacker).Num <= 0 Then
        Exit Function
    End If

    ' Check for subscript out of range
    If MapNpc(MapNum).Npc(Victim).Num <= 0 Then
        Exit Function
    End If

    aNpcNum = MapNpc(MapNum).Npc(Attacker).Num
    vNpcNum = MapNpc(MapNum).Npc(Victim).Num

    If aNpcNum <= 0 Then Exit Function
    If vNpcNum <= 0 Then Exit Function

    ' Make sure the npcs arent already dead
    If MapNpc(MapNum).Npc(Attacker).Vital(Vitals.HP) <= 0 Then
        Exit Function
    End If

    ' Make sure the npc isn't already dead
    If MapNpc(MapNum).Npc(Victim).Vital(Vitals.HP) <= 0 Then
        Exit Function
    End If

    ' Make sure npcs dont attack more then once a second
    If GetTickCount < MapNpc(MapNum).Npc(Attacker).AttackTimer + 1000 Then
        Exit Function
    End If

    MapNpc(MapNum).Npc(Attacker).AttackTimer = GetTickCount

    AttackerX = MapNpc(MapNum).Npc(Attacker).x
    AttackerY = MapNpc(MapNum).Npc(Attacker).y
    VictimX = MapNpc(MapNum).Npc(Victim).x
    VictimY = MapNpc(MapNum).Npc(Victim).y

    ' Check if at same coordinates
    If (VictimY + 1 = AttackerY) And (VictimX = AttackerX) Then
        CanNpcAttackNpc = True
    Else

        If (VictimY - 1 = AttackerY) And (VictimX = AttackerX) Then
            CanNpcAttackNpc = True
        Else

            If (VictimY = AttackerY) And (VictimX + 1 = AttackerX) Then
                CanNpcAttackNpc = True
            Else

                If (VictimY = AttackerY) And (VictimX - 1 = AttackerX) Then
                    CanNpcAttackNpc = True
                End If
            End If
        End If
    End If

End Function

Sub NpcAttackNpc(ByVal MapNum As Long, ByVal Attacker As Long, ByVal Victim As Long, ByVal Damage As Long)
    Dim i As Long
    Dim Buffer As clsBuffer
    Dim aNpcNum As Long
    Dim vNpcNum As Long
    Dim n As Long
    Dim PetOwner As Long

    If Attacker <= 0 Or Attacker > MAX_MAP_NPCS Then Exit Sub
    If Victim <= 0 Or Victim > MAX_MAP_NPCS Then Exit Sub

    If Damage <= 0 Then Exit Sub

    aNpcNum = MapNpc(MapNum).Npc(Attacker).Num
    vNpcNum = MapNpc(MapNum).Npc(Victim).Num

    If aNpcNum <= 0 Then Exit Sub
    If vNpcNum <= 0 Then Exit Sub

    'set the victim's target to the pet attacking it
    MapNpc(MapNum).Npc(Victim).targetType = 2 'Npc
    MapNpc(MapNum).Npc(Victim).target = Attacker

    ' Send this packet so they can see the person attacking
    Set Buffer = New clsBuffer
    Buffer.WriteLong SNpcAttack
    Buffer.WriteLong Attacker
    SendDataToMap MapNum, Buffer.ToArray()
    Set Buffer = Nothing

    If Damage >= MapNpc(MapNum).Npc(Victim).Vital(Vitals.HP) Then
        SendActionMsg MapNum, "-" & Damage, BrightRed, 1, (MapNpc(MapNum).Npc(Victim).x * 32), (MapNpc(MapNum).Npc(Victim).y * 32)
        SendBlood MapNum, MapNpc(MapNum).Npc(Victim).x, MapNpc(MapNum).Npc(Victim).y

        ' npc is dead.
        'Call GlobalMsg(CheckGrammar(Trim$(Npc(vNpcNum).Name), 1) & " has been killed by " & CheckGrammar(Trim$(Npc(aNpcNum).Name)) & "!", BrightRed)

        ' Set NPC target to 0
        MapNpc(MapNum).Npc(Attacker).target = 0
        MapNpc(MapNum).Npc(Attacker).targetType = 0
        'reset the targetter for the player

        If MapNpc(MapNum).Npc(Attacker).IsPet = YES Then
            TempPlayer(MapNpc(MapNum).Npc(Attacker).PetData.Owner).target = 0
            TempPlayer(MapNpc(MapNum).Npc(Attacker).PetData.Owner).targetType = TARGET_TYPE_NONE

            PetOwner = MapNpc(MapNum).Npc(Attacker).PetData.Owner

            SendTarget PetOwner

            'Give the player the pet owner some experience from the kill
            Call SetPlayerExp(PetOwner, GetPlayerExp(PetOwner) + Npc(MapNpc(MapNum).Npc(Victim).Num).Exp)
            CheckPlayerLevelUp PetOwner
            SendActionMsg MapNum, "+" & Npc(MapNpc(MapNum).Npc(Victim).Num).Exp & "Exp", White, 1, GetPlayerX(PetOwner) * 32, GetPlayerY(PetOwner) * 32
            SendEXP PetOwner

        ElseIf MapNpc(MapNum).Npc(Victim).IsPet = YES Then
            'Get the pet owners' index
            PetOwner = MapNpc(MapNum).Npc(Victim).PetData.Owner
            'Set the NPC's target on the owner now
            MapNpc(MapNum).Npc(Attacker).targetType = 1 'player
            MapNpc(MapNum).Npc(Attacker).target = PetOwner
            'Disband the pet
            PetDisband PetOwner, GetPlayerMap(PetOwner)
        End If

        ' Drop the goods if they get it
        'For n = 1 To MAX_NPC_DROPS
        If Npc(vNpcNum).DropItem <> 0 Then
            If Rnd <= Npc(vNpcNum).DropChance Then
                Call SpawnItem(Npc(vNpcNum).DropItem, Npc(vNpcNum).DropItemValue, MapNum, MapNpc(MapNum).Npc(Victim).x, MapNpc(MapNum).Npc(Victim).y)
            End If
        End If
        'Next

        ' Reset victim's stuff so it dies in loop
        MapNpc(MapNum).Npc(Victim).Num = 0
        MapNpc(MapNum).Npc(Victim).SpawnWait = GetTickCount
        MapNpc(MapNum).Npc(Victim).Vital(Vitals.HP) = 0

        ' send npc death packet to map
        Set Buffer = New clsBuffer
        Buffer.WriteLong SNpcDead
        Buffer.WriteLong Victim
        SendDataToMap MapNum, Buffer.ToArray()
        Set Buffer = Nothing

        If PetOwner > 0 Then
            PetFollowOwner PetOwner
        End If
    Else
        ' npc not dead, just do the damage
        MapNpc(MapNum).Npc(Victim).Vital(Vitals.HP) = MapNpc(MapNum).Npc(Victim).Vital(Vitals.HP) - Damage

        ' Say damage
        SendActionMsg MapNum, "-" & Damage, BrightRed, 1, (MapNpc(MapNum).Npc(Victim).x * 32), (MapNpc(MapNum).Npc(Victim).y * 32)
        SendBlood MapNum, MapNpc(MapNum).Npc(Victim).x, MapNpc(MapNum).Npc(Victim).y
    End If

    'Send both Npc's Vitals to the client
    SendMapNpcVitals MapNum, Attacker
    SendMapNpcVitals MapNum, Victim

End Sub
```
Now search for "Sub PlayerAttackNPC". Add this below where the Map NPC's HP is set to zero:
```
'Checks if NPC was a pet
        If MapNpc(MapNum).Npc(mapNpcNum).IsPet = YES Then
            Call PetDisband(MapNpc(MapNum).Npc(mapNpcNum).PetData.Owner, MapNum) 'The pet was killed         
        End If
```
Staying in modCombat, find the Function: "CanNpcAttackPlayer". Underneath the main checks: Add this:

```
'check if the NPC attacking us is actually our pet.
'We don't want a rebellion on our hands now do we?

If MapNpc(MapNum).Npc(mapNpcNum).PetData.Owner = Index Then Exit Function
```
This stops the pet attacking it's owner. >_<

Next, ctrl+F "Sub CloseSocket". Replace the current procedure with this:

```
Sub CloseSocket(ByVal Index As Long)
Dim I As Integer

    If Index > 0 Then
        If TempPlayer(Index).TempPetSlot > 0 Then
            Call PetDisband(Index, GetPlayerMap(Index))
            For I = 1 To Player_HighIndex
                If GetPlayerMap(I) = GetPlayerMap(Index) Then
                    SendMap I, GetPlayerMap(Index)
                End If
            Next
        End If

        Call LeftGame(Index)
        Call TextAdd("Connection from " & GetPlayerIP(Index) & " has been terminated.")
        frmServer.Socket(Index).Close
        Call UpdateCaption
        Call ClearPlayer(Index)
    End If

End Sub
```
The modification here disbands a pet if its owner logs out.
After this, Ctrl+F "This is used for npcs to attack targets". This will move you into modServerLoop>UpdateMapLogic.

In that section, up to "This is used for regenerating NPC's HP, replace that code with this:

```
If Map(MapNum).Npc(x) > 0 And MapNpc(MapNum).Npc(x).Num > 0 Then
                    target = MapNpc(MapNum).Npc(x).target
                    targetType = MapNpc(MapNum).Npc(x).targetType

                    ' Check if the npc can attack the targeted player player
                    If target > 0 Then

                        If targetType = 1 Then ' player

                            ' Is the target playing and on the same map?
                            If IsPlaying(target) And GetPlayerMap(target) = MapNum Then
                                TryNpcAttackPlayer x, target
                            Else
                                ' Player left map or game, set target to 0
                                MapNpc(MapNum).Npc(x).target = 0
                                MapNpc(MapNum).Npc(x).targetType = 0 ' clear
                            End If
                        ElseIf targetType = 2 Then
                            ' lol no npc combat :( DATS WAT YOU THINK
                            If CanNpcAttackNpc(MapNum, x, MapNpc(MapNum).Npc(x).target) = True Then
                                Call NpcAttackNpc(MapNum, x, MapNpc(MapNum).Npc(x).target, Npc(Map(MapNum).Npc(x)).Damage)
                            End If
                        Else

                        End If
                    End If
                End If
```
The modification I have done here basically handles the NPC vs. NPC combat for your pet, mentioned earlier.

Afterwards, go to modDatabase and add this:

```
Sub ClearSingleMapNpc(ByVal index As Long, ByVal MapNum As Long)
    Call ZeroMemory(ByVal VarPtr(MapNpc(MapNum).Npc(index)), LenB(MapNpc(MapNum).Npc(index)))
    Map(MapNum).Npc(index) = 0
    MapNpc(MapNum).Npc(index).Num = 0
    MapCache_Create (MapNum)
End Subb
```
This helps for clearing a single npc from a map; whether on death or dismissal.

Next, move to modPlayer and find the procedure named "PlayerWarp". Replace that procedure with this modded version:

```
Sub PlayerWarp(ByVal Index As Long, ByVal MapNum As Long, ByVal x As Long, ByVal y As Long)
    Dim shopNum As Long
    Dim OldMap As Long
    Dim I As Long
    Dim Buffer As clsBuffer

    ' Check for subscript out of range
    If IsPlaying(Index) = False Or MapNum <= 0 Or MapNum > MAX_MAPS Then
        Exit Sub
    End If

    ' Check if you are out of bounds
    If x > Map(MapNum).MaxX Then x = Map(MapNum).MaxX
    If y > Map(MapNum).MaxY Then y = Map(MapNum).MaxY
    If x < 0 Then x = 0
    If y < 0 Then y = 0

    ' if same map then just send their co-ordinates
    If MapNum = GetPlayerMap(Index) Then
        SendPlayerXYToMap Index
    End If

    ' clear target
    TempPlayer(Index).target = 0
    TempPlayer(Index).targetType = TARGET_TYPE_NONE
    SendTarget Index

    ' Save old map to send erase player data to
    OldMap = GetPlayerMap(Index)

    If OldMap <> MapNum Then
        Call SendLeaveMap(Index, OldMap)
    End If

    Call SetPlayerMap(Index, MapNum)
    Call SetPlayerX(Index, x)
    Call SetPlayerY(Index, y)

    'If 'refreshing' map
    If (OldMap <> MapNum) And TempPlayer(Index).TempPetSlot > 0 Then
        'switch maps
      PetDisband Index, OldMap
        SpawnPet Index, MapNum
        PetFollowOwner Index

        If PetMapCache(OldMap).UpperBound > 0 Then
            For i = 1 To PetMapCache(OldMap).UpperBound
                If PetMapCache(OldMap).Pet(i) = TempPlayer(Index).TempPetSlot Then
                    PetMapCache(OldMap).Pet(i) = 0
                End If
            Next
        Else
            PetMapCache(OldMap).Pet(1) = 0
        End If
    End If

    'View Current Pets on Map
    If PetMapCache(Player(Index).Map).UpperBound > 0 Then
        For i = 1 To PetMapCache(Player(Index).Map).UpperBound
            Call NPCCache_Create(Index, Player(Index).Map, PetMapCache(Player(Index).Map).Pet(i))
        Next
    End If

    ' send player's equipment to new map
    SendMapEquipment Index

    ' send equipment of all people on new map
    If GetTotalMapPlayers(MapNum) > 0 Then
        For I = 1 To Player_HighIndex
            If IsPlaying(I) Then
                If GetPlayerMap(I) = MapNum Then
                    SendMapEquipmentTo I, Index
                End If
            End If
        Next
    End If

    ' Now we check if there were any players left on the map the player just left, and if not stop processing npcs
    If GetTotalMapPlayers(OldMap) = 0 Then
        PlayersOnMap(OldMap) = NO

        ' Regenerate all NPCs' health
        For I = 1 To MAX_MAP_NPCS

            If MapNpc(OldMap).Npc(I).Num > 0 Then
                MapNpc(OldMap).Npc(I).Vital(Vitals.HP) = GetNpcMaxVital(MapNpc(OldMap).Npc(I).Num, Vitals.HP)
            End If

        Next

    End If

    ' Sets it so we know to process npcs on the map
    PlayersOnMap(MapNum) = YES
    TempPlayer(Index).GettingMap = YES
    Set Buffer = New clsBuffer
    Buffer.WriteLong SCheckForMap
    Buffer.WriteLong MapNum
    Buffer.WriteLong Map(MapNum).Revision
    SendDataTo Index, Buffer.ToArray()
    Set Buffer = Nothing
End Sub
```
The modification here merely de-spawns the pet from the old map and spawns it onto the new one.

Next, go to modServerTCP, and add these two subs at the bottom of it:

```
Sub NPCCache_Create_SendToAll(ByVal MapNum As Long, ByVal NPCNum As Long)
    Dim i As Long
    Dim Buffer As clsBuffer

    Set Buffer = New clsBuffer

    Buffer.WriteLong SNPCCache
    Buffer.WriteLong MapNum
    Buffer.WriteLong NPCNum
    Buffer.WriteLong Map(MapNum).Npc(NPCNum)
    Buffer.WriteLong MapNpc(MapNum).Npc(NPCNum).Num

    For i = 1 To Player_HighIndex
        If IsPlaying(i) Then
            If Player(i).Map = MapNum Then
                SendDataTo i, Buffer.ToArray()
            End If
        End If
    Next
End Sub

Sub NPCCache_Create(ByVal Index As Long, ByVal MapNum As Long, ByVal NPCNum As Long)
    Dim i As Long
    Dim Buffer As clsBuffer

    Set Buffer = New clsBuffer

    Buffer.WriteLong SNPCCache
    Buffer.WriteLong MapNum
    Buffer.WriteLong NPCNum
    Buffer.WriteLong Map(MapNum).Npc(NPCNum)
    Buffer.WriteLong MapNpc(MapNum).Npc(NPCNum).Num

    SendDataTo Index, Buffer.ToArray()
End Sub
```
You will also need to add "SNPCCache" to modEnumerations.

Finally, move to modTypes, and modify these pieces of code. Add PetRec above PlayerRec:

```
Public Type PetRec
    SpriteNum As Byte
    Name As String * 50
    Owner As Long
End Type
```
Add this to the bottom of PlayerRec:

```
Pet As PetRec
```
Add This to the bottom of TempPlayerRec:

```
TempPetSlot As Byte
```
Finally, add this to the bottom of MapNpcRec:

```
'Pet Data
    IsPet As Byte
    PetData As PetRec
```

And, Voila! You should now have a decent base to implement more features, if you wish, to this Pet System. I hope it wasn't too hard to follow, and that you learned something in the process of doing this.

Regards,

_**Lightning**_

PS: If you include this in your game, you must place me in the game credits for my "Base Pet System", seeing as someone likes to think my work is theirs. >_>
Link to comment
Share on other sites

  • Replies 304
  • Created
  • Last Reply

Top Posters In This Topic

@n00b:

> Beautiful, if I ever did create a game, I would love this. Thanks for the share Lightning.

@Païn:

> You are truly the best, Lightning!
>
> Thanks so much,
> Païn

Thanks! :)

@Yukiyo:

> I haven't exactly looked through this yet but, does the pet come back to it's owner's side once the target's vitals reach 0?

Yes, once the target's vitals are reduced to zero, the pet comes back to its owner. It's only 1 line of code, calling the "PetFollow" procedure. It's easily removed. ;P
Link to comment
Share on other sites

I updated the tutorial a few hours ago, just to let everyone know. If you followed the tutorial and an error was flagging a line including "ClearSingleMapNpc" look through the tutorial and follow the extra step I added.

Thanks,

Lightning
Link to comment
Share on other sites

Oops, that is another thing I have forgotten. All you need to do is go to the spawnnpc sub, and add 2 parameters, x and y. Then go to the part where it determines the x and y coords and set a check there. Make sure the parameters are set as optional. Ill release the official code tomorrow. And rarity yes you can do that. ;-)
Link to comment
Share on other sites

Well I got her working with the usual level system with random add HP and add Damage on levelup, though it's all saving in the Player(index) dat. Can't say she's really a clean code after what I did to her but lol, it's pretty cool. I could evolve the pet by using a simple level check on level up. Thanks again for the share Lightning.
Link to comment
Share on other sites

@masa:

> what is code of menu buttons?
> Sory I'm spanish and not speack good enlish

Like I said at the beginning of the tutorial, you require basic knowledge of the source code and VB6.

@n00b:

> Well I got her working with the usual level system with random add HP and add Damage on levelup, though it's all saving in the Player(index) dat. Can't say she's really a clean code after what I did to her but lol, it's pretty cool. I could evolve the pet by using a simple level check on level up. Thanks again for the share Lightning.

No problem, good luck with that! ;)

@BugSICK:

> wow this is nice very very nice, thanks again lightning, I have a suggestion can it possible 'a pet get/pick item drops?

That would be fairly simple to implement, when an npc drops its items, make then npc walk to the drops and then give the items to its owner.

Also, I will be implementing 2 procedures I missed out, one of which Richy pointed out yesterday. I'll do it once I get back from college in about 5 hours.
Link to comment
Share on other sites

I've now included the missing subs into the tutorial.  :mad:

**CLIENT**

Go to modHandleData and change HandleSpawnNpc to this:

```
Private Sub HandleSpawnNpc(ByVal Index As Long, ByRef Data() As Byte, ByVal StartAddr As Long, ByVal ExtraVar As Long)
Dim n 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()
    n = Buffer.ReadLong

    With MapNpc(n)
        .Num = Buffer.ReadLong
        .x = Buffer.ReadLong
        .y = Buffer.ReadLong
        .Dir = Buffer.ReadLong
        .IsPet = Buffer.ReadByte
        .PetData.Name = Buffer.ReadString
        .PetData.Owner = Buffer.ReadLong
        ' Client use only
        .XOffset = 0
        .YOffset = 0
        .Moving = 0
    End With

    ' Error handler
    Exit Sub
errorhandler:
    HandleError "HandleSpawnNpc", "modHandleData", Err.Number, Err.Description, Err.Source, Err.HelpContext
    Err.Clear
    Exit Sub
End Sub
```

**SERVER**
Go to modGameLogic and replace Sub SpawnNpc with this:

```
Public Sub SpawnNpc(ByVal mapNpcNum As Long, ByVal MapNum As Long, Optional ByVal SetX As Long, Optional ByVal SetY As Long)
    Dim Buffer As clsBuffer
    Dim npcNum As Long
    Dim i As Long
    Dim x As Long
    Dim y As Long
    Dim Spawned As Boolean

    ' Check for subscript out of range
    If mapNpcNum <= 0 Or mapNpcNum > MAX_MAP_NPCS Or MapNum <= 0 Or MapNum > MAX_MAPS Then Exit Sub
    npcNum = Map(MapNum).Npc(mapNpcNum)

    If npcNum > 0 Then

        MapNpc(MapNum).Npc(mapNpcNum).Num = npcNum
        MapNpc(MapNum).Npc(mapNpcNum).target = 0
        MapNpc(MapNum).Npc(mapNpcNum).targetType = 0 ' clear

        MapNpc(MapNum).Npc(mapNpcNum).Vital(Vitals.HP) = GetNpcMaxVital(npcNum, Vitals.HP)
        MapNpc(MapNum).Npc(mapNpcNum).Vital(Vitals.MP) = GetNpcMaxVital(npcNum, Vitals.MP)

        MapNpc(MapNum).Npc(mapNpcNum).Dir = Int(Rnd * 4)

        'Check if theres a spawn tile for the specific npc
        For x = 0 To Map(MapNum).MaxX
            For y = 0 To Map(MapNum).MaxY
                If Map(MapNum).Tile(x, y).Type = TILE_TYPE_NPCSPAWN Then
                    If Map(MapNum).Tile(x, y).Data1 = mapNpcNum Then
                        MapNpc(MapNum).Npc(mapNpcNum).x = x
                        MapNpc(MapNum).Npc(mapNpcNum).y = y
                        MapNpc(MapNum).Npc(mapNpcNum).Dir = Map(MapNum).Tile(x, y).Data2
                        Spawned = True
                        Exit For
                    End If
                End If
            Next y
        Next x

        If Not Spawned Then

            ' Well try 100 times to randomly place the sprite
            For i = 1 To 100

                If SetX = 0 And SetY = 0 Then
                    x = Random(0, Map(MapNum).MaxX)
                    y = Random(0, Map(MapNum).MaxY)
                Else
                    x = SetX
                    y = SetY
                End If

                If x > Map(MapNum).MaxX Then x = Map(MapNum).MaxX
                If y > Map(MapNum).MaxY Then y = Map(MapNum).MaxY

                ' Check if the tile is walkable
                If NpcTileIsOpen(MapNum, x, y) Then
                    MapNpc(MapNum).Npc(mapNpcNum).x = x
                    MapNpc(MapNum).Npc(mapNpcNum).y = y
                    Spawned = True
                    Exit For
                End If

            Next

        End If

        ' Didn't spawn, so now we'll just try to find a free tile
        If Not Spawned Then

            For x = 0 To Map(MapNum).MaxX
                For y = 0 To Map(MapNum).MaxY

                    If NpcTileIsOpen(MapNum, x, y) Then
                        MapNpc(MapNum).Npc(mapNpcNum).x = x
                        MapNpc(MapNum).Npc(mapNpcNum).y = y
                        Spawned = True
                    End If

                Next
            Next

        End If

        ' If we suceeded in spawning then send it to everyone
        If Spawned Then
            Set Buffer = New clsBuffer
            Buffer.WriteLong SSpawnNpc
            Buffer.WriteLong mapNpcNum
            Buffer.WriteLong MapNpc(MapNum).Npc(mapNpcNum).Num
            Buffer.WriteLong MapNpc(MapNum).Npc(mapNpcNum).x
            Buffer.WriteLong MapNpc(MapNum).Npc(mapNpcNum).y
            Buffer.WriteLong MapNpc(MapNum).Npc(mapNpcNum).Dir
            Buffer.WriteByte MapNpc(MapNum).Npc(mapNpcNum).IsPet
            Buffer.WriteString MapNpc(MapNum).Npc(mapNpcNum).PetData.Name
            Buffer.WriteLong MapNpc(MapNum).Npc(mapNpcNum).PetData.Owner
            SendDataToMap MapNum, Buffer.ToArray()
            Set Buffer = Nothing
        End If

        SendMapNpcVitals MapNum, mapNpcNum
    End If

End Sub
```
modPlayer, Sub PlayerWarp:

```
Sub PlayerWarp(ByVal Index As Long, ByVal MapNum As Long, ByVal x As Long, ByVal y As Long)
    Dim shopNum As Long
    Dim OldMap As Long
    Dim i As Long
    Dim Buffer As clsBuffer

    ' Check for subscript out of range
    If IsPlaying(Index) = False Or MapNum <= 0 Or MapNum > MAX_MAPS Then
        Exit Sub
    End If

    ' Check if you are out of bounds
    If x > Map(MapNum).MaxX Then x = Map(MapNum).MaxX
    If y > Map(MapNum).MaxY Then y = Map(MapNum).MaxY
    If x < 0 Then x = 0
    If y < 0 Then y = 0

    ' if same map then just send their co-ordinates
    If MapNum = GetPlayerMap(Index) Then
        SendPlayerXYToMap Index
    End If

    ' clear target
    TempPlayer(Index).target = 0
    TempPlayer(Index).targetType = TARGET_TYPE_NONE
    SendTarget Index

    ' Save old map to send erase player data to
    OldMap = GetPlayerMap(Index)

    If OldMap <> MapNum Then
        Call SendLeaveMap(Index, OldMap)
    End If

    Call SetPlayerMap(Index, MapNum)
    Call SetPlayerX(Index, x)
    Call SetPlayerY(Index, y)

    'If 'refreshing' map
    If (OldMap <> MapNum) And TempPlayer(Index).TempPetSlot > 0 Then
        'switch maps
      PetDisband Index, OldMap
        SpawnPet Index, MapNum
    End If

    ' send player's equipment to new map
    SendMapEquipment Index

    ' send equipment of all people on new map
    If GetTotalMapPlayers(MapNum) > 0 Then
        For i = 1 To Player_HighIndex
            If IsPlaying(i) Then
                If GetPlayerMap(i) = MapNum Then
                    SendMapEquipmentTo i, Index
                End If
            End If
        Next
    End If

    ' Now we check if there were any players left on the map the player just left, and if not stop processing npcs
    If GetTotalMapPlayers(OldMap) = 0 Then
        PlayersOnMap(OldMap) = NO

        ' Regenerate all NPCs' health
        For i = 1 To MAX_MAP_NPCS

            If MapNpc(OldMap).Npc(i).Num > 0 Then
                MapNpc(OldMap).Npc(i).Vital(Vitals.HP) = GetNpcMaxVital(MapNpc(OldMap).Npc(i).Num, Vitals.HP)
            End If

        Next

    End If

    ' Sets it so we know to process npcs on the map
    PlayersOnMap(MapNum) = YES
    TempPlayer(Index).GettingMap = YES
    Set Buffer = New clsBuffer
    Buffer.WriteLong SCheckForMap
    Buffer.WriteLong MapNum
    Buffer.WriteLong Map(MapNum).Revision
    SendDataTo Index, Buffer.ToArray()
    Set Buffer = Nothing
End Sub
```
Enjoy!
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share


×
×
  • Create New...