• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

Lua problem pet system

ImaG

Active Member
Joined
Aug 16, 2017
Messages
82
Solutions
1
Reaction score
38
Location
Poland
GitHub
ImaGus01v
Hi
The problem is that the pet disappears after being summoned, as if it had no condition. It was ok at first, but after being killed or sent away it does something like in the movie.
4VUSj7j.mp4


debug:
Summon Pet called. Pet UID: 0
Setting Pet UID to: 1073755568
Setting Pet UID to: 1073755568
Pet summoned successfully.
LUA:
---- based on Jordanhenry pet system version 1.77 (changelog)
---- edited by hellboy

-- config
PETS = {
    PREFIX = "PET_",
    CHANNELID = 10,

    CONFIG = {
        introduction = "You may catch pets using command '!petcatch'. If your pet dies, you have to revive it in order to re-summon it. Some pets have a special requirement in order to catch them, some cannot be catched at all and can only be gotten by evolution. Type 'commands' for a list of available commands.",
        sameSpeed = true,

        healSoulCost = 0.1,
        healSoulBase = 10,

        healOnLevelUp = true,
        standardHpAdd = 5,
        expMultipler = 1,
        shareExpMultipler = 0.3,
        maxLevel = 30,

        reviveSoulBaseCost = 5,
        reviveSoulLevelCost = 0.2
    },

    SYSTEM = {
        EVOLUTION = true,
        MOUNTS = false,
        TELEPORT = true,
        PLAYER_SHARE_EXPERIENCE = false,
    DUELS_ONLY = false
    },

    IDENTIFICATION = {
        [1] = {
            name = "Cat",
            health = 100,
            evolve = {
                to = 3,
                at = 10
            },
            check = true
        },
        [2] = {
            name = "Dog",
            health = 100,
            evolve = {
                to = 4,
                at = 10
            },
            check = true
        },
        [3] = {
            name = "Tiger",
            health = 300,
            check = false,
            info = "Evolves from Cat."
        },
        [4] = {
            name = "Lion",
            health = 300,
            mountId = 40,
            check = false,
            info = "Evolves from Dog."
        },
        [5] = {
            name = "Husky",
            health = 150,
            check = function(player) return player:getPremiumDays() > 0 end,
            info = "Requires a premium account."
        },
        [6] = {
            name = "Wolf",
            health = 200,
            evolve = {
                to = 7,
                at = 4
            },
            check = function(player) return player:getLevel() >= 10 end,
            info = "Requires level 10."
        },
        [7] = {
            name = "War Wolf",
            health = 500,
            evolve = {
                to = 8,
                at = 55
            },
            check = false,
            info = "Evolves from Wolf."
        },
        [8] = {
            name = "Werewolf",
            health = 1000,
            check = false,
            info = "Evolves from War Wolf."
        },
        [9] = {
            name = "Bear",
            health = 300,
            mountId = 3,
            check = function(player) return player:isDruid() and player:getLevel() >= 10 end,
            info = "Only available to druids above level 10."
        },
        [10] = {
            name = "Panda",
            health = 300,
            mountId = 19,
            check = function(player) return player:isDruid() and player:getLevel() >= 10 end,
            info = "Only available to druids above level 10."
        },
        [11] = {
            name = "Chicken",
            health = 50,
            check = true
        },
        [12] = {
            name = "Sheep",
            health = 50,
            check = true
        },
        [13] = {
            name = "Seagull",
            health = 100,
            check = function(player) return player:getPremiumDays() > 0 end,
            info = "Requires a premium account."
        },
        [14] = {
            name = "Parrot",
            health = 100,
            check = function(player) return player:getPremiumDays() > 0 end,
            info = "Requires a premium account."
        },
        [15] = {
            name = "Penguin",
            health = 100,
            check = function(player) return player:getPremiumDays() > 0 end,
            info = "Requires a premium account."
        },
        [16] = {
            name = "Elephant",
            health = 300,
            check = function(player) return player:getPremiumDays() > 0 and player:getLevel() >= 10 end,
            contain = 5,
            info = "Only available to Premium accounts above level 10."
        },
        [17] = {
            name = "Dragon Hatchling",
            health = 300,
            evolve = {
                to = 18,
                at = 20
            },
            check = function(player) return player:getPremiumDays() > 0 and player:getLevel() >= 25 and player:isSorcerer() end,
            info = "Only available to Premium Sorcerers above level 25."
        },
        [18] = {
            name = "Dragon",
            health = 1000,
            check = false,
            info = "Evolves from Dragon Hatchling."
        }
    },

    STORAGE = {
        TYPE = 12000,
        UID = 12001,
        LOSTHEALTH = 12002,
        MAXHEALTH = 12003,
        EXPERIENCE = 12004,
        LEVEL = 12005
    },

    CONSTANS = {
        STATUS_OK = 0,
        STATUS_DOESNT_EXIST = -1,
        STATUS_DEAD = -2,
        STATUS_MOUNT = -3
    }
}

