• 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!

TFS 1.2 help with "item" Spawner system.

oshrigames

Active Member
Joined
Nov 9, 2012
Messages
222
Reaction score
47
Location
israel
Hello again :)

TFS 1.2, Protocol 10.98

ive been working on a Mining / Harvest / etc.. systems.
thanks to Ramirow and many others who help along the way, most of it already finished ♥
but i come to another issue i can't solve by myself (even tho i tried).

ive been working on a specific spawn system of a Crystals, Plants, and basically anything that ill ever gonna need. (with minor changes)

i want to have lets say, 3 types of Crystals spawn at random locations inside the mine (to counter future bots and players who camp the locations).
so ive remembered a similar systrem by oen432, ([TFS 1.X] Cursed Chests).

i've modified and remove most of it but i encounter few issues.

the issues:
1) once i mine of the the crystals, it spawn only at that location and that type. (mining.lua "function doCreateStone" is the issue?)
2) the crystal however sometimes spawn under stuff which prevents players to use "ice pick" on it.
seems like i broke oen432's "isBadTile" function. 😅
grass.png

either make the "item" (crystal) spawn on top of everything or on a ground where nothing on it.
and minior issue i get that error for some reason :x
Code:
[Warning - Event::checkScript] Event onUse not found. scripts/custom/crystal_type.lua

heres the codes and if you have any question or need more info let me know.
(i know it can be cleaned even more, i just try to make it work first)

crystal_spawner.lua
Lua:
CRYSTAL_AID = 9001

CRYTAL_SPAWNS = {
    [1] = {
        pos = Position(988, 965, 7),
        size = 2,
        crystals = {1}
    },
    [2] = {
        pos = Position(1021, 1070, 10),
        size = 25,
        crystals = {1}
    }
}
-- [1 - test], [2 - Mine ]

