• 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 Help to optimize script for Monster:onSpawn(position)

beenii

Well-Known Member
Joined
Jul 26, 2010
Messages
580
Solutions
1
Reaction score
57
zx9oog.png




So far I have achieved this, but it does not work as I would like.
the random ones are not very random sometimes.


CODE:
Code:
function Monster:onSpawn(position)
    local nombres = {"[1] Rotworm Queen", "[2] Minotaur Hunter","[3] Dragon Lord", "[4] Glooth Brigand","[5] Glooth Bandit", "[6] Demodras","[7] Flameborn", "[8]  The Welter"}
    if isInArray(nombres, self:getName()) then
    return true
    end


---------------------------------------------------------
-- ADVANCE CHANCE START
---------------------------------------------------------
local config = {
    [1] = {chance = 270, min = 1, max = 3},
    [2] = {chance = 280, min = 4, max = 5},
    [3] = {chance = 170, min = 6, max = 8},
    [4] = {chance = 70, min = 9, max = 10},
    [5] = {chance = 30, min = 11, max = 13}
}
local totalChance = 0
for i = 1, #config do
    totalChance = totalChance + config[i].chance
end


local rand = math.random(totalChance)
local index = -1
for i = 1, #config do
    if rand <= config[i].chance then
        index = i
        break
    end
end
if index > -1 then
count = math.random(config[index].min, config[index].max)
end

---------------------------------------------------------
-- ADVANCE CHANCE FINISH
---------------------------------------------------------
maxHealth = self:getHealth()*count
local originalHealth = self:getHealth()    
local div = maxHealth / originalHealth
local numdiv = math.floor(div)



        if maxHealth < originalHealth then
        clase = "[weak]"
        end
        if numdiv == 1 or  numdiv == 2 or  numdiv == 3 then -- 45%
        clase = "[commun]"
        end       
        if numdiv == 4 or  numdiv == 5 then --28%
        clase = "[rare]"
        end               
        if numdiv == 6 or  numdiv == 7 or numdiv == 8 then  --17%
        clase = "[royale]"
        end       
        if numdiv == 9 or  numdiv == 10 then -- 7%
        clase = "[epic]"
        end       
        if numdiv == 11 or  numdiv == 12 or  numdiv == 13 then -- 3%
        clase = "[legendary]"
        end               
       
        self:setMaxHealth(maxHealth)
        self:addHealth(maxHealth)
        self:setName(""..clase.." "..self:getName().."", ""..clase.." "..self:getName().."")
        return true
    end
 
Solution
You are comparing the random number with the weight of each separate rank instead of the cumulative number.
Lua:
rand = rand - config[i].chance
should fix that
Code:
local config = {
    [1] = {chance = 40,clase ="commun", min = 1, max = 3},
    [2] = {chance = 33,clase ="rare", min = 4, max = 5},
    [3] = {chance = 17,clase ="royal", min = 6, max = 8},
    [4] = {chance = 7,clase ="epic", min = 9, max = 10},
    [5] = {chance = 3,clase ="legendary", min = 11, max = 13}
}
function Monster:onSpawn(position)
local totalChance = 0
for i = 1, #config do
    totalChance = totalChance + config[i].chance
end
math.randomseed(self:getId()+os.time())
local rand = math.random(totalChance)
local index = -1
for i = 1, #config do
    if rand <=...
Code:
function Monster:onSpawn(position)
    local nombres = {"[1] Rotworm Queen", "[2] Minotaur Hunter","[3] Dragon Lord", "[4] Glooth Brigand","[5] Glooth Bandit", "[6] Demodras","[7] Flameborn", "[8]  The Welter"}
    if isInArray(nombres, self:getName()) then
    return true
    end


---------------------------------------------------------
-- ADVANCE CHANCE START
---------------------------------------------------------
local config = {
    [1] = {chance = 270, min = 1, max = 3},
    [2] = {chance = 280, min = 4, max = 5},
    [3] = {chance = 170, min = 6, max = 8},
    [4] = {chance = 70, min = 9, max = 10},
    [5] = {chance = 30, min = 11, max = 13}
}
local totalChance = 0
for i = 1, #config do
    totalChance = totalChance + config[i].chance
end