--/ config
function Player.petSystemMessage(self, txt, talkType)
    local playerId = self:getId()
    talkType = (talkType == nil) and TALKTYPE_CHANNEL_O or talkType

    local function eventMessage(playerId, text, talkType)
        local player = Player(playerId)
        if not player then
            return false
        end
        player:sendChannelMessage('[PET-SYSTEM]', txt, talkType, PETS.CHANNELID)
    end
    addEvent(eventMessage, 150, playerId, text, talkType)

    --self:sendChannelMessage('[PET-SYSTEM]', txt, ((talkType == nil) and TALKTYPE_CHANNEL_O or talkType), PETS.CHANNELID)
    --self:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, '[PET-SYSTEM] '..txt)
    return true
end

-- get
function Player.getPetExperience(self)
    return self:getStorageValue(PETS.STORAGE.EXPERIENCE)
end

function Player.getPetLevel(self)
    return self:getStorageValue(PETS.STORAGE.LEVEL)
end

function Player.getPetType(self)
    return self:getStorageValue(PETS.STORAGE.TYPE)
end

function Player.getPetUid(self)
    -- Debugowanie: Sprawdzanie UID peta
    local petUid = self:getStorageValue(PETS.STORAGE.UID)
    print("Getting Pet UID: " .. petUid)
    return petUid
end

function Player.getPetMaxHealth(self)
    return self:getStorageValue(PETS.STORAGE.MAXHEALTH)
end

function Player.getPetLostHealth(self)
    return self:getStorageValue(PETS.STORAGE.LOSTHEALTH)
end

function Player.getPetMountId(self)
    local petType = self:getPetType()
    local mountId = PETS.IDENTIFICATION[petType].mountId
    return mountId
end

-- set
function Player.setPetExperience(self, experience)
    return self:setStorageValue(PETS.STORAGE.EXPERIENCE, experience)
end

function Player.setPetLevel(self, petLevel)
    return self:setStorageValue(PETS.STORAGE.LEVEL, petLevel)
end

function Player.setPetType(self, petType)
    return self:setStorageValue(PETS.STORAGE.TYPE, petType)
end

function Player.setPetUid(self, petUid)
    -- Debugowanie
    print("Setting Pet UID to: " .. petUid)

    -- Ustawiamy UID peta w storage
    return self:setStorageValue(PETS.STORAGE.UID, petUid)
end

function Player.setPetMaxHealth(self, health)
    return self:setStorageValue(PETS.STORAGE.MAXHEALTH, health)
end

function Player.setPetLostHealth(self, health)
    return self:setStorageValue(PETS.STORAGE.LOSTHEALTH, health)
end

