Code: Select all
data = {}
function get(name) return data[name] end
function set(name,value) data[name] = value end
levels = {1,2,3,4,5,6,7,8,9,10,20,25,50,50,50,50,100,100,500,1000}
function xpUp(level) return level>0 and levels[math.min(#levels,level)]*1000 or 0 end
function xp(level)
if level <= 1 then return 0 end
local l1 = math.floor(level)
local l2 = level-l1
local x = 0
for l = 1,l1-1 do x = x + xpUp(l) end
return x + l2*xpUp(l1)
end
function level(xp)
local level = 1
while true do
local up = xpUp(level)
if xp < up then return level,xp/up else xp = xp-up level = level+1 end
end
end
function floatLevel(xp)
local l1,l2 = level(xp)
return l1+l2
end
function addStat(tab, name, value) tab[name] = (tab[name] or 0)+value end
function levelUp(c)
local class = traits.script.defByName[c.class]
if class then
addStat(c, "maxHealth", class.hu)
addStat(c, "maxEnergy", class.eu)
end
if c.class == "barbarian" then addStat(c.currentStats, "strength", 1)
elseif c.class == "knight" then addStat(c, "protection", 1)
elseif c.class == "wizard" then addStat(c.currentStats, "willpower", 1)
end
end
stats = {'strength','dexterity','vitality','willpower','exp_rate'}
conditions = {}
champions = {}
function defineChampion(def)
local index = #champions+1
def.index = index
champions[index] = def
end
function storeChampion(champ, tavern)
defineChampion {
baseStats = getBaseStats(champ),
currentStats = getCurrentStats(champ),
class = champ:getClass(),
dualClass = champ:getDualClass(),
energy = champ:getEnergy(),
evasion = champ:getEvasion(),
experience = champ:getExp(),
food = champ:getFood(),
water = getWater(champ),
health = champ:getHealth(),
level = champ:getLevel(),
load = champ:getLoad(),
maxEnergy = champ:getMaxEnergy(),
maxHealth = champ:getMaxHealth(),
maxLoad = champ:getMaxLoad(),
name = champ:getName(),
portrait = getPortrait(champ),
protection = champ:getProtection(),
race = champ:getRace(),
sex = champ:getSex(),
skillLevels = skills.script.getSkillLevels(champ),
traits = traits.script.getTraits(champ),
spells = traits.script.getSpells(champ),
skillPoints = champ:getSkillPoints(),
description = getDescription(champ),
deltaLevel = getDeltaLevel(champ),
plan = getPlan(champ),
magic = getMagic(champ),
items = getItems(champ),
money = getMoney(champ),
tavern = tavern,
}
champ:setEnabled(false)
set("mortar"..champ:getOrdinal(), nil)
end
function loadChampion(index, ordinal)
local replaceChamp = nil
if not ordinal then for i = 1,4 do if not party.party:getChampionByOrdinal(i):getEnabled() then ordinal = i break end end end
if not ordinal then return end
replaceChamp = party.party:getChampionByOrdinal(ordinal)
if not replaceChamp or replaceChamp:getEnabled() then return end
local data = table.remove(champions, index)
if index <= championUpdateIndex then championUpdateIndex = championUpdateIndex-1 end
for i = 1,#champions do champions[i].index = i end
if not data then return end
if type(data.portrait) == "number" and ordinal ~= data.portrait then
local loadChamp = party.party:getChampionByOrdinal(data.portrait)
if loadChamp:getEnabled() then
storeChampion(loadChamp)
loadChampion(#champions, ordinal)
end
replaceChamp = loadChamp
ordinal = data.portrait
end
replaceChamp:setEnabled(true)
replaceChamp:resetExp()
traits.script.resetTraitsAndSpells(replaceChamp)
resetItems(replaceChamp)
local expRate = replaceChamp:getCurrentStat("exp_rate")
if expRate ~= 100 then replaceChamp:addStatModifier("exp_rate", 100-expRate) end
replaceChamp:gainExp(data.experience)
replaceChamp:setName(data.name)
replaceChamp:setRace(data.race)
replaceChamp:setSex(data.sex)
replaceChamp:setClass(data.class)
setBaseStats(replaceChamp,data.baseStats)
replaceChamp:setEnergy(data.energy)
replaceChamp:setFood(data.food)
setWater(data.water, replaceChamp)
replaceChamp:setHealth(data.health)
set("portrait"..ordinal, data.portrait)
set("description"..ordinal, data.description)
set("deltaLevel"..ordinal, data.deltaLevel)
set("plan"..ordinal, data.plan)
set("magic"..ordinal, data.magic)
traits.script.addTraits(replaceChamp, data.traits)
traits.script.addSpells(replaceChamp, data.spells)
skills.script.setSkillLevels(replaceChamp, data.skillLevels)
replaceChamp:setSkillPoints(data.skillPoints)
addItems(replaceChamp, data.items)
money[replaceChamp:getOrdinal()] = data.money<0 and 0 or data.money
hudPrint('') hudPrint('') hudPrint('') hudPrint('')
hudPrint(data.name..' joined to your party.')
if data.onRecruit then
data.onRecruit(data)
end
end
function getPortrait(from)
if type(from) == "string" then return from end
if type(from) == "number" then for j = 1,4 do if party.party:getChampion(j):getOrdinal() == from then return "$portrait"..j end end return from end
local i = from:getOrdinal()
local p = get("portrait"..i)
return iff(type(p) == "string", p, i)
end
function getCurrentPortrait(champ)
local i = champ:getOrdinal()
local p = get("portrait"..i)
return iff(type(p) == "string", p, getPortrait(i))
end
function getDescription(champ)
return get("description"..champ:getOrdinal()) or "Your old friend. Always there since the beginning!"
end
function getDeltaLevel(champ)
return get("deltaLevel"..champ:getOrdinal()) or 0
end
function getPlan(champ)
return get("plan"..champ:getOrdinal())
end
function getMagic(champ)
return get("magic"..champ:getOrdinal())
end
function getItems(champ)
local c = findEntity("champions")
local items = spawn("inventory", c.level, c.x, c.y, c.facing, c.elevation)
for i = 1, ItemSlot.MaxSlots do
local item = champ:getItem(i)
if item then
items.store:insertItem(i, item)
champ:removeItemFromSlot(i)
end
end
return items.id
end
function resetItems(champ)
local c = findEntity("champions")
for i = 1, ItemSlot.MaxSlots do if champ:getItem(i) then champ:removeItemFromSlot(i) end end
end
function addItems(champ, items)
if not items then return end
if type(items) == "string" then
items = findEntity(items)
if not items then return end
for i = 1, ItemSlot.MaxSlots do
local item = items.store:getItem(i)
if item then champ:insertItem(i, item) end
end
items:destroy()
else
for i = 1, ItemSlot.MaxSlots do
if items[i] then
local item = createItem(items[i])
if item then champ:insertItem(i, item) end
end
end
end
end
function createItem(def)
local item = nil
if type(def) == "string" then item = self.go:spawn(def).item
else
item = self.go:spawn(def[1]).item
if item:getStackable() then item:setStackSize(def[2])
elseif item.go.containerItem then for i = 2,#def do
local it = createItem(def[i])
if it then item.go.containerItem:addItem(it) end
end
else item:setCharges(def[2]) end
end
return item
end
function getBaseStats(champ)
local result = {}
for _,stat in ipairs(stats) do
result[stat] = champ:getBaseStat(stat)
end
return result
end
function setBaseStats(champ,stats)
for stat,value in pairs(stats) do
champ:setBaseStat(stat,value)
end
end
function getCurrentStats(champ)
local result = {}
for _,stat in ipairs(stats) do
result[stat] = champ:getCurrentStat(stat)
end
return result
end
-- GUI functions
mouseX,mouseY = 0,0
craftX,craftY = 0,0
mouseL,mouseR = false,false
tooltip = {"Water","All actions you do consume water. The bar turns", "yellow when you're Thirsty and you start losing", "Energy. If you don't have Energy you lose", "Health instead."}
function drawChampionGUI(context, champion)
local w, h, f = context.width, context.height, context.height/1080
--context.drawImage2(fileName, x, y, srcX, srcY, srcWidth, srcHeight, destWidth, destHeight)
context.drawImage2("mod_assets/textures/gui/food-water.tga", w-f*421, f*144, 0, 0, 373, 23, f*373, f*23)
local food = champion:getFood()
local foodbar = food<250 and "mod_assets/textures/gui/bar-red.tga" or food<350 and "mod_assets/textures/gui/bar-yellow.tga" or "mod_assets/textures/gui/bar-green.tga"
context.drawImage2(foodbar, w-f*298, f*147, 0, 0, 246, 8, f*246*food/1000, f*8)
local water = getWater(champion)
local waterbar = water<250 and "mod_assets/textures/gui/bar-red.tga" or water<350 and "mod_assets/textures/gui/bar-yellow.tga" or "mod_assets/textures/gui/bar-blue.tga"
local xw, ww, yw, hw = w-f*298, f*246, f*156, f*8
context.drawImage2(waterbar, xw, yw, 0, 0, 246, 8, ww*water/1000, hw)
local mX,mY = context.inverseTransformPoint(context.mouseX, context.mouseY)
if xw < mX and mX < xw+ww and yw+2 < mY and mY < yw+2+hw then
context.font(fontSize[1+math.floor(#fontSize*f*0.5)] or fontSize[#fontSize])
local th = context.getLineHeight()
local wt,ht,b = 0,#tooltip*th,8
for _,l in ipairs(tooltip) do
local lw = context.getTextWidth(l)
if lw>wt then wt=lw end
end
wt,ht = wt+2*b,ht+2*b
local x, y = math.min(w-wt-2*b, mX-wt/2), mY<h/2 and math.min(mY+37, 1080-ht) or math.max(mY-37-ht, 0)
context.color(0, 0, 0, 192)
context.drawRect(x-1, y-1, wt+2, ht+2)
context.color(255, 255, 255, 255)
--context.drawGuiItem2(item, x, y, srcX, srcY, srcWidth, srcHeight, width, height)
context.drawGuiItem2("DialogFrameSideBottom", x, y+ht-2, 0, 0, 90, 5, wt, 5)
context.drawGuiItem2("DialogFrameSideLeft", x-3, y, 0, 0, 5, 90, 5, ht)
context.drawGuiItem2("DialogFrameSideRight", x+wt-2, y, 0, 0, 5, 90, 5, ht)
context.drawGuiItem2("DialogFrameSideTop", x, y-3, 0, 0, 90, 5, wt, 5)
--context.drawGuiItem(item, x, y)
context.drawGuiItem("DialogFrameCornerBottomLeft", x-3, y+ht-2)
context.drawGuiItem("DialogFrameCornerBottomRight", x+wt-2, y+ht-2)
context.drawGuiItem("DialogFrameCornerTopLeft", x-3, y-3)
context.drawGuiItem("DialogFrameCornerTopRight", x+wt-2, y-3)
context.color(255, 255, 255, 255)
x,y = x+b,y+b
context.font(fontSize[1+math.floor(#fontSize*f)] or fontSize[#fontSize])
context.drawText(tooltip[1], x, y+th)
context.font(fontSize[1+math.floor(#fontSize*f*0.5)] or fontSize[#fontSize])
for i = 2,#tooltip do context.drawText(tooltip[i], x, y+i*th) end
end
local mortar = get("mortar"..champion:getOrdinal())
if not mortar then return end
mortar = champion:getItem(mortar)
if not mortar or not mortar.go.craftpotioncustom then set("mortar"..champion:getOrdinal(), nil) return end
--context.scale(f, f)
local x0, y0 ,w0 ,h0 = w-f*544+craftX, h-f*352+craftY, f*64, f*320
context.button("craftpotionbutton", x0, y0, w0, h0)
--context.drawGuiItem2(item, x, y, srcX, srcY, srcWidth, srcHeight, width, height)
context.drawGuiItem2("InventoryTab", x0, y0, 237, 64, 64, 320, w0, h0)
--context.drawGuiItem2(item, x, y, srcX, srcY, srcWidth, srcHeight, width, height)
context.drawGuiItem2("DialogFrameSideBottom", x0, y0+h0-2*f, 0, 0, 90, 5, w0, 5*f)
context.drawGuiItem2("DialogFrameSideLeft", x0-3*f, y0, 0, 0, 5, 90, 5*f, h0)
context.drawGuiItem2("DialogFrameSideRight", x0+w0-2*f, y0, 0, 0, 5, 90, 5*f, h0)
context.drawGuiItem2("DialogFrameSideTop", x0, y0-3*f, 0, 0, 90, 5, w0, 5*f)
--context.drawGuiItem(item, x, y)
context.drawGuiItem("DialogFrameCornerBottomLeft", x0-3*f, y0+h0-2*f)
context.drawGuiItem("DialogFrameCornerBottomRight", x0+w0-2*f, y0+h0-2*f)
context.drawGuiItem("DialogFrameCornerTopLeft", x0-3*f, y0-3*f)
context.drawGuiItem("DialogFrameCornerTopRight", x0+w0-2*f, y0-3*f)
context.drawImage2("mod_assets/textures/gui/up.tga", x0+w0*0.25, y0+h0*0.2-w0*0.125, 0, 0, 64, 32, w0*0.5, w0*0.25)
local potion = mortar.go.craftpotioncustom:get(0)
local atlas,x,y
if potion then atlas,x,y = shops.script.getItemIconByName(potion[1]) else atlas,x,y = shops.script.getItemIcon(mortar) end
context.drawImage2(atlas, x0, y0, x, y, 75, 75, w0, w0)
local mL = context.mouseDown(0)
if x0 < mX and mX < x0+w0 and y0 < mY and mY < y0+h0 then
if mL then
if mouseL then
craftX,craftY = craftX+mX-mouseX,craftY+mY-mouseY
else
local mouseItem = getMouseItem()
local index = math.floor(5*(mY-y0)/h0)
if index>0 then
local craftItem = mortar.go.craftpotioncustom:get(index)
if mouseItem then
if mouseItem:hasTrait("herb") or mouseItem.go.name == "water_flask" then
if craftItem and craftItem[2]>0 and craftItem[1] == mouseItem.go.name then
if context.keyDown("shift") then
mortar.go.craftpotioncustom:set(index, {craftItem[1], craftItem[2]-1})
mouseItem:setStackSize(mouseItem:getStackSize()+1)
else
mortar.go.craftpotioncustom:set(index, {craftItem[1], craftItem[2]+mouseItem:getStackSize()})
setMouseItem(nil)
end
else
mortar.go.craftpotioncustom:set(index, {mouseItem.go.name, mouseItem:getStackSize()})
mouseItem = nil
setMouseItem(nil)
end
end
else
if craftItem and craftItem[2]>0 and context.keyDown("shift") then
mortar.go.craftpotioncustom:set(index, {craftItem[1], craftItem[2]-1})
mouseItem = spawn(craftItem[1]).item
setMouseItem(mouseItem)
else
mortar.go.craftpotioncustom:set(index, nil)
end
end
if not mouseItem and craftItem and craftItem[2]>0 then
mouseItem = spawn(craftItem[1]).item
mouseItem:setStackSize(craftItem[2])
setMouseItem(mouseItem)
end
local tmp = {}
for i = 1,4 do
craftItem = mortar.go.craftpotioncustom:get(i)
if craftItem and craftItem[2]>0 then
tmp[ingredientID[craftItem[1]]] = (tmp[ingredientID[craftItem[1]]] or 0) + craftItem[2]
end
end
local ingredients = ""
for i = 1,6 do if tmp[i] then for j = 1,tmp[i] do ingredients = ingredients..tostring(i) end end end
if tmp[0] then for j = 1,tmp[0] do ingredients = ingredients.."0" end end
local level = champion:getSkillLevel("alchemy")
mortar.go.craftpotioncustom:set(0, nil)
for _,r in ipairs(recipes.script.defOrdered) do
if level < r.level then break end
if ingredients == tostring(r.ingredients) then
local name,num = r.potion,1
if champion:hasTrait("improved_alchemy") then
name = name == "potion_healing" and "potion_greater_healing" or name == "potion_energy" and "potion_greater_energy" or name
end
if champion:hasTrait("bomb_expert") and (name == "fire_bomb" or name == "frost_bomb" or name == "poison_bomb" or name == "shock_bomb") then num = 3 end
mortar.go.craftpotioncustom:set(0, {name, num})
break
end
end
elseif potion and not mouseItem then
mouseItem = spawn(potion[1]).item
mouseItem:setStackSize(potion[2])
setMouseItem(mouseItem)
for i = 0,4 do mortar.go.craftpotioncustom:set(i, nil) end
end
end
end
end
context.font(fontSize[1+math.floor(#fontSize*f*0.5)] or fontSize[#fontSize])
for l = 1,4 do
local craftItem = mortar.go.craftpotioncustom:get(l)
if craftItem and craftItem[2]>0 then
atlas,x,y = shops.script.getItemIconByName(craftItem[1])
context.drawImage2(atlas, x0, y0+l*w0, x, y, 75, 75, w0, w0)
local n = tostring(craftItem[2])
local nw,nh = context.getTextWidth(n),context.getLineHeight()
context.drawText(n, x0+0.9*w0-nw, y0+l*w0+nh)
end
end
mouseX,mouseY = mX,mY
mouseL = mL
end
ingredientID = {
water_flask = 0,
blooddrop_cap = 1,
etherweed = 2,
mudwort = 3,
falconskyre = 4,
blackmoss = 5,
crystal_flower = 6,
}
fontSize = {"tiny", "small", "medium", "large"}
function drawInventory(context, champion)
drawChampionGUI(context, champion)
local f = context.height/1080
drawMoney(context, f, getMoney(champion), context.width-f*549, f*609, 1, champion)
end
function getMoneyWidth(context, f, money, tf)
tf = tf or f
context.font(fontSize[1+math.floor(#fontSize*f*0.5)] or fontSize[#fontSize])
local result = 0
local ms = f*24
local showSilver = false
local gold = math.floor(money/10000)
if gold>0 then
gold = tostring(gold)
result = result + context.getTextWidth(gold)/tf + 1.5*ms
showSilver = true
end
local silv = math.floor(money/100) % 100
if silv>0 or showSilver then
silv = tostring(silv)
result = result + context.getTextWidth(silv)/tf + 1.5*ms
end
local copp = math.floor(money) % 100
copp = tostring(copp)
result = result + context.getTextWidth(copp)/tf + ms
return result
end
function drawMoney(context, f, money, x, y, tf, championShare)
tf = tf or f
context.font(fontSize[1+math.floor(#fontSize*f*0.5)] or fontSize[#fontSize])
local x0 = x
local th = context.getLineHeight()
local ms = f*24
local showSilver = false
local gold = math.floor(money/10000)
if gold>0 then
gold = tostring(gold)
local gw = context.getTextWidth(gold)/tf
context.color(214, 204, 170, 255)
context.drawText(gold, x, y+0.75*ms)
x = x+gw
context.color(255, 255, 255, 255)
--context.drawImage2(fileName, x, y, srcX, srcY, srcWidth, srcHeight, destWidth, destHeight)
context.drawImage2("mod_assets/textures/gui/gold.tga", x, y, 0, 0, 24, 24, ms, ms)
x = x+1.5*ms
showSilver = true
end
local silv = math.floor(money/100) % 100
if silv>0 or showSilver then
silv = tostring(silv)
local sw = context.getTextWidth(silv)/tf
context.color(192, 192, 192, 255)
context.drawText(silv, x, y+0.75*ms)
x = x+sw
context.color(255, 255, 255, 255)
context.drawImage2("mod_assets/textures/gui/silver.tga", x, y, 0, 0, 24, 24, ms, ms)
x = x+1.5*ms
end
local copp = math.floor(money) % 100
copp = tostring(copp)
local cw = context.getTextWidth(copp)/tf
context.color(188, 160, 139, 255)
context.drawText(copp, x, y+0.75*ms)
x = x+cw
context.color(255, 255, 255, 255)
context.drawImage2("mod_assets/textures/gui/copper.tga", x, y, 0, 0, 24, 24, ms, ms)
if championShare then
x = x+1.5*ms
local mouseX,mouseY = context.inverseTransformPoint(context.mouseX, context.mouseY)
if x0<mouseX and mouseX<x and y<mouseY and mouseY<y+ms then
local mL, mR = context.mouseDown(0), context.mouseDown(2)
if mouseL and not mL then
if context.keyDown("shift") then shareAllMoney() else getAllMoney(championShare) end
elseif mouseR and not mR then
shareAllMoney()
end
mouseL, mouseR = mL, mR
end
end
end
function getBody(champ)
local result = "default"
local race = champ:getRace()
if race == "insectoid" or race == "lizardman" or race == "ratling" then
result = race
else
result = race.."_"..champ:getSex()
end
return "mod_assets/textures/gui/inventory_backgrounds/alpha/"..result..".tga"
end
-- elemental resistance functions
lastHurt = {fire={0,0,0,0},shock={0,0,0,0},cold={0,0,0,0},poison={0,0,0,0}}
weakness = {fire={0,0,0,0},shock={0,0,0,0},cold={0,0,0,0},poison={0,0,0,0}}
function getWeakness(champion, element)
local e = weakness[element]
if e and champion:getEnabled() then
return math.floor(e[champion:getOrdinal()])
end
return 0
end
function addWeakness(champion, element)
local e = weakness[element]
if e and champion:getEnabled() then
local i = champion:getOrdinal()
local t = Time.currentTime()
local r = champion:getResistance(element)
local w = champion:hasCondition(element.."_weakness")
if not w then e[i] = 0 lastHurt[element][i] = 0 end
local malus = math.min(0.5, 0.02*(t-lastHurt[element][i]))*r/100*(r+e[i])
lastHurt[element][i] = t
e[i] = e[i]+malus
if e[i]>=1 and not w then champion:setCondition(element.."_weakness") end
end
end
function weaknessTick(champion, element)
local e = weakness[element]
if e and champion:getEnabled() then
local i = champion:getOrdinal()
e[i] = e[i]*0.98
return e[i]>=1
end
end
-- money functions
money = {0,0,0,0}
function getMoney(champion) return money[champion:getOrdinal()] end
function modifyMoney(amount, champion) setMoney(getMoney(champion)+amount, champion) end
function setMoney(amount, champion) money[champion:getOrdinal()] = amount<0 and 0 or amount playSound("money") end
function partyPay(cost)
local each, total = {}, 0
for i = 1,4 do
local c = party.party:getChampionByOrdinal(i)
if c and c:getEnabled() and c:isAlive() then
local m = getMoney(c)
each[#each+1] = {c, m}
total = total+m
end
end
if total<cost then return false end
repeat
for i = #each,1,-1 do if each[i][2] == 0 then table.remove(each, i) end end
local share = #each
for _,c in ipairs(each) do
local amount = spells_functions.script.quantum(cost/share)
if c[2]<amount then amount = c[2] end
c[2] = c[2]-amount
money[c[1]:getOrdinal()] = c[2]
cost = cost-amount
share = share-1
end
until cost < 1
playSound("money")
return true
end
function shareAllMoney()
local traders, total = {}, 0
for i = 1,4 do
local c = party.party:getChampionByOrdinal(i)
if c and c:getEnabled() then
total = total + money[i]
money[i] = 0
traders[#traders+1] = c
end
end
if total>0 then playSound("money") end
while #traders>1 do
local share = math.floor(total/#traders)
money[traders[#traders]:getOrdinal()] = share
traders[#traders] = nil
total = total-share
end
money[traders[1]:getOrdinal()] = total
end
function getAllMoney(champion)
local total = 0
for i = 1,4 do
local c = party.party:getChampionByOrdinal(i)
if c and c:getEnabled() then
total = total + money[i]
money[i] = 0
end
end
money[champion:getOrdinal()] = total
if total>0 then playSound("money") end
end
-- water bar functions
waterLevels = {700, 700, 700, 700}
function getWater(champion) return waterLevels[champion:getOrdinal()] end
function consumeWater(amount, champion) modifyWater(-amount, champion) end
function modifyWater(amount, champion) setWater(getWater(champion)+amount, champion) end
function setWater(water, champion)
water = water<0 and 0 or water>1000 and 1000 or water
waterLevels[champion:getOrdinal()] = water
if water<250 then
if not champion:hasCondition("dehydration") then champion:setCondition("dehydration") end
else
if champion:hasCondition("dehydration") then champion:removeCondition("dehydration") end
end
--hudPrint(champion:getName().." food="..champion:getFood().." water="..water)
end
-- empty flask functions
function addFlask(potion, champion)
local empty, pos, containers = 0, 0, {}
for slot = ItemSlot.BackpackFirst,ItemSlot.BackpackLast do
local item = champion:getItem(slot)
if item then
if item.go.name == "flask" then item:setStackSize(1+item:getStackSize()) return end
if item.go.containeritem then containers[#containers+1] = {item.go.containeritem, slot, 0, 0} end
if pos<1 and item.go.id == potion.id then pos = slot end
else
if empty<1 then empty = slot end
end
end
for i = 1,#containers do
for slot = 1,containers[i][1]:getCapacity() do
local item = containers[i][1]:getItem(slot)
if item then
if item.go.name == "flask" then item:setStackSize(1+item:getStackSize()) return end
if containers[i][3]<1 and item.go.id == potion.id then containers[i][3] = slot end
else
if containers[i][4]<1 then containers[i][4] = slot end
end
end
end
if potion.item:getStackSize()<2 then
if pos>0 then delayedCall("champions", 0, "delayedFlask", champion:getOrdinal(), pos) return end
for i = 1,#containers do
if containers[i][3]>0 then
delayedCall("champions", 0, "delayedFlask", champion:getOrdinal(), containers[i][2], containers[i][3]) return
end
end
end
if empty>0 then champion:insertItem(empty, spawn("flask").item) return end
for i = 1,#containers do
if containers[i][3]>0 then containers[i][1]:insertItem(containers[i][3], spawn("flask").item) return end
end
if getMouseItem() then
if potion.item:getStackSize()<2 then
delayedCall("champions", 0, "delayedFlask")
else
spawn("flask")
end
else
setMouseItem(spawn("flask").item)
end
end
function delayedFlask(ordinal, slot, slotInSlot)
if slot then
if slotInSlot then
party.party:getChampionByOrdinal(ordinal):getItem(slot).go.containeritem:insertItem(slotInSlot, spawn("flask").item)
else
party.party:getChampionByOrdinal(ordinal):insertItem(slot, spawn("flask").item)
end
else
setMouseItem(spawn("flask").item)
end
end
-- enabled champions
function getEnabledChampions()
local tab = {}
if taverns.script.current then
for i = 1,4 do
if taverns.script.enabled[i] then tab[#tab+1] = party.party:getChampionByOrdinal(i) end
end
elseif shops.script.current then
for i = 1,4 do
if shops.script.enabled[i] then tab[#tab+1] = party.party:getChampionByOrdinal(i) end
end
else
for i = 1,4 do
local champ = party.party:getChampionByOrdinal(i)
if champ:getEnabled() then tab[#tab+1] = champ end
end
end
return tab
end
-- update
championUpdateIndex = 0
timeMoney = 50
timeXP = 50
timeShop = 50
timeLearn = 5
function updateChampions(dt)
--print("------- update -------")
shops.script.setLastSell()
shops.script.setLastBuy()
if championUpdateIndex >= #champions then
shops.script.updateShops()
championUpdateIndex = 0
return
else
championUpdateIndex = championUpdateIndex < 0 and 1 or championUpdateIndex + 1
end
local c = champions[championUpdateIndex]
if not c then return end
if not c.plan then c.plan = plans[c.class] end
if type(c.items) == "table" then
local items = self.go:spawn("inventory")
for i = 1,ItemSlot.MaxSlots do
if c.items[i] then
local item = createItem(c.items[i])
if item then items.store:insertItem(i, item) end
end
end
c.items = items.id
end
--print(c.name.." is champion "..c.index.."/"..#champions)
if c.busy then
local t = Time.currentTime()
if c.busy > t then
--print(c.name.." is busy")
return
end
--print(c.name.." comes back from "..((c.moneyGoal or c.xpGoal) and "a quest!" or c.shopping and "shopping" or "learning skills"))
if c.moneyGoal then
c.money = c.money + (timeMoney + t-c.busy)/timeMoney*(0.5+math.random())*c.level*1000
for i = 1,spells_functions.script.quantum(7*math.random()*c.level/(20+c.level)) do market.script.loot(c) end
end
if c.xpGoal then
c.experience = c.xpGoal
local lvl = level(c.experience)
local up = lvl-c.level
if up > 0 then
c.skillPoints = c.skillPoints + up
c.level = lvl
for _,v in ipairs(c.traits) do
if v == "mutation" then
for i = 1,up do
local stat = stats[math.random(#stats)]
c.baseStats[stat] = c.baseStats[stat]+1
c.currentStats[stat] = c.currentStats[stat]+1
if stat == "strength" then c.maxLoad = c.maxLoad and c.maxLoad + 3 or c.currentStats[stat] * 3
elseif stat == "dexterity" then c.evasion = (c.evasion or 0) + 5
elseif stat == "vitality" then c.maxHealth = c.maxHealth + 5
elseif stat == "willpower" then c.maxEnergy = c.maxEnergy + 5
end
end
break
end
end
for i = 1,up do levelUp(c) end
learn(c)
end
market.script.loot(c)
end
if math.random() < (c.wandering or 0) then c.tavern = taverns.script.taverns[math.random(#taverns.script.taverns)] end
c.busy = nil
--print(c.name.." is back in "..c.tavern)
else
--print(c.name.." is available")
c.moneyGoal = nil
c.xpGoal = nil
c.shopping = nil
c.learning = nil
dt = dt * (#champions+1)
local resting = party.party:isResting()
local champs = getEnabledChampions()
if not c.tavern then c.tavern = taverns.script.taverns[math.random(#taverns.script.taverns)] end
local tavern = findEntity(c.tavern).script.tavern
--print(c.name.." is in tavern "..tavern.name)
-- eat/drink
local consume = dt * (resting and 1 or 0.001)
c.food = c.food - consume
c.water = c.water - consume
if c.water < 250 or c.food < 0 then
if c.money < tavern.menuCost then
c.moneyGoal = true
else
c.money = c.money - tavern.menuCost
c.food = math.min(1000, c.food + 250)
c.water = math.min(1000, c.water + 250)
end
end
-- heal/sleep
local gain = dt/8/3600 * (resting and 1000 or 1)
c.health = math.min(c.maxHealth, c.health + c.maxHealth*gain)
c.energy = math.min(c.maxEnergy, c.energy + c.maxEnergy*gain)
-- money/trade
local shop = findEntity(shops.script.shops[math.random(#shops.script.shops)])
shop = shop and shop.script.shop
if shop and GameMode.getTimeOfDay()<1 then
--print(c.name.." looks for goods in shop "..shop.name)
local inv = findEntity(c.items)
local rope,craftpotion = cleanInventory(c, inv, shop)
local list = {}
for _,item in ipairs(shop.items) do if item[2] > 0 then list[#list+1] = item end end
local item = list[math.random(#list)]
if item then
local o = shops.script.getObject(item)
if o.spellscrollitem then
local spell = spells_functions.script.defByName[o.spellscrollitem:getSpell()]
if spell and canUse(c, spell.requirements) and not hasSpell(c, spell.name) then
if buy(c, inv, nil, nil, o, item, shop) then c.spells[#c.spells+1] = spell.name end
end
elseif o.craftpotioncustom then
if not craftpotion and ((c.skillLevels["alchemy"] or 0) > 0 or hasTrait(c, "alchemist")) then
buy(c, inv, nil, nil, o, item, shop)
end
elseif o.name == "flask" then
if (c.skillLevels["alchemy"] or 0) > 0 or hasTrait(c, "alchemist") then buy(c, inv, nil, nil, o, item, shop, 7) end
elseif o.item:hasTrait("herb") then
if (c.skillLevels["alchemy"] or 0) > 0 or hasTrait(c, "alchemist") then buy(c, inv, nil, nil, o, item, shop, 30) end
elseif o.item:hasTrait("potion") then
if o.name == "potion_strength" then statShopping(c, "strength" , o, item, inv, shop)
elseif o.name == "potion_dexterity" then statShopping(c, "dexterity", o, item, inv, shop)
elseif o.name == "potion_vitality" then statShopping(c, "vitality" , o, item, inv, shop)
elseif o.name == "potion_willpower" then statShopping(c, "willpower", o, item, inv, shop)
else buy(c, inv, nil, nil, o, item, shop, 3) end
elseif o.ropetool then
if not rope then buy(c, inv, nil, nil, o, item, shop) end
elseif o.name == "lock_pick" then
buy(c, inv, nil, nil, o, item, shop, 7)
elseif o.usableitem then
local f,w = food_functions.script.getNutritionValue(o.name),food_functions.script.getHydrationValue(o.name)
if (f>0 or w>0) and (c.food+f<=1000 and c.water+w<=1000) and buy(c, inv, 0, nil, o, item, shop) then
c.food = c.food+f
c.water = c.water+w
if o.name == "water_flask" then sell(c, spawn("flask"), shop) end
if o.map then o:destroy() end
end
elseif o.containeritem then
local empty,slot,current,wslot,worst = getInventoryEmptySpace(c, inv)
if empty < 9 and slot then
if current then inv.store:removeItemFromSlot(slot) end
if buy(c, inv, slot, nil, o, item, shop) then if current then o.containeritem:addItem(current.item) end
elseif current then inv.store:insertItem(slot, current.item) end
elseif worst and isBetterContainer(o, worst) then
inv.store:removeItemFromSlot(wslot)
if buy(c, inv, wslot, nil, o, item, shop) then
for s = 1,worst.containeritem:getCapacity() do
local item = worst.containeritem:getItem(s)
if item then worst.containeritem:removeItemFromSlot(s) o.containeritem:insertItem(s, item) end
end
sell(c, worst, shop)
else inv.store:insertItem(wslot, worst.item) end
end
else
local slot = market.script.getSlot(o)
if slot then
--print(item[1].." goes in slot "..(slot or "nil"))
local current = inv.store:getItem(slot)
current = current and current.go
if isUpgradeTo(c, o, current) then buy(c, inv, slot, current, o, item, shop) end
elseif canUseItem(c, o) then
local h1,h2 = inv.store:getItem(ItemSlot.Weapon),inv.store:getItem(ItemSlot.OffHand)
h1,h2 = h1 and h1.go,h2 and h2.go
local l1,l2 = legalHands(c, o, h2),legalHands(c, h1, o)
if h1 and h2 then
if l1 and l2 then
local v1,v2 = market.script.getUseValue(c, h1),market.script.getUseValue(c, h2)
local current,s
if v1<v2 then current,s = h1,ItemSlot.Weapon else current,s = h2,ItemSlot.OffHand end
if isUpgradeTo(c, o, current) then buy(c, inv, s, current, o, item, shop, 40) end
elseif l1 then
if isUpgradeTo(c, o, h1) then buy(c, inv, ItemSlot.Weapon, h1, o, item, shop, 40) end
elseif l2 then
if isUpgradeTo(c, o, h2) then buy(c, inv, ItemSlot.OffHand, h2, o, item, shop, 40) end
elseif legalHands(c, o) and isUpgradeTo(c, o, h1) and isUpgradeTo(c, o, h2) then
local o1,o2,s1,s2
if h1.name == o.name then o1,o2,s1,s2 = h1,h2,ItemSlot.Weapon,ItemSlot.OffHand
elseif h2.name == o.name then o1,o2,s1,s2 = h2,h1,ItemSlot.OffHand,ItemSlot.Weapon
elseif math.random() < 0.5 then o1,o2,s1,s2 = h1,h2,ItemSlot.Weapon,ItemSlot.OffHand
else o1,o2,s1,s2 = h2,h1,ItemSlot.OffHand,ItemSlot.Weapon
end
if buy(c, inv, s1, o1, o, item, shop, 40) then sell(c, o2, shop) inv.store:removeItemFromSlot(s2) end
end
elseif h1 then
if l2 then
if isUpgradeTo(c, o, h2) then buy(c, inv, ItemSlot.OffHand, h2, o, item, shop, 40) end
elseif l1 then
if isUpgradeTo(c, o, h1) then buy(c, inv, ItemSlot.Weapon, h1, o, item, shop, 40) end
end
elseif h2 then
if l1 then
if isUpgradeTo(c, o, h1) then buy(c, inv, ItemSlot.Weapon, h1, o, item, shop, 40) end
elseif l2 then
if isUpgradeTo(c, o, h2) then buy(c, inv, ItemSlot.OffHand, h2, o, item, shop, 40) end
end
elseif l1 then
buy(c, inv, math.random() < 0.5 and ItemSlot.Weapon or ItemSlot.OffHand, nil, o, item, shop, 40)
end
end
end
end
end
if not c.moneyGoal then
if c.money < c.level/2 then
c.moneyGoal = true
else
local moneyGoal = -c.money
for _,champ in ipairs(champs) do moneyGoal = moneyGoal + getMoney(champ)/#champs end
if moneyGoal > 0 then c.moneyGoal = true end
end
end
-- xp
local flvl = floatLevel(c.experience)
local lvlGoal = (c.deltaLevel or 0)-flvl
for _,champ in ipairs(champs) do lvlGoal = lvlGoal + (floatLevel(champ:getExp())-getDeltaLevel(champ))/#champs end
if lvlGoal > math.random() then c.xpGoal = xp(flvl+lvlGoal) end
learn(c)
local duration = (c.moneyGoal and timeMoney or 0) + (c.xpGoal and timeXP or 0) + (c.shopping and timeShop or 0) + timeLearn*(c.learning or 0)
if duration > 0 then c.busy = Time.currentTime() + duration end
--print(c.name.." end of turn")
end
end
-- shopping parts cut...
-- potion craft ui
function craftPotion(mortar, champion)
local mord = "mortar"..champion:getOrdinal()
local slot
for s = 1,ItemSlot.MaxSlots do if champion:getItem(s) == mortar.item then slot = s break end end
if not slot then hudPrint("Cannot be used inside a container.") return end
if get(mord) == slot then set(mord, nil) else set(mord, slot) end
--print("craft potion ok for slot "..slot)
end
-- champions definitions
skillPlan = {
alchemy = {
{"alchemy",5},
},
critical = {
{"critical",5},
},
defense = {
{"athletics",5},
{"armors",2},
{"dodge",5},
{"armors",5},
},
dualWield = {
{"light_weapons",5},
{"critical",5},
{"accuracy",5},
{"dodge",5},
},
firearm = {
{"firearms",5},
{"critical",5},
{"accuracy",5},
{"dodge",5},
},
frontHeavy = {
{"heavy_weapons",5},
{"armors",5},
{"accuracy",5},
},
frontMage = {
{"concentration",5},
{"armors",5},
},
heal = {
{"concentration",1},
{"water_magic",1},
{"earth_magic",1},
{"water_magic",2},
{"earth_magic",2},
{"water_magic",3},
{"earth_magic",3},
{"concentration",2},
{"water_magic",4},
{"earth_magic",4},
{"water_magic",5},
{"earth_magic",5},
{"concentration",3},
{"air_magic",1},
{"concentration",4},
{"air_magic",2},
{"concentration",5},
{"air_magic",5},
{"fire_magic",5},
},
magic = {
{"concentration",1},
{"fire_magic",1},
{"air_magic",1},
{"water_magic",1},
{"earth_magic",1},
{"concentration",2},
{"air_magic",2},
{"water_magic",2},
{"earth_magic",2},
{"fire_magic",2},
{"concentration",3},
{"water_magic",3},
{"earth_magic",3},
{"fire_magic",3},
{"air_magic",3},
{"concentration",4},
{"earth_magic",4},
{"fire_magic",4},
{"air_magic",4},
{"water_magic",4},
{"concentration",5},
{"fire_magic",5},
{"air_magic",5},
{"water_magic",5},
{"earth_magic",5},
},
magicFAC = {
{"fire_magic",1},
{"air_magic",1},
{"concentration",1},
{"air_magic",2},
{"fire_magic",2},
{"concentration",2},
{"fire_magic",3},
{"air_magic",3},
{"concentration",3},
{"air_magic",4},
{"fire_magic",4},
{"concentration",4},
{"fire_magic",5},
{"air_magic",5},
{"concentration",5},
},
magicFWC = {
{"fire_magic",1},
{"water_magic",1},
{"concentration",1},
{"water_magic",2},
{"fire_magic",2},
{"concentration",2},
{"fire_magic",3},
{"water_magic",3},
{"concentration",3},
{"water_magic",4},
{"fire_magic",4},
{"concentration",4},
{"fire_magic",5},
{"water_magic",5},
{"concentration",5},
},
missile = {
{"missile_weapons",5},
{"critical",5},
{"accuracy",5},
{"dodge",5},
},
reach = {
{"accuracy",2},
},
throw = {
{"throwing",5},
{"accuracy",5},
{"critical",5},
{"dodge",5},
},
}
plans = {
-- class standard
fighter = {
stats = {strength = 1, dexterity = 0.75, vitality = 0.75, willpower = 0.5},
skills = {skillPlan.frontHeavy, skillPlan.critical, skillPlan.defense, skillPlan.throw},
},
barbarian = {
stats = {strength = 1, dexterity = 0.75, vitality = 0.5, willpower = 0.25},
skills = {skillPlan.frontHeavy, skillPlan.throw, skillPlan.defense},
},
knight = {
stats = {strength = 1, dexterity = 0.75, vitality = 0.75, willpower = 0.5},
skills = {skillPlan.frontHeavy, skillPlan.defense, skillPlan.heal},
},
rogue = {
stats = {strength = 0.75, dexterity = 1, vitality = 0.75, willpower = 0.5},
skills = {skillPlan.reach, skillPlan.dualWield, skillPlan.missile, skillPlan.defense},
},
battle_mage = {
stats = {strength = 0.5, dexterity = 0.5, vitality = 0.75, willpower = 1},
skills = {skillPlan.frontMage, skillPlan.magic, skillPlan.defense, skillPlan.reach},
},
wizard = {
stats = {strength = 0.25, dexterity = 0.25, vitality = 0.75, willpower = 1},
skills = {skillPlan.magic, skillPlan.defense, skillPlan.reach},
},
alchemist = {
stats = {strength = 0.75, dexterity = 1, vitality = 0.75, willpower = 0.75},
skills = {skillPlan.alchemy, skillPlan.firearm, skillPlan.defense},
},
farmer = {
stats = {strength = 0.25, dexterity = 0.25, vitality = 0.75, willpower = 1},
skills = {skillPlan.magic, skillPlan.defense, skillPlan.reach},
},
-- other templates
archer = {
stats = {strength = 0.25, dexterity = 1, vitality = 0.75, willpower = 0.5},
skills = {skillPlan.missile, skillPlan.defense},
},
healer = {
stats = {strength = 0.25, dexterity = 0.25, vitality = 0.75, willpower = 1},
skills = {skillPlan.heal, skillPlan.defense, skillPlan.reach},
},
ninja = {
stats = {strength = 1, dexterity = 0.75, vitality = 0.75, willpower = 0.5},
skills = {skillPlan.throw, skillPlan.defense},
},
shooter = {
stats = {strength = 1, dexterity = 0.75, vitality = 0.75, willpower = 0.5},
skills = {skillPlan.firearm, skillPlan.defense},
},
}
function randomOrder(tab)
local result = {}
for i = 1,#tab do table.insert(result, math.random(i), tab[i]) end
return result
end
champions = randomOrder(champions)
for i = 1,#champions do
champions[i].index = i
champions[i].food = math.random(1000)
champions[i].water = math.random(1000)
end