math.randomseed(self:getId()+os.time())


local rand = math.random(totalChance)
local index = -1
for i = 1, #config do
    if rand <= config[i].chance then
        index = i
        break
    end
end
if index > -1 then
count = math.random(config[index].min, config[index].max)
end

---------------------------------------------------------
-- ADVANCE CHANCE FINISH
---------------------------------------------------------
maxHealth = self:getHealth()*count
local originalHealth = self:getHealth()
local div = maxHealth / originalHealth
local numdiv = math.floor(div)



        if maxHealth < originalHealth then
        clase = "[weak]"
        end
        if numdiv == 1 or  numdiv == 2 or  numdiv == 3 then -- 45%
        clase = "[commun]"
        end
        if numdiv == 4 or  numdiv == 5 then --28%
        clase = "[rare]"
        end       
        if numdiv == 6 or  numdiv == 7 or numdiv == 8 then  --17%
        clase = "[royale]"
        end
        if numdiv == 9 or  numdiv == 10 then -- 7%
        clase = "[epic]"
        end
        if numdiv == 11 or  numdiv == 12 or  numdiv == 13 then -- 3%
        clase = "[legendary]"
        end       
 
        self:setMaxHealth(maxHealth)
        self:addHealth(maxHealth)
        self:setName(""..clase.." "..self:getName().."", ""..clase.." "..self:getName().."")
        return true
    end

That should make it completely random, I just added math.randomseed(self:getId()+os.time()) inside the script. And os.time() isn't enough on it's own, since I believe most of the monsters spawns at the same time on startup and with self:getId() after every restart the same monsters will start with their new names etc, but with both it of them it should be completely random.
 
Last edited:
I tried to start reading but got so annoyed about the way it's written.

You should write cleaner code, then perhaps you could understand what you writing or I would even be interested to read in first place.
It should take max 1 minute to improve it, but you got so many lines I didn't even bother.

Start by ordering your code in relevant order.
Configurations put on top.
classes ( aka the meta methods put in the middle)
functions below.
Scripting barely needs comments. So don't use them for such a case at all, what you want to do is straightforward.

In addition, don't spread configuration around. Put every bit of info in 1 table.
WHY did you kick into my face in the second line of code? Don't use this [1] number in monster names.
Expand table and put the meaning of the number as a table key.

Improve your code by above guides and I help you to optimize.
 
Code:
function Monster:onSpawn(position)
    local nombres = {"[1] Rotworm Queen", "[2] Minotaur Hunter","[3] Dragon Lord", "[4] Glooth Brigand","[5] Glooth Bandit", "[6] Demodras","[7] Flameborn", "[8]  The Welter"}
    if isInArray(nombres, self:getName()) then
    return true
    end


---------------------------------------------------------
-- ADVANCE CHANCE START
---------------------------------------------------------
local config = {
    [1] = {chance = 270, min = 1, max = 3},
    [2] = {chance = 280, min = 4, max = 5},
    [3] = {chance = 170, min = 6, max = 8},
    [4] = {chance = 70, min = 9, max = 10},
    [5] = {chance = 30, min = 11, max = 13}
}
local totalChance = 0
for i = 1, #config do
    totalChance = totalChance + config[i].chance
end

math.randomseed(self:getId()+os.time())


local rand = math.random(totalChance)
local index = -1
for i = 1, #config do
    if rand <= config[i].chance then
        index = i
        break
    end
end
if index > -1 then
count = math.random(config[index].min, config[index].max)
end

---------------------------------------------------------
-- ADVANCE CHANCE FINISH
---------------------------------------------------------
maxHealth = self:getHealth()*count
local originalHealth = self:getHealth()
local div = maxHealth / originalHealth
local numdiv = math.floor(div)



        if maxHealth < originalHealth then
        clase = "[weak]"
        end
        if numdiv == 1 or  numdiv == 2 or  numdiv == 3 then -- 45%
        clase = "[commun]"
        end
        if numdiv == 4 or  numdiv == 5 then --28%
        clase = "[rare]"
        end      
        if numdiv == 6 or  numdiv == 7 or numdiv == 8 then  --17%
        clase = "[royale]"
        end
        if numdiv == 9 or  numdiv == 10 then -- 7%
        clase = "[epic]"
        end
        if numdiv == 11 or  numdiv == 12 or  numdiv == 13 then -- 3%
        clase = "[legendary]"
        end      
 
        self:setMaxHealth(maxHealth)
        self:addHealth(maxHealth)
        self:setName(""..clase.." "..self:getName().."", ""..clase.." "..self:getName().."")
        return true
    end