-- other
function Player.doAddPet(self, petType)
    -- Debugowanie: Sprawdzanie, czy pet już istnieje
    local pet = Creature(self:getStorageValue(PETS.STORAGE.UID))
    if pet then
        print("Pet already exists. Returning false.")
        return false
    end

    -- Debugowanie: Tworzenie nowego peta
    print("Adding a new pet. Pet Type: " .. petType)

    -- Sprawdzamy, czy UID jest prawidłowe przed jego ustawieniem
    local newUid = Game.createMonster(PETS.PREFIX .. (PETS.IDENTIFICATION[petType].name), self:getPosition())
    if not newUid then
        print("Failed to create pet. Returning false.")
        return false
    end

    -- Ustawiamy UID peta na nowy UID
    self:setPetUid(newUid:getId())
    print("Setting Pet UID to: " .. newUid:getId())

    -- Inicjalizacja wartości związanych z petem
    self:setPetExperience(0)
    self:setPetLevel(1)
    self:setPetType(petType)

    -- Ustawianie zdrowia peta
    local maxHealth = PETS.IDENTIFICATION[petType].health
    self:setPetMaxHealth(maxHealth)
    print("Setting Pet Max Health to: " .. maxHealth)

    -- Inicjalizacja utraconego zdrowia
    self:setPetLostHealth(0)

    -- Dodawanie mounta, jeśli system mountów jest włączony
    if PETS.SYSTEM.MOUNTS then
        local mountId = self:getPetMountId()
        if mountId ~= nil and mountId ~= 0 then
            self:addMount(mountId)
            print("Adding mount with ID: " .. mountId)
        end
    end

    -- Debugowanie: Pet successfully added
    print("Pet successfully added.")
    return true
end

function Player.doResetPet(self)
    for _, i in pairs(PETS.STORAGE) do
        self:setStorageValue(i, -1)
    end
    return true
end

function Player.doRemovePet(self)
    local petUid = self:getPetUid()
    local pet = Creature(petUid)

    -- Jeśli pet nie istnieje lub nie jest prawdziwą kreaturą
    if not pet or not pet:isCreature() then
        print("Pet does not exist or is not a creature.")
        -- Jeśli UID jest większe niż 0, resetujemy UID
        if petUid > 0 then
            self:setPetUid(PETS.CONSTANS.STATUS_OK)
            print("Resetting Pet UID to 0.")
        end
        return true
    end

    -- Sprawdzamy maxHealth peta, aby zapisać stan zdrowia przed jego usunięciem
    local maxHealth = pet:getMaxHealth()

    -- Ustawiamy dane o zdrowiu peta przed jego usunięciem
    self:setPetMaxHealth(maxHealth)
    self:setPetLostHealth(maxHealth - pet:getHealth())

    -- Usuwamy samego peta
    pet:remove()

    -- Resetujemy UID peta po jego usunięciu
    self:setPetUid(PETS.CONSTANS.STATUS_OK)
    print("Pet removed and UID reset to 0.")

    -- Usuwamy mounta, jeśli system mountów jest włączony
    if PETS.SYSTEM.MOUNTS then
        local mountId = self:getPetMountId()
        if mountId and mountId > 0 then
            self:addMount(mountId)
        end
    end

    return true
end

function Player.doKillPet(self, removeBody)
    if removeBody then
        self:doRemovePet()
    end
    self:setPetUid(PETS.CONSTANS.STATUS_DEAD)
    self:setPetLostHealth(0)

    if PETS.SYSTEM.MOUNTS then
        local mountId = self:getPetMountId()
        if mountId ~= nil then
            self:removeMount(mountId)
        end
    end
    return true
end

