Conditions, Costs, Activation Procedures, and Resolution
Activated effects usually delegate work to callbacks.
e1:SetCondition(s.condition)
e1:SetCost(s.cost)
e1:SetTarget(s.target)
e1:SetOperation(s.operation)Not every effect uses all four. A simple continuous stat effect might only use SetValue; a simple activated effect might only use SetTarget and SetOperation.
Common Callback Arguments
| Name | Meaning |
|---|---|
e | The effect being checked or resolving. |
tp | The player activating the effect or the player used as this effect's context. |
eg | Event group, when an event gives cards to the callback. |
ep | Event player. |
ev | Event value. |
re | Related effect that caused the event. |
r | Reason flags. |
rp | Reason player. |
chk | Cost/target legality check flag. |
chkc | Re-target check for target effects. |
The first eight arguments appear together so often that many scripts keep the same names even when only one or two are used.
Condition
Conditions answer whether the effect may be considered.
function s.condition(e,tp,eg,ep,ev,re,r,rp)
return Duel.IsMainPhase()
endUse a condition for timing or event requirements: "during the Main Phase", "when this card is Summoned", "if this card was destroyed by battle", and so on.
Conditions are ordinary Lua expressions, so grouping matters.
return c:IsDefensePos() and Duel.GetLP(1-tp)>Duel.GetLP(tp)Use parentheses when the card text mixes and and or.
return (a or b) and c
return a or (b and c)Be careful with not: write the expression you mean.
return not (Duel.GetLP(tp)>1500)That is clearer than relying on reader memory of Lua operator precedence.
Event And State Conditions
A condition can check a live state, an event that just happened, or both.
State conditions read the current Duel:
function s.condition(e,tp,eg,ep,ev,re,r,rp)
return Duel.IsMainPhase()
endEvent conditions inspect the event arguments. In local script c1003840.lua, the trigger condition reads the first card from eg and checks where it came from:
function c1003840.thcon(e,tp,eg,ep,ev,re,r,rp)
local ec=eg:GetFirst()
return Duel.GetTurnPlayer()~=tp
and ec:IsPreviousLocation(LOCATION_EXTRA)
and ec:IsPreviousControler(tp)
and ec:IsType(TYPE_SYNCHRO)
endUse event arguments only when the effect is actually tied to an event such as EVENT_SUMMON_SUCCESS, EVENT_TO_GRAVE, EVENT_CHAINING, or a phase event. For a free-chain effect, eg and friends usually do not carry the card text's main requirement; that requirement normally belongs in the live-state checks.
Callback Shapes Change
The familiar e,tp,eg,ep,ev,re,r,rp shape is common, but it is not universal. The effect type and effect code decide the callback shape.
| Effect shape | Common callback shape |
|---|---|
| Activated effects and event-watching effects | condition(e,tp,eg,ep,ev,re,r,rp), operation(e,tp,eg,ep,ev,re,r,rp) |
| Cost or target callbacks for activated effects | add chk; targeting effects often add chkc |
| Continuous field target filters | usually target(e,c) for each card being tested |
| Continuous value callbacks | code-specific; stat modifiers often use value(e,c) |
| Inherent Special Summon procedures | local scripts commonly use condition(e,c) and pass the Summoned card as c |
For example, Lava Golem (c102380.lua) uses an inherent Special Summon procedure, so its condition is not the normal activated-effect shape:
function c102380.spcon(e,c)
if c==nil then return true end
local tp=c:GetControler()
local rg=Duel.GetMatchingGroup(Card.IsReleasable,tp,0,LOCATION_MZONE,nil,REASON_SPSUMMON)
return rg:CheckSubGroup(c102380.fselect,2,2,tp)
endWhen a callback behaves strangely, check the effect's SetType, SetCode, and the matching procedure helper before changing the function body.
Cost
Costs have two phases. When chk==0, only answer whether the cost can be paid. When chk is not 0, actually pay it.
function s.cost(e,tp,eg,ep,ev,re,r,rp,chk)
if chk==0 then return Duel.CheckLPCost(tp,1000) end
Duel.PayLPCost(tp,1000)
endDo not release, discard, banish, or pay LP in the chk==0 branch. The engine may call that branch just to test whether the effect can be activated.
Many cost functions have three practical sections:
function s.cost(e,tp,eg,ep,ev,re,r,rp,chk)
local c=e:GetHandler()
if chk==0 then
return c:IsDiscardable()
end
Duel.SendtoGrave(c,REASON_COST+REASON_DISCARD)
end| Section | Job |
|---|---|
| Shared setup | Read e:GetHandler(), count cards, or build local values used by both branches. |
| Checking branch | Return whether the cost can be paid. |
| Payment branch | Actually pay the cost. |
Do not hide payment inside a helper that is called from both branches unless the helper itself also respects chk.
Target
Target callbacks usually do two jobs:
- During
chk==0, prove the effect can be activated. - During the real activation, select targets and announce operation info.
function s.target(e,tp,eg,ep,ev,re,r,rp,chk,chkc)
if chkc then return chkc:IsOnField() and s.filter(chkc) end
if chk==0 then
return Duel.IsExistingTarget(s.filter,tp,LOCATION_MZONE,0,1,nil)
end
Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_TARGET)
Duel.SelectTarget(tp,s.filter,tp,LOCATION_MZONE,0,1,1,nil)
Duel.SetOperationInfo(0,CATEGORY_DESTROY,nil,1,tp,LOCATION_MZONE)
endUse Duel.IsExistingTarget and Duel.SelectTarget when the effect targets. Use matching-card functions when the card text does not target.
For activated effects that do not target, the target callback often only checks whether the later operation has a legal attempt and announces operation info.
function s.sptg(e,tp,eg,ep,ev,re,r,rp,chk)
local c=e:GetHandler()
if chk==0 then
return Duel.GetLocationCount(tp,LOCATION_MZONE)>0
and c:IsCanBeSpecialSummoned(e,0,tp,false,false)
end
Duel.SetOperationInfo(0,CATEGORY_SPECIAL_SUMMON,c,1,0,0)
endSome effects have no legal manual target recheck. In those cases scripts may answer false in the chkc branch.
if chkc then return false endUse that only when the effect's activation should not accept a manually chosen target.
For continuous field effects, SetTarget has a different job: it filters which cards in the target range are affected.
e1:SetType(EFFECT_TYPE_FIELD)
e1:SetCode(EFFECT_UPDATE_ATTACK)
e1:SetTargetRange(LOCATION_MZONE,0)
e1:SetTarget(s.atktg)
e1:SetValue(300)
function s.atktg(e,c)
return c:IsFaceup() and c:IsSetCard(0x123)
endThis target callback does not receive chk and does not select official Chain targets. Always read the effect type and effect code before assuming a callback signature.
Operation
Operations resolve the effect. The game state may have changed after activation, so re-check cards before moving or modifying them.
function s.operation(e,tp,eg,ep,ev,re,r,rp)
local tc=Duel.GetFirstTarget()
if tc and tc:IsRelateToEffect(e) then
Duel.Destroy(tc,REASON_EFFECT)
end
endIf several target cards were selected, use Duel.GetTargetsRelateToChain() or Duel.GetChainInfo(0,CHAININFO_TARGET_CARDS):Filter(Card.IsRelateToEffect,nil,e) depending on what the script needs to preserve.
Value
SetValue can be a number or a callback. Continuous ATK/DEF effects commonly use value callbacks when the amount depends on the current field.
function s.val(e,c)
return Duel.GetMatchingGroupCount(s.filter,c:GetControler(),LOCATION_MZONE,0,nil)*400
endThe arguments depend on the effect code. A value function for a stat modifier is not the same shape as a value function for an activation restriction or an equip limit.
Duel.SetOperationInfo
Duel.SetOperationInfo tells the engine and UI what the effect intends to do. It does not perform the action. The actual action belongs in the operation.
Duel.SetOperationInfo(0,CATEGORY_TOHAND,nil,1,tp,LOCATION_DECK)Use categories that match the real operation: draw, destroy, send to GY, banish, Special Summon, equip, search, and so on.
Relevant API pages: