1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-22 22:13:35 +02:00
vcmi/scripts/lib/erm/MA.lua
AlexVinS ecaa9f5d0b Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2021-02-14 19:05:43 +03:00

234 lines
5.7 KiB
Lua

local logError = logError
local bit = bit
local ReceiverBase = require("core:erm.ReceiverBase")
local Metatype = require ("core:Metatype")
local EntitiesChanged = require("netpacks.EntitiesChanged")
local Bonus = require("Bonus")
local BonusBearer = require("BonusBearer")
local BonusList = require("BonusList")
local RES = {[0] = "wood", [1] = "mercury", [2] = "ore", [3] = "sulfur", [4] = "crystal", [5] = "gems", [6] = "gold", [7] = "mithril"}
local SERVICES = SERVICES
local creatures = SERVICES:creatures()
local SERVER = SERVER
local getCreatureByIndex = creatures.getByIndex
local function creatureByIndex(index)
return getCreatureByIndex(creatures, index)
end
local function sendChanges(creatureIndex, data)
local pack = EntitiesChanged.new()
pack:update(Metatype.CREATURE, creatureIndex, data)
SERVER:commitPackage(pack)
end
local MA = ReceiverBase:new()
function MA:new(ERM)
return ReceiverBase.new(self,{ERM = ERM})
end
local function checkCreatureIndex(creatureIndex)
assert(creatureIndex ~= nil, "!!MA requires creature identifier")
if type(creatureIndex) == "string" then
error("Identifier resolving is not implemented")
end
return creatureIndex
end
local function createModifier(scope, jsonKey, getterKey)
local f = function (self, x, creatureIndex, p1)
local creatureIndex = checkCreatureIndex(creatureIndex)
if p1 == nil then
local creature = creatureByIndex(creatureIndex)
return nil, creature[getterKey](creature)
else
local packData = {config = {}}
local config = packData.config
for _, v in ipairs(scope) do
config[v] = {}
config = config[v]
end
config[jsonKey] = p1
sendChanges(creatureIndex, packData)
return
end
end
return f
end
MA.A = createModifier({}, "attack", "getBaseAttack")
MA.B = createModifier({}, "spellPoints" ,"getBaseSpellPoints")
MA.D = createModifier({}, "defense" ,"getBaseDefense")
MA.E = createModifier({"damage"}, "max", "getBaseDamageMax")
MA.F = createModifier({}, "fightValue" ,"getFightValue")
MA.G = createModifier({}, "growth" ,"getGrowth")
MA.H = createModifier({"advMapAmount"}, "max" ,"getAdvMapAmountMax")
MA.I = createModifier({}, "aiValue" ,"getAIValue")
MA.L = createModifier({}, "level" , "getLevel")
MA.M = createModifier({"damage"}, "min", "getBaseDamageMin")
MA.N = createModifier({}, "shots" , "getBaseShots")
MA.O = createModifier({}, "faction" ,"getFactionIndex")
MA.P = createModifier({}, "hitPoints" ,"getBaseHitPoints")
MA.R = createModifier({}, "horde" , "getHorde")
MA.S = createModifier({}, "speed" , "getBaseSpeed")
MA.V = createModifier({"advMapAmount"}, "min","getAdvMapAmountMin")
function MA:C(x, creatureIndex, resIndex, cost)
local creatureIndex = checkCreatureIndex(creatureIndex)
if cost == nil then
local creature = creatureByIndex(creatureIndex)
return nil, nil, creature:getCost(resIndex)
else
local packData = {config = {cost = {[RES[resIndex]] = cost}}}
sendChanges(creatureIndex, packData)
end
end
function MA:U(x, creatureIndex, upgradeIndex)
-- -2 - no upgrade
-- -1 - usual upgrade
logError("!!MA:U is not implemented")
end
local FLAG_NAMES =
{
--[1] = "doubleWide", --0
[2] = "FLYING", --1
[4] = "SHOOTER", --2
[8] = "TWO_HEX_ATTACK_BREATH", --3
-- [16] = "alive", --4
[32] = "CATAPULT", --5
[64] = "SIEGE_WEAPON", --6
[128] = "KING1", --7
[256] = "KING2", --8
[512] = "KING3", --9
[1024] = "MIND_IMMUNITY", --10
--[2048] = "laser shot", --11
[4096] = "NO_MELEE_PENALTY", --12
-- [8192] - unused --13
[16384] = "FIRE_IMMUNITY", --14
[32768] = "ADDITIONAL_ATTACK", -- val=1 --15
[65536] = "NO_RETALIATION", --16
[131072] = "NO_MORALE", --17
[262144] = "UNDEAD", --18
[524288] = "ATTACKS_ALL_ADJACENT", --19
-- [1048576] - AOE spell-like attack --20
-- [2097152] - war machine? --21
-- [4194304] = "summoned", --22
-- [8388608] = "cloned", --23
}
local FLAGS = {}
for k, v in pairs(FLAG_NAMES) do
local bonusType = Bonus[v]
assert(bonusType ~= nil, "Invalid Bonus type: "..v)
FLAGS[k] = bonusType
end
local FLAGS_REV = {}
for mask, bonusType in pairs(FLAGS) do
FLAGS_REV[bonusType] = mask
end
function MA:X(x, creatureIndex, flagsMask)
local creatureIndex = checkCreatureIndex(creatureIndex)
local creature = creatureByIndex(creatureIndex)
local creatureBonuses = creature:accessBonuses()
local all = creatureBonuses:getBonuses()
local currentMask = 0
local toRemove = {}
do
local idx = 1
local bonus = all[idx]
while bonus do
local bonusType = bonus:getType()
local mask = FLAGS_REV[bonusType]
if mask ~= nil then
if flagsMask ~= nil then
if bit.band(mask, flagsMask) == 0 then
table.insert(toRemove, bonus:toJsonNode())
end
end
currentMask = bit.bor(currentMask, mask)
end
idx = idx + 1
bonus = all[idx]
end
end
if flagsMask == nil then
local ret = currentMask
if creature:isDoubleWide() then
ret = bit.bor(ret, 1)
end
return nil, ret
else
flagsMask = tonumber(flagsMask)
local hasChanges = false
local packData = {config = {}}
local reqDoubleWide = bit.band(flagsMask, 1) > 0
if reqDoubleWide ~= creature:isDoubleWide() then
packData.config.doubleWide, hasChanges = reqDoubleWide, true
end
local toAdd = {}
for mask, name in pairs(FLAG_NAMES) do
if (bit.band(currentMask, mask) == 0) and (bit.band(flagsMask, mask) ~= 0) then
local bonus =
{
duration = {[1] = "PERMANENT"},
source = "CREATURE_ABILITY",
type = name
}
--special case
if name == "ADDITIONAL_ATTACK" then
bonus.val = 1
end
table.insert(toAdd, bonus)
end
end
hasChanges = hasChanges or #toAdd > 0 or #toRemove > 0
if hasChanges then
packData.bonuses = {toAdd = toAdd, toRemove = toRemove}
sendChanges(creatureIndex, packData)
end
end
end
return MA