Files
vcmi/scripts/summon.lua
T
Ivan Savenko 94a586b172 Implemented several TODO items
- Dropped incomplete attempt to add initialize() function
- Removed effectively duplicated getSpellByKey() method from API
- Fixed several Sonar warnings
2026-06-03 23:13:17 +03:00

152 lines
4.3 KiB
Lua

local Base = require("spellEffect")
local Script = setmetatable({}, {__index = Base})
Script.__index = Script
function Script:summonedEffectValue(mechanics)
local effectPower = mechanics:getEffectPower()
local rawEffectPower = mechanics:calculateRawEffectValue(0, effectPower)
local finalEffectPower = mechanics:applySpecificSpellBonus(rawEffectPower)
return finalEffectPower
end
function Script:summonedCreatureHealth(mechanics)
local valueWithBonus = self:summonedEffectValue(mechanics)
local creature = LIBRARY:getCreatureByName(self.id)
if self.summonByHealth then
return valueWithBonus
else
return valueWithBonus * creature:getMaxHealth()
end
end
function Script:summonedCreatureAmount(mechanics)
local valueWithBonus = self:summonedEffectValue(mechanics)
local creature = LIBRARY:getCreatureByName(self.id)
if self.summonByHealth then
return math.floor(valueWithBonus / creature:getMaxHealth())
else
return valueWithBonus
end
end
--- Returns true if spell can be casted in general
--- if no valid targets exist, script needs to call `problem:add`
--- to explain the reason to the player
function Script:applicableGeneral(mechanics, problem)
local creature = LIBRARY:getCreatureByName(self.id)
if self:summonedCreatureAmount(mechanics) == 0 then
print("SpellEffectSummon: zero summoned creatures!")
problem:addGeneric(mechanics)
return false
end
-- check if there are summoned creatures of other type
if self.exclusive then
local elementals = mechanics:getBattle():getUnitsIf(function(unit)
return (unit:getOwner() == mechanics:getCasterColor())
and (unit:isSummoned())
and (not unit:isClone())
and (unit:getCreature():getJsonKey() ~= creature:getJsonKey())
end)
local elemental = elementals[1]
print("SpellEffectSummon - summoning:", creature:getJsonKey(), " elemental is ", elemental)
if elemental ~= nil then
local hero = mechanics:getHeroCaster()
local himHer = "core.genrltxt.539"
if hero ~= nil and hero:isFemale() then
himHer = "core.genrltxt.540"
end
if hero ~= nil then
problem:addCustom({
append = { "core.genrltxt.538" },
replace = {
hero:getNameTextID(),
elemental:getCreature():getNamePluralTextID(),
himHer
}
})
else
problem:addCustom({
append = { "core.genrltxt.538" }
})
end
print("SpellEffectSummon - summoning:", creature:getJsonKey(), " already summoned: ", elemental:getCreature():getJsonKey())
return false
end
end
return true
end
--- Actually casts the spells and applies all changes caused by spell
--- use `server` parameter to apply changes on specified target(s)
function Script:apply(mechanics, server, target)
local creature = LIBRARY:getCreatureByName(self.id)
for _, dest in ipairs(target) do
if dest.unit ~= nil then
server:healUnit(
mechanics:getBattleID(),
dest.unit,
self:summonedCreatureHealth(mechanics),
ENUM.HealLevel.overheal,
self.permanent and ENUM.HealPower.permanent or ENUM.HealPower.oneBattle
)
else
print("SpellEffectSummon. Hex: ", dest.hex)
assert(dest.hex ~= nil)
server:createUnit(
mechanics:getBattleID(),
mechanics:getBattle():getNextUnitId(),
{
count = self:summonedCreatureAmount(mechanics),
type = creature:getJsonKey(),
side = mechanics:getCasterSide(),
position = dest.hex:toInteger(),
summoned = not self.permanent
}
)
end
end
end
--- converts specified range into actual list of affected targets
--- for example, area damage spells should locate all units on affected hexes
--- and return list of affected units
function Script:transformTarget(mechanics, aimPoint, spellTarget)
local creature = LIBRARY:getCreatureByName(self.id)
local sameSummoned = mechanics:getBattle():getUnitsIf(function(unit)
return (unit:getOwner() == mechanics:getCasterColor())
and (unit:isSummoned())
and (not unit:isClone())
and (unit:getCreature():getJsonKey() == creature:getJsonKey())
and (unit:isAlive())
end)[1]
if sameSummoned == nil or not self.summonSameUnit then
local hex = mechanics:getBattle():getAvailableHex(creature, mechanics:getCasterSide())
if not hex:isValid() then
return {} -- no free space. FIXME: should be in isApplicable
else
return {
{
hex = hex,
unit = nil
}
}
end
else
return {
{
hex = sameSummoned:getPosition(),
unit = sameSummoned
}
}
end
end
return Script