308 lines
11 KiB
Lua
308 lines
11 KiB
Lua
--[[
|
|
Illarion Server
|
|
|
|
This program is free software: you can redistribute it and/or modify it under
|
|
the terms of the GNU Affero General Public License as published by the Free
|
|
Software Foundation, either version 3 of the License, or (at your option) any
|
|
later version.
|
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
details.
|
|
|
|
You should have received a copy of the GNU Affero General Public License along
|
|
with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
]]
|
|
--[[The collection contains some function to cedign mobs]]
|
|
local common = require("base.common")
|
|
|
|
local M = {}
|
|
|
|
local mobs = {}
|
|
--[[
|
|
mobs[] = { nameDe="",
|
|
nameEn="",
|
|
monsters = {{id or {ids},min,max},{}}
|
|
} ]]--
|
|
mobs[1] = { nameDe="Kapitän Molgans glausame Pilaten",
|
|
nameEn="Kaptain Molgans feald pilates",
|
|
monsters = {{2,1,1},{{3,4},1,2},{{2,12,22,42,52},0,7},{15,25,44},0,2},
|
|
help = "human warrior, 0-7 warriors from all races; 1-2 necromancer or mages; 0-2 archer"
|
|
}
|
|
mobs[2] = { nameDe="Sperlings Piraten",
|
|
nameEn="Sperlings Pirates",
|
|
monsters = {{2,1,4},{1,1,6},{5,0,5},{3,1,1}},
|
|
help = "average human set, 1 mage"
|
|
}
|
|
mobs[3] = { nameDe="Piraten vom großen Weiher",
|
|
nameEn="Pirates of the large pond",
|
|
monsters = {{2,1,1},{1,0,5},{5,0,5}},
|
|
help = "human warrior, 0-10 human or human thieves"
|
|
}
|
|
mobs[4] = { nameDe="Piraten in Ausbildung",
|
|
nameEn="Pirate apprentices",
|
|
monsters = {{1,1,2},{{5,23,43},2,5},{582,0,3}},
|
|
help = "human, 2-5 thieves, 0-3 dogs"
|
|
}
|
|
mobs[5] = { nameDe="Elfen des Meeres",
|
|
nameEn="Elves of the sea",
|
|
monsters = {{33,1,1},{{32,34},1,3},{{31,35},0,6}},
|
|
help = "elves, priest, 1-3 mage or warrior, 0-6 elf or hunter"
|
|
}
|
|
mobs[6] = { nameDe="Schwimmende Seeräuber",
|
|
nameEn="Swimming pirates",
|
|
monsters = {{52,1,1},{{53,54},1,1},{{51,55},0,6}},
|
|
help = "1 lizzard warrior, priest or mage, 0-6 lizzards or thives"
|
|
}
|
|
mobs[7] = { nameDe="Verlauste Seeräuber",
|
|
nameEn="Lousy pirates",
|
|
monsters = {{573,1,3},{{582,592,1031,1051,1111,1112},0,10}},
|
|
help = "1-3 ratmen, 0-10 level 0 vermin"
|
|
}
|
|
mobs[8] = { nameDe="Mumientanz in heller Nacht",
|
|
nameEn="Mummys dance in a bright night",
|
|
monsters = {{{111,152},1,3},{{171,115},0,1},{{101,103,114,151,172,762},0,10}},
|
|
help = "1-3 skeletons, 0-1 low undead mage, 0-10 level 1 undeads, beetle"
|
|
}
|
|
mobs[9] = { nameDe="Unbekannt und ungefürchtet",
|
|
nameEn="Unknown and unfeared",
|
|
monsters = {{23,1,2},{{21,24},0,7},{{582,592,1031,1051,1111,1112},0,10}},
|
|
help = "1-2 halfling thief, 0-7 halflings, 0-10 level 0 vermin"
|
|
}
|
|
mobs[10] = { nameDe="Ork Räuber",
|
|
nameEn="Orc robber",
|
|
monsters = {{42,1,3},{{45,44},2,1},{{41,43},0,6},{872,871,851},0,2},
|
|
help = "1-3 orc warrior, schaman or hunter, 0-6 orc or thives, 0-2 hellhounds"
|
|
}
|
|
mobs[100] = { nameDe="Armee des Liches",
|
|
nameEn="Liche army",
|
|
monsters = {{205,1,1},{{202,204,783},1,2},{{201,203,782},2,10},{{744,784,753},2,7},{{206,741,751},0,10},{{111,112,113,114},0,15}},
|
|
help = "1 liche, 1-2 mages, 2-10 higher warrior, 2-7 archer, 0-10 lower special warriors, 0-15 skeletons"
|
|
}
|
|
mobs[101] = { nameDe="Ratten",
|
|
nameEn="rats",
|
|
monsters = {{{1115,1116},1,1},{{1113,1114,1115},1,4},{1112,2,10}},
|
|
help = "rat pack 1 xlvl 3; 1-4 xlvl 1; 2-10 xlvl 0"
|
|
}
|
|
|
|
local DEFAULT_MOB_SIZE = 6
|
|
|
|
local function gmGetSpawnRange(item)
|
|
local range = item:getData("mobspawnrange")
|
|
if range ~= nil then
|
|
range = tonumber(range)
|
|
end
|
|
if range == nil then
|
|
range = 4
|
|
end
|
|
return range
|
|
end
|
|
|
|
local function gmSetSpawnRange(user,item)
|
|
local thisInputDialog = function (dialog)
|
|
|
|
if (not dialog:getSuccess()) then
|
|
return
|
|
end
|
|
|
|
local input = dialog:getInput()
|
|
|
|
if not common.IsNilOrEmpty(input) then
|
|
local value = (tonumber(input))
|
|
if value == nil then
|
|
user:inform("This input is not valid: "..input)
|
|
else
|
|
user:inform("Spawn range changed to "..tostring(value).." tiles.")
|
|
item:setData("mobspawnrange",value)
|
|
world:changeItem(item)
|
|
end
|
|
M.gmSpawnMob(user,item)
|
|
end
|
|
end
|
|
|
|
user:requestInputDialog(InputDialog("Spawn Mob Selection",
|
|
"Enter the range for the spawn area\nCurrent range: "..tostring(gmGetSpawnRange(item)).." tiles",
|
|
false, 255, thisInputDialog))
|
|
end
|
|
|
|
local function gmGetSpawnSize(item)
|
|
local size = item:getData("mobspawnsize")
|
|
if size ~= nil then
|
|
size = tonumber(size)
|
|
end
|
|
if size == nil then
|
|
size = 4
|
|
end
|
|
return size
|
|
end
|
|
|
|
local function gmSetSpawnSize(user,item)
|
|
local thisInputDialog = function (dialog)
|
|
|
|
if (not dialog:getSuccess()) then
|
|
return
|
|
end
|
|
|
|
local input = dialog:getInput()
|
|
|
|
if not common.IsNilOrEmpty(input) then
|
|
local value = (tonumber(input))
|
|
if value == nil then
|
|
user:inform("This input is not valid: "..input)
|
|
else
|
|
user:inform("Spawn size changed to "..tostring(value).." monsters.")
|
|
item:setData("mobspawnsize",value)
|
|
world:changeItem(item)
|
|
end
|
|
M.gmSpawnMob(user,item)
|
|
end
|
|
end
|
|
|
|
user:requestInputDialog(InputDialog("Spawn Mob Selection",
|
|
"Enter the size for the mob\nCurrent size: "..tostring(gmGetSpawnSize(item)).." monsters",
|
|
false, 255, thisInputDialog))
|
|
end
|
|
|
|
local function gmSpawnNow(user,mobId,amount,range)
|
|
user:inform("Monster group "..mobs[mobId].nameEn.." ("..tostring(mobId)..") spawned with "..tostring(amount).." monsters.")
|
|
local mob = M.getMonsters(mobId,amount)
|
|
for _, monster in pairs (mob) do
|
|
local pos = common.getFreePos(user.pos, range)
|
|
world:createMonster(monster,pos,0)
|
|
end
|
|
end
|
|
|
|
local function getCapability(user)
|
|
local skillFight = math.max (user:getSkill(Character.concussionWeapons),
|
|
user:getSkill(Character.distanceWeapons),
|
|
user:getSkill(Character.punctureWeapons),
|
|
user:getSkill(Character.slashingWeapons))
|
|
local skillDefense = math.max (user:getSkill(Character.heavyArmour),
|
|
user:getSkill(Character.lightArmour),
|
|
user:getSkill(Character.mediumArmour))
|
|
local skillMage = user:getSkill(Character.fireMagic)
|
|
local skillParry = user:getSkill(Character.parry)
|
|
local attAgility = user:getBaseAttribute("agility")
|
|
local attConstitution = user:getBaseAttribute("constitution")
|
|
local attDexterity = user:getBaseAttribute("dexterity")
|
|
local attEssence = user:getBaseAttribute("essence")
|
|
local attIntelligence = user:getBaseAttribute("intelligence")
|
|
local attPerception = user:getBaseAttribute("perception")
|
|
local attStrength = user:getBaseAttribute("strength")
|
|
|
|
local capaFight = (100 + (attStrength-6)*3 + (attPerception-6) + (attDexterity-6) + (skillFight-20)*1.5 ) / 2.9
|
|
local capaMage = (100 + (attIntelligence-6)*3.5 + (attEssence-6)*1.1 + (skillMage-20)*1.5 ) / 2.82
|
|
local capaDefense = attConstitution * skillDefense / 20
|
|
local capaParry = skillParry / 5 * (0.5 + attAgility/10) * 2
|
|
|
|
local capabilityTotal = 0.5 * math.max(capaFight, capaMage) + 0.38 * capaDefense + 0.12 * capaParry
|
|
return capabilityTotal
|
|
end
|
|
|
|
function M.gmSpawnMob(user,item)
|
|
local optionList = {}
|
|
local dialogTitle
|
|
local dialogAddText
|
|
local SELECT_SETRANGE = -1
|
|
local SELECT_SETSIZE = -2
|
|
|
|
local callback = function(dialog)
|
|
if (not dialog:getSuccess()) then
|
|
return
|
|
end
|
|
local selected = dialog:getSelectedIndex()
|
|
local selectedOption = optionList[selected+1]
|
|
if selectedOption == SELECT_SETRANGE then
|
|
gmSetSpawnRange(user,item)
|
|
elseif selectedOption == SELECT_SETSIZE then
|
|
gmSetSpawnSize(user,item)
|
|
else
|
|
gmSpawnNow(user,selectedOption,gmGetSpawnSize(item),gmGetSpawnRange(item))
|
|
end
|
|
end
|
|
dialogTitle = "Spawn Mob Selection"
|
|
dialogAddText = "Select the function"
|
|
local dialog = SelectionDialog(dialogTitle, dialogAddText, callback)
|
|
|
|
dialog:addOption(0, "Amount of monster in spawn: "..tostring(gmGetSpawnSize(item)).." monsters")
|
|
table.insert(optionList, SELECT_SETSIZE)
|
|
dialog:addOption(0, "Range of the spawn: "..tostring(gmGetSpawnRange(item)).." tiles")
|
|
table.insert(optionList, SELECT_SETRANGE)
|
|
for i, mob in pairs(mobs) do
|
|
if not common.IsNilOrEmpty(mob.nameEn) and not common.IsNilOrEmpty(mob.help)then
|
|
dialog:addOption(1, mob.nameEn.."\n"..mob.help)
|
|
table.insert(optionList, i)
|
|
end
|
|
end
|
|
user:requestSelectionDialog(dialog)
|
|
end
|
|
|
|
function M.getPartyFightCapability(partyMembers)
|
|
local capabilityList = {}
|
|
local countParty = 0
|
|
for _, member in pairs (partyMembers) do
|
|
table.insert(capabilityList, getCapability(member))
|
|
countParty = countParty + 1
|
|
end
|
|
table.sort(capabilityList, function(a,b) return tonumber(a) > tonumber(b) end)
|
|
local bestFighter = capabilityList[1]
|
|
local totalParty = 0
|
|
for i, rowValue in ipairs(capabilityList) do
|
|
totalParty = totalParty + rowValue / i
|
|
end
|
|
return countParty, bestFighter, totalParty
|
|
end
|
|
|
|
function M.getMonsters(baseList, number, mobListExt)
|
|
local workingMob
|
|
if type(baseList) == "number" then
|
|
workingMob = mobs[baseList]
|
|
elseif type(baseList) == "table" then
|
|
if baseList.monsters ~= nil then
|
|
workingMob = baseList
|
|
else
|
|
workingMob = nil
|
|
end
|
|
else
|
|
workingMob = nil
|
|
end
|
|
local mobList = mobListExt or {}
|
|
local sizeMob = tonumber(number) or DEFAULT_MOB_SIZE
|
|
if workingMob == nil then
|
|
return {}
|
|
end
|
|
|
|
for _, mobRow in pairs(workingMob.monsters) do
|
|
if mobRow[2] > 0 then
|
|
for i=1, mobRow[2] do
|
|
table.insert(mobList, common.getOneOutOfList(mobRow[1]))
|
|
mobRow[3] = mobRow[3] - 1
|
|
if #mobList >= sizeMob then
|
|
return mobList
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local tmpList = {}
|
|
for _, mobRow in pairs(workingMob.monsters) do
|
|
if mobRow[3] > 0 then
|
|
for i=1, mobRow[3] do
|
|
table.insert(tmpList, common.getOneOutOfList(mobRow[1]))
|
|
end
|
|
end
|
|
end
|
|
common.Shuffle(tmpList)
|
|
for i=1, math.min(#tmpList, sizeMob - #mobList) do
|
|
table.insert(mobList, tmpList[i])
|
|
end
|
|
|
|
if sizeMob > #mobList then
|
|
M.getMonsters(baseList, number, mobList)
|
|
end
|
|
|
|
return mobList
|
|
end
|
|
|
|
return M
|