测试
Effect = Class:extend()
Duel = {}
Helper = {}
Modifier = {}
function Effect:init(card, type, time, name)
-- ctx 可能为 Card Player Attack
local effect = GameEffect.Effect(type, time or 0)
self.effect = effect
if name ~= nil then
effect.effectName = name
end
if type == EffectType.Event then
-- 等待优化
effect.card = card;
game:AddEffect(effect)
else
card:AddEffect(effect)
end
end
function Effect:SetOperation(call)
if call == nil and self.effect.card ~= nil then
print("========================ERROR EMPTY CALL: " .. self.effect.card.cardId .. "=========================")
end
local effect = self.effect
local operation = function(...)
local status, err = pcall(call, ...)
if err then
print(err)
end
end
self.co = coroutine.create(operation);
effect:SetOperation(function(...)
if coroutine.status(self.co) == 'dead' then
self.co = coroutine.create(operation)
end
coroutine.resume(self.co, ...)
end)
end
function Effect:SetDestroy(call)
if call == nil and self.effect.card ~= nil then
print("========================ERROR EMPTY CALL: " .. self.effect.card.cardId .. "=========================")
end
local effect = self.effect
local operation = function(...)
local status, err = pcall(call, ...)
if err then
print(err)
end
end
self.de_co = coroutine.create(operation);
effect:SetDestroy(function(...)
if coroutine.status(self.de_co) == 'dead' then
self.de_co = coroutine.create(operation)
end
coroutine.resume(self.de_co, ...)
end)
end
function Effect:SetCondition(call)
local effect = self.effect
effect:SetCondition(call)
end
function Effect:SetEventPlayer(eventPlayer)
local effect = self.effect
effect.EventPlayer = eventPlayer
end
function Effect:SetOnce()
local effect = self.effect
effect.IsOnce = true
end
function Helper.CreateCharaCard(charaId)
local card = PlayObject.Card(null)
card.id = -charaId
return card
end
function Helper.RequestThroughout(player, card)
card.IsThroughout = false
if player.NormalActionUsed or player.ThroughoutActionUsed then
return false
end
local used = game:FilterLogs(GameLogType.PlayCard, player)
if used >1 then
return false
end
local throughout = Duel.ShowDialog(player, "是否要使用全力化?")
if throughout then
card.IsThroughout = true
player.ThroughoutActionUsed = true
end
return throughout
end
function Helper.AddExtendAction(player, actionName, call, condition)
local operation = function(...)
local status, err = pcall(call, ...)
if err then
print(err)
end
end
local co = coroutine.create(operation);
player:AddExtendAction(actionName, function(...)
if coroutine.status(co) == 'dead' then
co = coroutine.create(operation)
end
coroutine.resume(co, ...)
end, condition)
end
function Helper.RemoveListener(card, effectName)
if card ~=nil then
game:RemoveEffect(card.id.."#"..effectName)
else
game:RemoveEffect(effectName)
end
end
function Helper.Listen(effectName, card, event, eventPlayer, operation, condition)
local e
if card ~=nil then
e = Effect(card, EffectType.Event, event, card.id.."#"..effectName)
else
e = Effect(card, EffectType.Event, event, effectName)
end
e:SetEventPlayer(eventPlayer)
e:SetOperation(operation)
if condition ~=nil then
e:SetCondition(condition)
end
return e
end
function Helper.ListenOnce(effectName, card, event, eventPlayer, operation, condition)
local e = Helper.Listen(effectName, card, event, eventPlayer, operation, condition)
e:SetOnce()
return e
end
function Helper.RemoveModifiersNextAttack(card, ctx, modifiers, condition)
local function clear(effect)
Helper.RemoveListener(effect.card, "helper_e1")
Helper.RemoveListener(effect.card, "helper_e2")
for key, eventName in pairs(modifiers) do
ctx:RemoveModifier(effect.card, eventName)
end
effect:Complete()
end
Helper.ListenOnce("helper_e1", card, GameEventCode.END_TURN, -1, function(effect)
clear(effect)
end)
Helper.Listen("helper_e2", card, GameEventCode.ATTACK, card.user.id, function(effect, payload)
local attack = payload.attack
if condition == nil or condition(attack) then
clear(effect)
else
effect:Complete()
end
end)
end
function Modifier.MaxAura(card, value, op, condition)
local m = GameEffect.MaxAuraModifier(value, op, condition);
m.source = card;
return m;
end
function Modifier.CardSubType(card, type, condition)
local m = GameEffect.CardSubTypeModifier(type, condition);
m.source = card;
return m;
end
function Modifier.RemoveCardFlag(card, flag, condition)
local m = GameEffect.RemoveCardFlagModifier(flag, condition);
m.source = card;
return m;
end
function Modifier.RemoveAttackFlag(card, flag, condition)
local m = GameEffect.RemoveAttackFlagModifier(flag, condition);
m.source = card;
return m;
end
-- 攻击Buff
function Modifier.AttackDamageReplace(card, aura, life, condition)
local m = GameEffect.AttackDamageReplace(aura, life, condition)
m.source = card;
return m;
end
function Modifier.AttackDamageExchange(card, condition)
local m = GameEffect.AttackDamageExchange(condition);
m.source = card;
return m;
end
function Modifier.AttackDamageMultiple(card, aura, life, condition)
local m = GameEffect.AttackDamageMultiple(aura, life, condition);
m.source = card;
return m;
end
function Modifier.AttackDamageDivide(card, aura, life, type, condition)
local m = GameEffect.AttackDamageDivide(aura, life, type, condition);
m.source = card;
return m;
end
function Modifier.AttackDamagePlus(card, aura, life, condition)
local m = GameEffect.AttackDamagePlus(aura, life, condition);
m.source = card;
return m;
end
-- 攻击Buff 结束
function Modifier.Cost(card, value, op, condition)
local m = GameEffect.CostModifier(value, op, condition)
m.source = card;
return m;
end
function Modifier.Charge(card, value, op, condition)
local m = GameEffect.ChargeModifier(value, op, condition)
m.source = card;
return m;
end
function Modifier.AttackRange(card, value, op, condition)
local m = GameEffect.AttackRangeModifier(value, op, condition)
m.source = card;
return m;
end
function Modifier.AttackFlag(card, flag, condition)
local m = GameEffect.AttackFlagModifier(flag, condition);
m.source = card;
return m;
end
function Modifier.CardFlag(card, flag, count, condition)
count = count or 0
local m = GameEffect.CardFlagModifier(flag, count, condition);
m.source = card;
return m;
end
function Modifier.HandLimit(card, value, condition)
local m = GameEffect.HandLimitModifier(value, condition);
m.source = card;
return m;
end
function Modifier.PlayerFlag(card, flag, condition)
local m = GameEffect.PlayerFlagModifier(flag, condition);
m.source = card;
return m;
end
function Modifier.AdditionalCardCost(cost, condition)
local m = GameEffect.AdditionalCardCostModifier(cost, condition);
m.source = card;
return m;
end
function Modifier.CardUseLimit(card, condition)
local m = GameEffect.CardUseLimitModifier(condition);
m.source = card;
return m;
end
function Modifier.NormalActionLimit(card, condition)
local m = GameEffect.NormalActionLimitModifier(condition);
m.source = card;
return m;
end
function Modifier.Distance(card, value, op, condition)
local m = GameEffect.DistanceModifier(value, op, condition);
m.source = card;
return m;
end
function Modifier.ExpertDistance(card, value, op, condition)
local m = GameEffect.ExpertDistanceModifier(value, op, condition);
m.source = card;
return m;
end
function Modifier.DrawCardLimit(card, value, op, condition)
local m = GameEffect.DrawCardLimitModifier(value, op, condition);
m.overlay = true;
m.source = card;
return m;
end
function Duel.CheckEvent(player, code, payload)
local co = coroutine.running()
System.CheckEvent(player, code, payload,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.DisableToken(tokenZone)
System.DisableToken(tokenZone)
end
function Duel.ShowMark(type, content)
local co = coroutine.running()
System.ShowMark(type, content, function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.Sync()
local co = coroutine.running()
System.Sync(function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.ShowDialog(player, content)
local co = coroutine.running()
System.ShowDialog(player, content,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.LoseGame(player)
local co = coroutine.running()
System.LoseGame(player,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.WinGame(player)
local co = coroutine.running()
System.WinGame(player,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.Irritation(player, value)
local co = coroutine.running()
System.Irritation(player, value,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.DealDamage(player, type, count)
local co = coroutine.running()
System.DealDamage(player, type, count,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.RemoveCard(card)
card.status = CardStatus.None
card.isProcessing = false
Duel.MoveCard(card.owner, card.zone, card.owner:GetCardZone(CardZoneType.Outside), {card}, 0)
end
function Duel.DrawCard(player, count)
local co = coroutine.running()
System.DrawCard(player, count,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.OpenHandCards(viewer, target)
local hand = target:GetCardZone(CardZoneType.Hand)
Duel.SelectCard(viewer, "查看手牌", hand.list, 0, 0)
end
function Duel.OpenCard(card)
local co = coroutine.running()
System.OpenCard(card,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.ActivateCard(player, card)
local co = coroutine.running()
System.ActivateCard(player, card,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.DestroyEnhanceCard(player, card)
local co = coroutine.running()
System.DestroyEnhanceCard(player, card,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.MoveTop(player, origin, target, cards)
Duel.MoveCard(player, origin, target, cards, Util.len(target.list))
end
function Duel.MoveBottom(player, origin, target, cards)
Duel.MoveCard(player, origin, target, cards, 0)
end
function Duel.MoveCards(player, target, cards, position)
if cards.Count ~= nil and cards.Length ~= nil then
for _, card in pairs(cards) do
Duel.MoveCard(player, card.zone, target, { card }, position);
end
else
for i = 0, Util.len(cards)-1, 1 do
Duel.MoveCard(player, cards[i].zone, target, { cards[i]}, position);
end
end
end
function Duel.MoveCard(player, origin, target, cards, position)
local move_cards = cards
if target.type == CardZoneType.Hand or target.type == CardZoneType.Deck then
move_cards = Util.find_cards(cards, function(c)
return not c:HasFlag(CardFlag.UNRETURN)
end)
end
local co = coroutine.running()
System.MoveCard(player, origin, target, move_cards, position,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.FoldCard(player, count)
local co = coroutine.running()
System.FoldCard(player, count,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.PlayCardEffect(player, card, type)
local co = coroutine.running()
System.PlayCardEffect(player, card, type,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.ClearCardEffect(player, card, type)
local co = coroutine.running()
System.ClearCardEffect(player, card, type,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.RequestChooseToken(player, zones, count, target)
local total = 0;
for _, zone in pairs(zones) do
total = total + zone:GetMovableCount()
end
if total == 0 then
return {}
end
local co = coroutine.running()
System.RequestChooseToken(player, zones, count, target,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.RequestCount(player, min, max, description)
local co = coroutine.running()
System.RequestCount(player, min, max, description,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.SelectCard(player, text, cards, min, max, condition)
local co = coroutine.running()
local list = cards
local mask = {}
if list.Count ~= nil then
list = Util.ListToArray(cards)
end
if condition ~= nil then
mask = Util.find_cardIds_revert(list, condition)
end
System.SelectCards(player, text, list, min, max, mask,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.RequestNextScene(player, choice)
local co = coroutine.running()
System.RequestNextScene(player, choice,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.SelectCardId(player, text, cards, min, max)
local co = coroutine.running()
System.SelectCardsId(player, text, cards, min, max,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.PlayCard(player, parentCard, card, skip_cost)
if not card:IsCardUsable() then
return
end
if card.type == CardType.Combine then
local hand = player:GetCardZone(CardZoneType.Hand)
local pool = Util.find_cards(hand.list, function(c)
return c.mainType == card.mainType and c.subType == card.subType
end)
local selection = Duel.SelectCard(player, "弃置1张同类型的牌", pool, 1, 1)
if Util.len(selection) > 0 then
local select = selection[0]
Duel.MoveCard(player, select.zone, select.owner:GetCardZone(CardZoneType.Discard), {select}, 0);
else
return;
end
end
local co = coroutine.running()
System.PlayCard(player, parentCard, card, skip_cost or false,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.DeclareAttack(player, attack)
local co = coroutine.running()
System.DeclareAttack(player, attack,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.ResetCard(card)
local co = coroutine.running()
System.ResetCard(card,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.ArrowEffectMovePoint(card, player, origin, target, count, force)
if force or card.owner ~= player or not player:HasFlag(PlayerFlag.DOUBLE_ARROW) then
local co = coroutine.running()
System.ArrowEffectMovePoint(card, player, origin, target, count,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
else
Duel.DoubleArrowEffectMovePoint(card, player, origin, target, count)
end
end
local function GetZoneName(player, zone)
if zone.type == TokenZoneType.Distance then
return "距"
elseif zone.type == TokenZoneType.Shadow then
return "虚"
elseif zone.type == TokenZoneType.Outside then
return "游戏外"
else
if zone.owner == nil then
return "未知"
else
local decorator = player.id == zone.owner.id and "自" or "敌"
if zone.type == TokenZoneType.Life then
return decorator.."命"
elseif zone.type == TokenZoneType.Aura then
return decorator.."装"
elseif zone.type == TokenZoneType.Flare then
return decorator.."气"
else
return "未知"
end
end
end
end
function Duel.DoubleArrowEffectMovePoint(card, player, origin, target, count)
local originName = GetZoneName(player, origin)
local targetName = GetZoneName(player, target)
local index = Duel.Choose(player, {
originName.."("..count..")→"..targetName,
targetName.."("..count..")→"..originName
})
if index == 0 then
Duel.ArrowEffectMovePoint(card, player, origin, target, count, true)
else
Duel.ArrowEffectMovePoint(card, player, target, origin, count, true)
end
end
function Duel.MovePoint(player, origin, target, count)
local co = coroutine.running()
System.MovePoint(player, origin, target, count,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.MoveToken(player, origin, target, tokens)
local co = coroutine.running()
System.MoveToken(player, origin, target, tokens,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.MoveTokens(player, target, tokens)
if tokens.Count ~= nil and tokens.Length ~= nil then
for _, token in pairs(tokens) do
Duel.MoveToken(player, token.zone, target, { token});
end
else
for i = 0, Util.len(tokens)-1, 1 do
Duel.MoveToken(player, tokens[i].zone, target, { tokens[i]});
end
end
end
function Duel.ImmediateResurgence(player, card)
local co = coroutine.running()
System.ImmediateResurgence(player, card,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.RestoreCombineCard(player, card)
local co = coroutine.running()
System.RestoreCombineCard(player, card,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.Choose(player, options, mask, button)
local showButton = button or false
local co = coroutine.running()
if mask == nil or Util.len(mask) == 0 then
mask = {}
for _ in pairs(options) do
table.insert(mask, true)
end
end
System.Choose(player, options, mask, showButton,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.ShuffleDeck(player)
local co = coroutine.running()
System.ShuffleDeck(player,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.RequestNormalAction(player)
if player.IsTerminal then
return
end
local co = coroutine.running()
System.RequestNormalAction(player,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.NormalAction(player, type)
local co = coroutine.running()
System.NormalAction(player, type,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.SealCard(player, parent, seal)
local co = coroutine.running()
System.SealCard(player, parent, seal,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.CancelAttack(player, attack)
local co = coroutine.running()
System.CancelAttack(player, attack,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end
function Duel.StopProcess(card)
local co = coroutine.running()
System.StopProcess(player,
function(...)
coroutine.resume(co, ...)
game:MoveNextPhase()
end)
return coroutine.yield(co)
end
function Duel.ExtendCard(player, cardId, used)
local extend = player:GetCardZone(CardZoneType.Extend)
local select = null
local iter = extend.list:GetEnumerator();
while iter:MoveNext() do
local card = iter.Current
if card.cardId == cardId then
select = card
end
end
if select ~= nil then
select.CanUse = false
select.status = CardStatus.None;
if used then
select.status = CardStatus.Used;
end
local target = select.data.type == CardType.Special and player:GetCardZone(CardZoneType.Special) or player:GetCardZone(CardZoneType.Hand)
Duel.MoveCard(player, select.zone, target, { select }, Util.len(target.list))
return select
end
end
function Duel.ActivateCardImage(player, cardId)
Duel.ActivateCard(player, PlayObject.Card(cardId))
end
function Duel.DeclareCardName(player)
local co = coroutine.running()
System.DeclareCardName(player,
function(...)
coroutine.resume(co, ...)
end)
return coroutine.yield(co)
end