1
0
mirror of https://github.com/vcmi/vcmi.git synced 2026-05-22 09:55:17 +02:00
Files
vcmi/scripts/SpellEffectSummon.lua
T
2026-04-30 18:00:50 +03:00

179 lines
5.6 KiB
Lua

meta = {
type = spellEffect,
spellEffectSchema = {
required = { "id" },
properties = {
type = {},
indirect = {},
optional = {},
id = { type = "string" }, -- type of creature that can be summoned by the spell
permanent = { type = "boolean" }, -- if true, summoned units persists after combat
exclusive = { type = "boolean" }, -- if true, spell can only be used if there are no summoned units of another typee
summonByHealth = { type = "boolean" }, -- if true, spell effect power represents summoned health, if not - summoned amount
summonSameUnit = { type = "boolean" } -- if true, spell will increase stack size of existing summon, if available, instead of summoning a separate stack
},
additionalProperties = false
}
}
local function summonedEffectValue(parameters, mechanics)
local effectPower = mechanics:getEffectPower()
local rawEffectPower = mechanics:calculateRawEffectValue(0, effectPower)
local finalEffectPower = mechanics:applySpecificSpellBonus(rawEffectPower)
return finalEffectPower
end
local function summonedCreatureHealth(parameters, mechanics)
local valueWithBonus = summonedEffectValue(parameters, mechanics)
local creature = LIBRARY:getCreatureByName(parameters.id)
if parameters.summonByHealth then
return valueWithBonus
else
return valueWithBonus * creature:getMaxHealth()
end
end
local function summonedCreatureAmount(parameters, mechanics)
local valueWithBonus = summonedEffectValue(parameters, mechanics)
local creature = LIBRARY:getCreatureByName(parameters.id)
if parameters.summonByHealth then
return math.floor(valueWithBonus / creature:getMaxHealth())
else
return valueWithBonus
end
end
-- TODO
-- initializes parameters of the script using spell effect json
-- returns converted parameters that contain resolved identifiers
initialize = function(parameters)
parameters.creature = LIBRARY:getCreatureByName(parameters.id)
return parameters
end
--- Returns true if specified target can be affected by the spell
--- if target can not be affected, script needs to call `problem:add`
--- to explain the reason to the player
applicableTarget = function(parameters, mechanics, problem, target)
return true
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
applicable = function(parameters, mechanics, problem)
local creature = LIBRARY:getCreatureByName(parameters.id)
if summonedCreatureAmount(parameters, mechanics) == 0 then
print("SpellEffectSummon: zero summoned creatures!")
return problem:addGeneric(mechanics:getCasterNameTextID())
end
-- check if there are summoned creatures of other type
if parameters.exclusive then
local elemental = mechanics:getBattle():getAnyUnitIf(function(unit)
return (unit:getOwner() == mechanics:getCasterColor())
and (unit:isSummoned())
and (not unit:isClone())
and (unit:getCreature():getJsonKey() ~= creature:getJsonKey())
end)
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:add({
append = "core.genrltxt.538",
replace = {
hero:getNameTextID(),
elemental:getNamePluralTextID(),
himHer
}
})
else
problem:add({
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)
apply = function(parameters, mechanics, server, target)
local creature = LIBRARY:getCreatureByName(parameters.id)
for _, dest in ipairs(target) do
if dest.unit ~= nil then
server:healUnit(
mechanics:getBattleID(),
dest.unit,
summonedCreatureHealth(parameters, mechanics),
ENUM.HealLevel.overheal,
parameters.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 = summonedCreatureAmount(parameters, mechanics),
type = creature:getJsonKey(),
side = mechanics:getCasterSide(),
position = dest.hex:toInteger(),
summoned = not parameters.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
transformTarget = function(parameters, mechanics, aimPoint, spellTarget)
local creature = LIBRARY:getCreatureByName(parameters.id)
local sameSummoned = mechanics:getBattle():getAnyUnitIf(function(unit)
return (unit:getOwner() == mechanics:getCasterColor())
and (unit:isSummoned())
and (not unit:isClone())
and (unit:getCreature():getJsonKey() == creature:getJsonKey())
and (unit:isAlive())
end)
if sameSummoned == nil or not parameters.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