function onThink(cid, interval, lastExecution)
    for spawnId, data in ipairs(CRYTAL_SPAWNS) do
        if not data.spawned then
            local from = Position(data.pos.x - data.size, data.pos.y - data.size, data.pos.z)
            local to = Position(data.pos.x + data.size, data.pos.y + data.size, data.pos.z)
            local crystalId = math.random(1, #data.crystals)
            local spawnPos = Position(math.random(from.x, to.x), math.random(from.y, to.y), data.pos.z)
            local tile = Tile(spawnPos)
            local spawnTest = 0

            while spawnTest < 100 do
                if isBadTile(tile) then
                    spawnPos = Position(math.random(from.x, to.x), math.random(from.y, to.y), data.pos.z)
                    tile = Tile(spawnPos)
                    spawnTest = spawnTest + 1
                else
                    break
                end
            end

            if spawnTest < 100 then
                local rarity = nil
                for i = #CRYSTAL_TIERS, 1, -1 do
                    rarity = CRYSTAL_TIERS[i]
                    if math.random(1, 100) <= rarity.chance then
                        break
                    end
                end
                if rarity ~= nil then
                    local crystal = Game.createItem(rarity.item, 1, spawnPos)
                    spawnPos:sendMagicEffect(CONST_ME_ENERGYHIT)
                    crystal:setActionId(CRYSTAL_AID)
                    local crystalData = {}
                    crystalData.pos = spawnPos
                    crystalData.spawnId = spawnId
                    crystalData.active = 0
                    crystalData.rarity = rarity
                    CRYSTAL_DATA[#CRYSTAL_DATA + 1] = crystalData
                    data.spawned = true
                end
            end

        end
    end
    return true
end

crystal_type.lua
Lua:
local CRYSTAL_SPAWN_VERSION = "1.0.0"
    print(">> Loaded Crystal Mine Spawn v" .. CRYSTAL_SPAWN_VERSION)
CRYSTAL_TIER_SMALL = 1
CRYSTAL_TIER_MEDIUM = 2
CRYSTAL_TIER_LARGE = 3

CRYSTAL_TIERS = {
    {
        tier = CRYSTAL_TIER_SMALL,
        chance = 90,
        text = " [Small Crystal Lv. 1+]", -- IGNORE
        item = 17999,
        reqLevel = 1 -- IGNORE
    },
    {
        tier = CRYSTAL_TIER_MEDIUM,
        chance = 40,
        text = "Medium Crystal [Lv.50+]", -- IGNORE
        item = 17597,
        reqLevel = 1 -- IGNORE
    },
    {
        tier = CRYSTAL_TIER_LARGE,
        chance = 10,
        text = "Large Crystal [Lv.70+]", -- IGNORE
        item = 17867,
        reqLevel = 1 -- IGNORE
    }
}

CRYSTAL_DATA = {}

function isBadTile(tile)
    return (tile == nil or tile:getGround() == nil or tile:hasProperty(TILESTATE_NONE) or tile:hasProperty(TILESTATE_FLOORCHANGE_EAST) or
        isItem(tile:getThing()) and not isMoveable(tile:getThing()) or
        tile:getTopCreature() or
        tile:hasFlag(TILESTATE_PROTECTIONZONE))
end

Mining.lua
Lua:
-- Mining Skill
-- For TFS version 1.1

local name = "Mining"  -- Name of the Custom Skill
local storage = 15034  -- Storage used to store Custom Skill Levels
local minutes = 1  -- Minutes to recreate the stone

function doCreateStone(pos, itemid)  -- Recreates the stone after given time
    local tile = Tile(pos)
    if tile:getTopCreature() then
    pos:sendMagicEffect(CONST_ME_POFF)
    return addEvent(doCreateStone, minutes * 60 * 1000, pos, itemid)
    else
    Game.createItem(itemid, 1, pos)
    pos:sendMagicEffect(CONST_ME_ENERGYHIT)
  end
end

local stones = {  -- Contains all stones and their data
  [17999] = {
       itemid = 17999,
       stonetype = 'Blue Crystal Shard',
       stonetype2 = 'Royal ingot',
       item = 18413, --Blue Crystal Shard
       item2 = 18337, -- Royal ingot
       level = {min = 1, max = 20}, --1 Mining kill the chance would be '20%'.
       bonusLevel = 20, -- chance to mine tiem2 ie: strange Royal ingot
       bonusChance = 1, -- chance to get extra item2 ie: strange Royal ingot
       roundChance = {min = 1, max = 1}, -- 'min' stands for the base amount of rubies you will get. 'max' stands for the maximun amount of rubies you will get. These values are base ones, remember that higher skill will increase the rewards. Also note that these values are counted for bonus rewards too.
       chance = 1, --What this value does is increasing your chance of success. In this case, it divides your MINING SKILL by 2 and adds the result to your success rate! Easy as that, in this example, using the value of 2. Having 4 Mining Skill will add 2% (4 / 2) to our success rate, which was 30% at it's base (Expressed as I said, in level.max). That gives us a total of 32% rate of success. With a Mining Skill of 100 we will have 80% success rate. (30% base + 50% for skill(100 / 2))
       round = 15, --This value works somehow like 'chance' but adds to the amount of rubies you will receive. 8 means that every 8 Skill Levels you will increase the rubies gained by 1. (8 / 8) Having 64 Mining Skill will give you 1 - 2 rubies (Base reward set in 'roundChance') + 8 additional rubies.
       xp = 1, -- exp per succseful hit
       xp2 = 2 -- exp per succseful hit for item2
  },
    [17597] = {
       itemid = 17597,
       stonetype = 'Blue Crystal Shard',
       stonetype2 = 'Royal ingot',
       item = 18413, --Blue Crystal Shard
       item2 = 18337, -- Royal ingot
       level = {min = 50, max = 20}, --1 Mining kill the chance would be '20%'.
       bonusLevel = 20, -- chance to mine tiem2 ie: strange Royal ingot
       bonusChance = 1, -- chance to get extra item2 ie: strange Royal ingot
       roundChance = {min = 1, max = 2}, -- 'min' stands for the base amount of rubies you will get. 'max' stands for the maximun amount of rubies you will get. These values are base ones, remember that higher skill will increase the rewards. Also note that these values are counted for bonus rewards too.
       chance = 1, --What this value does is increasing your chance of success. In this case, it divides your MINING SKILL by 2 and adds the result to your success rate! Easy as that, in this example, using the value of 2. Having 4 Mining Skill will add 2% (4 / 2) to our success rate, which was 30% at it's base (Expressed as I said, in level.max). That gives us a total of 32% rate of success. With a Mining Skill of 100 we will have 80% success rate. (30% base + 50% for skill(100 / 2))
       round = 15, --This value works somehow like 'chance' but adds to the amount of rubies you will receive. 8 means that every 8 Skill Levels you will increase the rubies gained by 1. (8 / 8) Having 64 Mining Skill will give you 1 - 2 rubies (Base reward set in 'roundChance') + 8 additional rubies.
       xp = 1, -- exp per succseful hit
       xp2 = 2 -- exp per succseful hit for item2
  },
  [17867] = {
       itemid = 17867,
       stonetype = 'Blue Crystal Shard',
       stonetype2 = 'Royal ingot',
       item = 18413, --Blue Crystal Shard
       item2 = 18337, -- Royal ingot
       level = {min = 70, max = 20}, --1 Mining kill the chance would be '20%'.
       bonusLevel = 20, -- chance to mine tiem2 ie: strange Royal ingot
       bonusChance = 1, -- chance to get extra item2 ie: strange Royal ingot
       roundChance = {min = 1, max = 3}, -- 'min' stands for the base amount of rubies you will get. 'max' stands for the maximun amount of rubies you will get. These values are base ones, remember that higher skill will increase the rewards. Also note that these values are counted for bonus rewards too.
       chance = 2, --What this value does is increasing your chance of success. In this case, it divides your MINING SKILL by 2 and adds the result to your success rate! Easy as that, in this example, using the value of 2. Having 4 Mining Skill will add 2% (4 / 2) to our success rate, which was 30% at it's base (Expressed as I said, in level.max). That gives us a total of 32% rate of success. With a Mining Skill of 100 we will have 80% success rate. (30% base + 50% for skill(100 / 2))
       round = 15, --This value works somehow like 'chance' but adds to the amount of rubies you will receive. 8 means that every 8 Skill Levels you will increase the rubies gained by 1. (8 / 8) Having 64 Mining Skill will give you 1 - 2 rubies (Base reward set in 'roundChance') + 8 additional rubies.
       xp = 1, -- exp per succseful hit
       xp2 = 2 -- exp per succseful hit for item2
  }
}

function onUse(cid, item, fromPosition, target, toPosition, isHotkey)
  local player = type(cid) == 'number' and Player(cid) or cid

  local miningSkill = player:getCustomSkill(storage)
  if stones[target.itemid] then

  local miningLevel = stones[target.itemid].level
  if miningSkill >= miningLevel.min then

  local chance = math.floor((math.random(1, 100)) - (miningSkill / stones[target.itemid].chance))
  if chance <= miningLevel.max then
     local roundChance = stones[target.itemid].roundChance
     local amount = math.floor((math.random(roundChance.min, roundChance.max)) + (miningSkill / stones[target.itemid].round))
     if miningSkill >= stones[target.itemid].bonusLevel and math.random(1,100) <= stones[target.itemid].bonusChance then
      local loop2 = stones[target.itemid].xp2
              player:addItem(stones[target.itemid].item2, amount)
          toPosition:sendMagicEffect(CONST_ME_FIREWORK_YELLOW)
          target:remove()
          addEvent(doCreateStone, minutes * 60 * 1000, toPosition, target.itemid)
          for i = loop2, 1, -1 do
          player:addCustomSkillTry(name, storage)
          end
          player:sendTextMessage(MESSAGE_STATUS_CONSOLE_RED, "You mined " .. amount .. " " .. stones[target.itemid].stonetype2 .. ".")
     else
     local loop = stones[target.itemid].xp
             player:addItem(stones[target.itemid].item, amount)
          toPosition:sendMagicEffect(CONST_ME_FIREWORK_BLUE)
          target:remove()
          addEvent(doCreateStone, minutes * 60 * 1000, toPosition, target.itemid)
          for i = loop, 1, -1 do
          player:addCustomSkillTry(name, storage)
          end
          player:sendTextMessage(MESSAGE_STATUS_CONSOLE_RED, "You mined " .. amount .. " " .. stones[target.itemid].stonetype .. ".")
             end
   else
  local failure = math.random(1,100)
          if  failure <= 50 then
          toPosition:sendMagicEffect(CONST_ME_POFF)
              player:sendTextMessage(MESSAGE_STATUS_SMALL, "You failed and the rock was destroyed.")
          target:remove()
          addEvent(doCreateStone, minutes * 60 * 1000, toPosition, target.itemid)
          else
          player:sendTextMessage(MESSAGE_STATUS_SMALL, "You couldn't mine anything.")
          toPosition:sendMagicEffect(CONST_ME_HITAREA)
          end
      end
      else
      player:sendTextMessage(MESSAGE_STATUS_SMALL, "You need a " .. name .. " level of " .. miningLevel.min .. " to mine this stone.")
      end
      end
  return true
end


once everything is finished i'll put it to the public, the modified Mining, Smith, Harvest and Alchemy (14+ Custom potions included).
with credit to everyone who gave a hand and wirte the core of the systems. ♥
 
Last edited:
1.x
Code:
local t = {} -- problematic ids

for i = 1, #t do
local it = Tile(pos):getItemById(t[i])
if it then
it:remove()
end
end

0.4 functions needed (replace in 1.x version):
Code:
local it = getTileItemById(pos, t[i]).uid
doRemoveItem(it)
 
Last edited:
im sorry but what im i looking at?
am i doing it right?

Lua:
local t = {9043, 9043, 6217, 6216} -- Grass and small stones ID |problematic ids|

for i = 1, #t do
local it = Tile(pos):getItemById(t[i])
if it then
it:remove()
end
end

Edit: guess not i get errors ;x
 
A solution to grass overlapping your crystals
I thought you understand the script you posted.

😅
well, i just modfied it.
and i understand only the very basic of the code.

no error, still land on a grass (ID 6219)
Lua:
local CRYSTAL_SPAWN_VERSION = "1.0.0"
    print(">> Loaded Crystal Mine Spawn v" .. CRYSTAL_SPAWN_VERSION)
    
local t = {6219,6218, 6217, 6216} -- Grass and small stones ID |problematic ids|

for i = 1, #t do
local it = getTileItemById(pos, t[i]).uid
doRemoveItem(it)
end
    
CRYSTAL_TIER_SMALL = 1
CRYSTAL_TIER_MEDIUM = 2
CRYSTAL_TIER_LARGE = 3

CRYSTAL_TIERS = {
    {
        tier = CRYSTAL_TIER_SMALL,
        chance = 99,
        text = " [Small Crystal Lv. 1+]",
        item = 17999,
        reqLevel = 1
    },
    {
        tier = CRYSTAL_TIER_MEDIUM,
        chance = 2,
        text = "Medium Crystal [Lv.50+]",
        item = 17597,
        reqLevel = 1
    },
    {
        tier = CRYSTAL_TIER_LARGE,
        chance = 1,
        text = "Large Crystal [Lv.70+]",
        item = 17867,
        reqLevel = 1
    }
}

CRYSTAL_DATA = {}

function isBadTile(tile)
    return (tile == nil or tile:getGround() == nil or tile:hasProperty(TILESTATE_NONE) or tile:hasProperty(TILESTATE_FLOORCHANGE_EAST) or
        isItem(tile:getThing()) and not isMoveable(tile:getThing()) or
        tile:getTopCreature() or
        tile:hasFlag(TILESTATE_PROTECTIONZONE))
end
 
Last edited:
try this

Code:
function isBadTile(pos)
    local tile = Tile(pos)

    if not tile
    or tile:hasFlag(TILESTATE_BLOCKSOLID)
    or tile:hasFlag(TILESTATE_FLOORCHANGE)
    or tile:hasFlag(TILESTATE_PROTECTIONZONE)
    or tile:getTopCreature() then
        return false
    end
    
    return true
end
 
try this

Code:
function isBadTile(pos)
    local tile = Tile(pos)

    if not tile
    or tile:hasFlag(TILESTATE_BLOCKSOLID)
    or tile:hasFlag(TILESTATE_FLOORCHANGE)
    or tile:hasFlag(TILESTATE_PROTECTIONZONE)
    or tile:getTopCreature() then
        return false
    end
   
    return true
end

for some wierd reason its effect my cursed_chest_spawner.lua even tho ive added this to crystal_spawner.lua
Error

Code:
Lua Script Error: [GlobalEvent Interface]
data/globalevents/scripts/cursed_chest_spawner.lua:onThink
data/globalevents/scripts/cursed_chest_spawner.lua:72: attempt to index local 'chest' (a nil value)
stack traceback:
        [C]: in function '__index'
        data/globalevents/scripts/cursed_chest_spawner.lua:72: in function <data/globalevents/scripts/cursed_chest_spawner.lua:42>
[Error - GlobalEvents::think] Failed to execute event: CursedChestSpawner
 
and what if you swap return values (true with false) in my isBadTile?

all the cursed chests never spawn when i switch values. (still not sure why its effected a different script tho)
by the way. thanks for take the time to find a fix for this issue.. it's much appreciated and not taken for granted ♥
 
still not sure why its effected a different script tho

if you don't set variable as local, it affects all scripts

you probably have isBadTile declared in both scripts (to declare it locally you would have to add local before "function isBadTile()"

if you suspect that isBadTile function is fucked in crystal spawn script, try removing it from that script and see if it fixes the problem (it will still be declared from random chests script).
 
if you don't set variable as local, it affects all scripts

you probably have isBadTile declared in both scripts (to declare it locally you would have to add local before "function isBadTile()"

if you suspect that isBadTile function is fucked in crystal spawn script, try removing it from that script and see if it fixes the problem (it will still be declared from random chests script).

i tried to remove it and add a loval to see if thats gonna fix things, still its spawn on grass and rocks.
i also tried (and failed) to edit the crystals in the item Editor and have them always be on top, i screw somethnig since it wont let me keep the changed even tho i saved.
i will keep on trying things and update my progress until i find a solution..
 
it's possible to do without item or source edits
I will see if I can fix it myself in a few hours (dont have time now)

I don't know what was wrong in your script, but I tested the isBadTile function and it works.
 
Last edited:
Back
Top