function Player.summonPet(self, position)
    local petUid = self:getPetUid()
    local pet = Creature(petUid)

    print("Summon Pet called. Pet UID: " .. petUid)

    -- Sprawdzamy, czy pet już istnieje
    if pet and pet:isCreature() then
        print("Pet already exists. Returning false.")
        return false
    end

    -- Tworzymy nowego peta
    if (Tile(position)):hasFlag(TILESTATE_PROTECTIONZONE) then
        print("Pet cannot be summoned in protection zone.")
        return false
    end

    local petName = PETS.PREFIX .. PETS.IDENTIFICATION[self:getPetType()].name
    local pet = Game.createMonster(petName, position)
    if pet then
        position:sendMagicEffect(CONST_ME_TELEPORT)
        pet:setMaster(self)

        -- Przypisanie UID peta do gracza
        self:setPetUid(pet:getId())  -- Tu zapisujemy UID peta
        print("Setting Pet UID to: " .. pet:getId())  -- Debugowanie

        -- Ustawienie zdrowia, szybkości i innych właściwości peta
        local maxHealth = self:getPetMaxHealth()
        pet:setMaxHealth(maxHealth)
        pet:addHealth(maxHealth - pet:getHealth() - self:getPetLostHealth())
      
        -- Ustawiamy inne właściwości peta
        pet:setSkull(SKULL_GREEN)
        pet:changeSpeed(PETS.CONFIG.sameSpeed and (self:getBaseSpeed() - pet:getBaseSpeed()) or 0)

        -- Rejestracja eventów
        for _, eventName in pairs({"PetDeath", "PetKill"}) do
            pet:registerEvent(eventName)
        end

        if PETS.SYSTEM.TELEPORT then
            pet:registerEvent("PetTeleport")
        end

        if PETS.SYSTEM.DUELS_ONLY then
            pet:registerEvent("PetHealthChange")
        end

        print("Pet summoned successfully.")
        return pet
    end

    print("Pet summon failed.")
    return false
end



function getExpNeeded(level)
    return ( (50 *level^3) -(150 *level^2) +(400 *level) )/3 *PETS.CONFIG.expMultipler
end

function Player.addPetExp(self, amount)
    local pet = Creature(self:getPetUid())
    if not pet then
        return false
    end

    if self:getPetLevel() >= PETS.CONFIG.maxLevel then
        return false
    end

    local totalExp = self:getPetExperience() + amount
    self:setPetExperience(totalExp)
    local petLevel, petType, petUid = self:getPetLevel(), self:getPetType(), self:getPetUid()

    if totalExp >= getExpNeeded(petLevel + 1) then
        pet:setMaxHealth(pet:getMaxHealth() + (PETS.IDENTIFICATION[petType].hpAdd or PETS.CONFIG.standardHpAdd))
        self:setPetLevel(petLevel +1)
        self:petSystemMessage("Your pet "..PETS.IDENTIFICATION[petType].name.." has advanced to level "..(petLevel +1)..".")

        if PETS.CONFIG.healOnLevelUp then
            pet:addHealth( pet:getMaxHealth() )
        end

        if PETS.SYSTEM.EVOLUTION and (PETS.IDENTIFICATION[petType]).evolve and ((PETS.IDENTIFICATION[petType]).evolve.at <= (petLevel +1)) then
            local position = pet:getPosition()
            self:doRemovePet()
            self:setPetType( (PETS.IDENTIFICATION[petType]).evolve.to)
            self:setPetMaxHealth( (PETS.IDENTIFICATION[(PETS.IDENTIFICATION[petType]).evolve.to]).health )
            self:setPetLostHealth(0)
            self:petSystemMessage("Your pet "..(PETS.IDENTIFICATION[petType]).name.." has evolved to a "..((PETS.IDENTIFICATION[(PETS.IDENTIFICATION[petType]).evolve.to]).name)..".")
            self:summonPet(position)
        end

        -- save max hp fix
        self:setPetMaxHealth(pet:getMaxHealth())
    end

    return true
end

function Player.canGetPet(self, petId)
    if self:getGroup():getId() >= 3 then
        return true
    end

    if type(PETS.IDENTIFICATION[petId].check) == "function" then
        return PETS.IDENTIFICATION[petId].check(self)
    end
    return PETS.IDENTIFICATION[petId].check
end

-- is Pet
function Player.isPet(self)
    return false
end

function Npc.isPet(self)
    return false
end

function Monster.isPet(self)
    local owner = self:getMaster()
    if owner:isPlayer() and owner:getPetUid() == self:getId() then
        return true
    end
    return false
end