That should make it completely random, I just added math.randomseed(self:getId()+os.time()) inside the script. And os.time() isn't enough on it's own, since I believe most of the monsters spawns at the same time on startup and with self:getId() after every restart the same monsters will start with their new names etc, but with both it of them it should be completely random.

update the code but now this happens:

20171102153109.png



CODE NEW:

Code:
local config = {
    [1] = {chance = 40,clase ="commun", min = 1, max = 3},
    [2] = {chance = 33,clase ="rare", min = 4, max = 5},
    [3] = {chance = 17,clase ="royal", min = 6, max = 8},
    [4] = {chance = 7,clase ="epic", min = 9, max = 10},
    [5] = {chance = 3,clase ="legendary", min = 11, max = 13}
}

function Monster:onSpawn(position)
local totalChance = 100
for i = 1, #config do
    totalChance = totalChance + config[i].chance
end
math.randomseed(self:getId()+os.time())
local rand = math.random(totalChance)
local index = -1
for i = 1, #config do
    if rand <= config[i].chance then
        index = i
        break
    end
end

if index > -1 then
count = math.random(config[index].min, config[index].max)
maxHealth = self:getHealth()*count

        self:setMaxHealth(maxHealth)
        self:addHealth(maxHealth)
        self:setName("["..config[index].clase.."] "..self:getName().."", "["..config[index].clase.."] "..self:getName().."")

end
return true
end
 
I tried to start reading but got so annoyed about the way it's written.

You should write cleaner code, then perhaps you could understand what you writing or I would even be interested to read in first place.
It should take max 1 minute to improve it, but you got so many lines I didn't even bother.

Start by ordering your code in relevant order.
Configurations put on top.
classes ( aka the meta methods put in the middle)
functions below.
Scripting barely needs comments. So don't use them for such a case at all, what you want to do is straightforward.

In addition, don't spread configuration around. Put every bit of info in 1 table.
WHY did you kick into my face in the second line of code? Don't use this [1] number in monster names.
Expand table and put the meaning of the number as a table key.

Improve your code by above guides and I help you to optimize.
at least he doesn't put INT, STRING and T everywhere. thank god for that
 
update the code but now this happens:

20171102153109.png



CODE NEW:

Code:
local config = {
    [1] = {chance = 40,clase ="commun", min = 1, max = 3},
    [2] = {chance = 33,clase ="rare", min = 4, max = 5},
    [3] = {chance = 17,clase ="royal", min = 6, max = 8},
    [4] = {chance = 7,clase ="epic", min = 9, max = 10},
    [5] = {chance = 3,clase ="legendary", min = 11, max = 13}
}

function Monster:onSpawn(position)
local totalChance = 100
for i = 1, #config do
    totalChance = totalChance + config[i].chance
end
math.randomseed(self:getId()+os.time())
local rand = math.random(totalChance)
local index = -1
for i = 1, #config do
    if rand <= config[i].chance then
        index = i
        break
    end
end

if index > -1 then
count = math.random(config[index].min, config[index].max)
maxHealth = self:getHealth()*count

        self:setMaxHealth(maxHealth)
        self:addHealth(maxHealth)
        self:setName("["..config[index].clase.."] "..self:getName().."", "["..config[index].clase.."] "..self:getName().."")

end
return true
end

What's the issue now?
Is every monster supposed to have changed name etc? Then you change local totalChance = 100 to local totalChance = 0
 
What's the issue now?
Is every monster supposed to have changed name etc? Then you change local totalChance = 100 to local totalChance = 0

i change now to 0:
20171102160605.png


some come without a nickname (commun, rare, etc)
As I have the code, it is only creating commun.

the idea is that all have nickname, most are common, some rare, royal, and hard to find epic and legendary
 
