mirror of
https://github.com/vcmi/vcmi.git
synced 2024-11-26 08:41:13 +02:00
ecaa9f5d0b
* 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.
234 lines
5.7 KiB
Lua
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
|