-- additional functions
function Position.getSurroundings(self)
  local return_array = {}
  local coordinates = {
    {x = self.x +1, y = self.y, z = self.z},
    {x = self.x -1, y = self.y, z = self.z},
    {x = self.x +1, y = self.y +1, z = self.z},
    {x = self.x, y = self.y +1, z = self.z},
    {x = self.x -1, y = self.y +1, z = self.z},
    {x = self.x +1, y = self.y -1, z = self.z},
    {x = self.x, y = self.y -1, z = self.z},
    {x = self.x -1, y = self.y -1, z = self.z}
  }

  for _, coordinate in pairs(coordinates) do
    table.insert(return_array, Position(coordinate))
  end
  return return_array
end

-- PET tools
function Monster.dig(self)
  if not self:isPet() then
    return false
  end

  local return_value = false

  local position = self:getPosition()
  local surroundings = position:getSurroundings()
  local HOLE_LIST = {468, 481, 483, 7932}

  local function _tmp_dig_in_tile(creature, tile, position)
    if not tile then
      return false
    end

    if tile:getCreatureCount() ~= 0 then
      return false
    end

    if tile:getItemCount() ~= 0 then
      return false
    end

    local ground = tile:getGround()

    if not ground then
      return false
    end

    local groundId = ground:getId()

    if not isInArray(HOLE_LIST, groundId) then
      return false
    end

    ground:transform(groundId + 1)
    ground:decay()
    position:sendMagicEffect(CONST_ME_POFF)
    return true
  end

  for _, next_position in pairs(surroundings) do
    local next_tile = Tile(next_position)

    if _tmp_dig_in_tile(self, next_tile, next_position) then
      return_value = true
    end
  end

  return return_value
end
I don't have the strength to look for the cause anymore, maybe someone will help.

I got the system from here: [TFS 1.2] Pet system (https://otland.net/threads/tfs-1-2-pet-system.236403/page-5)
I'm using otx 3. It works, but I had to transform the code a bit.

thanks and best regards ImaG
 
I think the problem is the script created in creaturescript and the cause is the onthink function. I edited the code from the original because it didn't assign me an owner and I don't think it still does... Any help?
LUA:
-- <event type="preparedeath" name="PetDeath" script="pet_creaturescript.lua" />
-- <event type="kill" name="PetKill" script="pet_creaturescript.lua" />
-- <event type="think" name="PetTeleport" script="pet_creaturescript.lua" />
-- <event type="healthchange" name="PetHealthChange" script="pet_creaturescript.lua" />

function onPrepareDeath(creature, killer)
    local player = creature:getMaster()
    if player then
        player:doKillPet(false)
        player:petSystemMessage("Your pet has died.")
    end
    return true
end

function onKill(creature, target)
    if target:isMonster() then
        local player = creature:getMaster()
        if not player then
            return true -- Jeśli brak właściciela, kończymy funkcję, aby uniknąć błędu
        end
        
        local experience = (target:getType()):getExperience()
        player:addPetExp(experience)
    end
    return true
end

function onThink(creature, interval)
    local maxDistance = 7
    local owner = creature:getMaster()

    -- Sprawdzamy, czy owner nie jest nil
    if not owner then
        return true  -- Jeśli brak właściciela, kończymy funkcję
    end

    local petPosition = creature:getPosition()
    local ownerPosition = owner:getPosition()

    local tile = owner:getTile()

    if tile:hasFlag(TILESTATE_PROTECTIONZONE) then
        owner:doRemovePet()
    else
        if petPosition.z ~= ownerPosition.z or ownerPosition:getDistance(petPosition) >= maxDistance then
            petPosition:sendMagicEffect(CONST_ME_TELEPORT)
            creature:teleportTo(ownerPosition)
            creature:getPosition():sendMagicEffect(CONST_ME_TELEPORT)
        end
    end
    return true
end

function onHealthChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
    if attacker and attacker:isPlayer() then
        return 0, primaryType, 0, secondaryType
    end

    return primaryDamage, primaryType, secondaryDamage, secondaryType
end
 
Back
Top