You are comparing the random number with the weight of each separate rank instead of the cumulative number.
Lua:
rand = rand - config[i].chance
should fix that
Code:
local config = {
    [1] = {chance = 40,clase ="commun", min = 1, max = 3},
    [2] = {chance = 33,clase ="rare", min = 4, max = 5},
    [3] = {chance = 17,clase ="royal", min = 6, max = 8},
    [4] = {chance = 7,clase ="epic", min = 9, max = 10},
    [5] = {chance = 3,clase ="legendary", min = 11, max = 13}
}
function Monster:onSpawn(position)
local totalChance = 0
for i = 1, #config do
    totalChance = totalChance + config[i].chance
end
math.randomseed(self:getId()+os.time())
local rand = math.random(totalChance)
local index = -1
for i = 1, #config do
    if rand <= config[i].chance then
        index = i
        break
    end
    rand = rand - config[i].chance
end
if index > -1 then
count = math.random(config[index].min, config[index].max)
maxHealth = self:getHealth()*count
        self:setMaxHealth(maxHealth)
        self:addHealth(maxHealth)
        self:setName("["..config[index].clase.."] "..self:getName().."", "["..config[index].clase.."] "..self:getName().."")
end
return true
end
 
Solution
at least he doesn't put INT, STRING and T everywhere. thank god for that
I use T because I prefer "monsterT" over "monsters".
I rarely use INT or STR unless It's crucial to have some type variable or when I have a duplicate variable name. Usually, these come when I get lazy or hack something new into existing function.

Code:
--[[ config guide
    monsterClasses = {
        [STR] = {           monster rarity class
            chance = INT,   % chance
            min = INT,      ?
            max = INT,      ?
            classIndex = INT   why you need it?   
        }
    }

    AUTOMATIC
    totalChance = INT       total % of all monsters
    defaultClass = STR      the highest chance class
    highestChance = INT     the highest chance % of a single class
]]

local config = {
    monsterClasses = {
        ["commun"]      = {chance = 40, min = 1, max = 3, classIndex = 1},
        ["rare"]        = {chance = 33, min = 4, max = 5, classIndex = 2},
        ["royal"]       = {chance = 17, min = 6, max = 8, classIndex = 3},
        ["epic"]        = {chance = 7, min = 9, max = 10, classIndex = 4},
        ["legendary"]   = {chance = 3, min = 11, max = 13, classIndex = 5},
    },
}

math.randomseed(os.time()) -- it's enough if you do the randomseed on script load, adding randomseed every execution doesn't make it more random

local highestChance = 0
for className, classT in pairs(config.monsterClasses) do
    config.totalChance = (config.totalChance or 0) + classT.chance

    if classT.chance > highestChance then
        highestChance = classT.chance
        config.highestChance = highestChance
        classT.defaultClass = className
    end
end

function Monster:onSpawn(position)
    local rand = math.random(config.totalChance)
    local randomClassName = config.defaultClass

    for className, classT in pairs(config.monsterClasses) do
        if rand <= classT.chance then randomClassName = className end
    end
   
    local classT = config.monsterClasses[randomClassName]
    local healthMultiplier = math.random(classT.min, classT.max)
    local maxHealth = self:getHealth()*healthMultiplier
    local monsterName = self:getName()

    self:setMaxHealth(maxHealth)
    self:addHealth(maxHealth)
    self:setName("["..randomClassName.."] "..monsterName, "["..randomClassName.."] "..monsterName)
    return true
end

I would use a more accurate random algorhytm than this, because you need to keep making sure you add up to 100% with ur current chances else the highest chance rarity will scale up compared to others, but didnt feel like thinking how I did it before nor have my data folder with me.
 
I use T because I prefer "monsterT" over "monsters".
I rarely use INT or STR unless It's crucial to have some type variable or when I have a duplicate variable name. Usually, these come when I get lazy or hack something new into existing function.

Code:
--[[ config guide
    monsterClasses = {
        [STR] = {           monster rarity class
            chance = INT,   % chance
            min = INT,      ?
            max = INT,      ?
            classIndex = INT   why you need it?  
        }
    }

    AUTOMATIC
    totalChance = INT       total % of all monsters
    defaultClass = STR      the highest chance class
    highestChance = INT     the highest chance % of a single class
]]

