It is currently 25 Apr 2024, 14:55
   
Text Size

Good example for counters management: Hex Parasite

Moderator: CCGHQ Admins

Good example for counters management: Hex Parasite

Postby thefiremind » 15 Jul 2012, 12:10

I thought it could be useful for someone to see my freshly coded Hex Parasite, as an example of how to manage any type of counter.

Here's the code for the ability:
Code: Select all
  <ACTIVATED_ABILITY dangerous="1" filter_zone="ZONE_IN_PLAY">
    <COST type="Mana" cost="{X}{B/P}" />
    <TARGET_DEFINITION id="0">
    if EffectController():IsAI() ~= 0 then
       MTG():ClearFilterMarkedObjectsInZone( ZONE_IN_PLAY )
    end
    local filter = Object():GetFilter()
    filter:Clear()
    filter:AddCardType( CARD_TYPE_ARTIFACT )
    filter:AddCardType( CARD_TYPE_ENCHANTMENT )
    filter:AddCardType( CARD_TYPE_LAND )
    filter:AddCardType( CARD_TYPE_CREATURE )
    filter:AddCardType( CARD_TYPE_PLANESWALKER )
    filter:SetZone( ZONE_IN_PLAY )
    if EffectController():IsAI() ~= 0 then
       local filter_count = filter:EvaluateObjects()
       for i=0,filter_count-1 do
           local candidate = filter:GetNthEvaluatedObject(i)
           if candidate:GetBestOrWorstCounterType(1) ~= 0 or candidate:GetBestOrWorstCounterType(0) ~= 0 then
              candidate:MarkForFilter()
           end
       end
       filter:SetMarkedObjectsOnly()
    end
    filter:SetHint( HINT_NEUTRAL, EffectController() )
    </TARGET_DEFINITION>
    <TARGET_DETERMINATION>
    return AtLeastOneTargetFromDefinition(0)
    </TARGET_DETERMINATION>
    <PLAY_TIME_ACTION target_choosing="1">
    EffectController():ChooseTarget( 0, "CARD_QUERY_CHOOSE_PERMANENT", EffectDC():Make_Targets(0) )
    </PLAY_TIME_ACTION>
    <RESOLUTION_TIME_ACTION>
    local target = EffectDC():Get_Targets(0):Get_CardPtr(0)
    local max_counters = GetEffectX()
    local i = 0
    if target ~= nil and target:GetZone() == ZONE_IN_PLAY and max_counters &gt; 0 then
       local counter_type = 0
       local friend = 0
       if target:GetPlayer():GetTeam() == EffectController():GetTeam() then
          friend = 1
       end
       repeat
          counter_type = target:GetBestOrWorstCounterType(1-friend)
          if i &lt; max_counters and counter_type ~= 0 then
             target:RemoveCounters( counter_type, 1 )
             i = i+1
          end
       until i == max_counters or counter_type == 0
       repeat
          counter_type = target:GetBestOrWorstCounterType(friend)
          if i &lt; max_counters and counter_type ~= 0 then
             target:RemoveCounters( counter_type, 1 )
             i = i+1
          end
       until i == max_counters or counter_type == 0
    end
    EffectDC():Set_Int(1, i)
    </RESOLUTION_TIME_ACTION>
    <CONTINUOUS_ACTION layer="7C">
    local power = EffectDC():Get_Int(1)
    if EffectSource() ~= nil and power &gt; 0 then
       EffectSource():GetCurrentCharacteristics():Power_Add( power )
    end
    </CONTINUOUS_ACTION>
    <DURATION simple_duration="UntilEOT" />
    <AI_AVAILABILITY type="in_response" />
    <AI_AVAILABILITY type="in_response_dangerous" />
    <AI_AVAILABILITY step="declare_blockers" />
  </ACTIVATED_ABILITY>
First, I save some burden from the AI by restricting its targets to those that actually have counters on them. The principle is the same you'll see further inside the ability code: the function that was used in DotP2012 for proliferate returns 0 if the permanent has no counters, otherwise returns a counter type index for a "good" counter if the parameter was 1, for a "bad" counter if the parameter was 0. I still have to check how well this distinction is made now that we can declare any counter type, but for the hard-coded counters (+1/+1, -1/-1, charge) it should still work well with no doubt.
The "core" of the ability consists in 2 repeat loops: if the target is on my side, I try to remove "bad" counters first and "good" ones afterwards, otherwise I do the opposite. Finally, I save the value of "i" (which has been incremented each time I removed a counter) and add it to the creature's power.

If someone wonders why I explicitly put all permanent types in the filter, it's because I don't want invisible tokens to get in the way. We have no way to select something invisible, but I'm not sure about the AI.

I still have to decide what to write as query string, so CARD_QUERY_CHOOSE_PERMANENT is just a placeholder. :wink:

In the attachment you can find the complete code and the illustration (it wasn't so quick to find it hi-res, so take it from there and save a couple of minutes googling).
Attachments
HEX_PARASITE_218008.zip
Hex Parasite code + illustration
(112.4 KiB) Downloaded 205 times
< Former DotP 2012/2013/2014 modder >
Currently busy with life...
User avatar
thefiremind
Programmer
 
Posts: 3515
Joined: 07 Nov 2011, 10:55
Has thanked: 118 times
Been thanked: 721 times

Return to Programming Talk

Who is online

Users browsing this forum: No registered users and 18 guests


Who is online

In total there are 18 users online :: 0 registered, 0 hidden and 18 guests (based on users active over the past 10 minutes)
Most users ever online was 4143 on 23 Jan 2024, 08:21

Users browsing this forum: No registered users and 18 guests

Login Form