local config = {
    monsterClasses = {
        ["commun"]      = {chance = 40, min = 1, max = 3, classIndex = 1},
        ["rare"]        = {chance = 33, min = 4, max = 5, classIndex = 2},
        ["royal"]       = {chance = 17, min = 6, max = 8, classIndex = 3},
        ["epic"]        = {chance = 7, min = 9, max = 10, classIndex = 4},
        ["legendary"]   = {chance = 3, min = 11, max = 13, classIndex = 5},
    },
}

math.randomseed(os.time()) -- it's enough if you do the randomseed on script load, adding randomseed every execution doesn't make it more random

local highestChance = 0
for className, classT in pairs(config.monsterClasses) do
    config.totalChance = (config.totalChance or 0) + classT.chance

    if classT.chance > highestChance then
        highestChance = classT.chance
        config.highestChance = highestChance
        classT.defaultClass = className
    end
end

function Monster:onSpawn(position)
    local rand = math.random(config.totalChance)
    local randomClassName = config.defaultClass

    for className, classT in pairs(config.monsterClasses) do
        if rand <= classT.chance then randomClassName = className end
    end
  
    local classT = config.monsterClasses[randomClassName]
    local healthMultiplier = math.random(classT.min, classT.max)
    local maxHealth = self:getHealth()*healthMultiplier
    local monsterName = self:getName()

    self:setMaxHealth(maxHealth)
    self:addHealth(maxHealth)
    self:setName("["..randomClassName.."] "..monsterName, "["..randomClassName.."] "..monsterName)
    return true
end

I would use a more accurate random algorhytm than this, because you need to keep making sure you add up to 100% with ur current chances else the highest chance rarity will scale up compared to others, but didnt feel like thinking how I did it before nor have my data folder with me.


classT anil value
 
I use T because I prefer "monsterT" over "monsters".
I rarely use INT or STR unless It's crucial to have some type variable or when I have a duplicate variable name. Usually, these come when I get lazy or hack something new into existing function.

Code:
--[[ config guide
    monsterClasses = {
        [STR] = {           monster rarity class
            chance = INT,   % chance
            min = INT,      ?
            max = INT,      ?
            classIndex = INT   why you need it?  
        }
    }

    AUTOMATIC
    totalChance = INT       total % of all monsters
    defaultClass = STR      the highest chance class
    highestChance = INT     the highest chance % of a single class
]]

local config = {
    monsterClasses = {
        ["commun"]      = {chance = 40, min = 1, max = 3, classIndex = 1},
        ["rare"]        = {chance = 33, min = 4, max = 5, classIndex = 2},
        ["royal"]       = {chance = 17, min = 6, max = 8, classIndex = 3},
        ["epic"]        = {chance = 7, min = 9, max = 10, classIndex = 4},
        ["legendary"]   = {chance = 3, min = 11, max = 13, classIndex = 5},
    },
}

math.randomseed(os.time()) -- it's enough if you do the randomseed on script load, adding randomseed every execution doesn't make it more random

local highestChance = 0
for className, classT in pairs(config.monsterClasses) do
    config.totalChance = (config.totalChance or 0) + classT.chance

    if classT.chance > highestChance then
        highestChance = classT.chance
        config.highestChance = highestChance
        classT.defaultClass = className
    end
end

function Monster:onSpawn(position)
    local rand = math.random(config.totalChance)
    local randomClassName = config.defaultClass

    for className, classT in pairs(config.monsterClasses) do
        if rand <= classT.chance then randomClassName = className end
    end
  
    local classT = config.monsterClasses[randomClassName]
    local healthMultiplier = math.random(classT.min, classT.max)
    local maxHealth = self:getHealth()*healthMultiplier
    local monsterName = self:getName()

    self:setMaxHealth(maxHealth)
    self:addHealth(maxHealth)
    self:setName("["..randomClassName.."] "..monsterName, "["..randomClassName.."] "..monsterName)
    return true
end

I would use a more accurate random algorhytm than this, because you need to keep making sure you add up to 100% with ur current chances else the highest chance rarity will scale up compared to others, but didnt feel like thinking how I did it before nor have my data folder with me.
all im really missing is just WIS, INT, AGI and VIT
 
Back
Top