It is currently 20 Oct 2018, 20:00
   
Text Size

Storing and Retrieving Filters

Moderators: Xander9009, CCGHQ Admins

Storing and Retrieving Filters

Postby Xander9009 » 11 Sep 2016, 06:28

Being able to store and retrieve filters seems like an idea that might be useful. I don't currently know of any way to store a filter and retrieve it later, perhaps by another card. For instance, protection filters. So, I made a set of functions that can manage this. It's only VERY basically tested, so far, but it did work for the extremely simple filter "creature".

Code: Select all
<RESOLUTION_TIME_ACTION>
   local oFilter = CW_Filter_ClearFilter()
   CW_Filter_Add(oFilter, {FE_TYPE, OP_IS, CARD_TYPE_CREATURE})
   EffectDC():Set_Int(0, CW_Filter_GetGlobalIndex(SmartFilter))
   EffectController():ChooseItem("CHOOSE", EffectDC():Make_Targets(1))
</RESOLUTION_TIME_ACTION>
<RESOLUTION_TIME_ACTION>
   local oFilter = CW_Filter_GetStoredFilter(EffectDC():Get_Int(0)) -- Technically, the variable is unnecessary.
   EffectController():ChooseItem("CHOOSE_AGAIN", EffectDC():Make_Targets(2))
</RESOLUTION_TIME_ACTION>
As you can see, the functions are called basically the same way they always are. Three small changes are made.
"CW_Filter_" is prefixed on the function name.
The filter (usually preceding the function) is moved into its first parameter.
The normal parameters are placed inside braces.

The idea here is that the "filter" return here is actually a rather complex table. The table contains two parts: indices, filter. This inner filter is the normal filter you'd get from ClearFilter(). Indices normally contains just the global index (but in a table) where this complex filter's instruction table is stored. Whenever you call "add", it appends a new entry to the table consisting of the function ("Add" in this case) and the parameters. The table for "creature" ends up looking like this: {"Add", {FE_TYPE, OP_IS, CARD_TYPE_CREATURE}}.

Non-human artifact would look like this:
{"Add", {FE_SUBTYPE, OP_NOT, CARD_TYPE_HUMAN}}
{"Add", {FE_TYPE, OP_IS, CARD_TYPE_ARTIFACT}}

It can also manage SetZone, AddSubFilter_Or/And, and SetFilterType, all using the same logic.

So, "Target red instant or sorcery card in your graveyard" would end up like this:
Code: Select all
{"SetZone", {ZONE_GRAVEYARD, EffectController()}}
{"Add", {FE_COLOUR, OP_IS, COLOUR_RED}}
{"AddSubFilter_Or", {
                     {"Add", {FE_TYPE, OP_IS, CARD_TYPE_INSTANT}}
                     {"Add", {FE_TYPE, OP_IS, CARD_TYPE_SORCERY}}
                                                                 }
It can all be put back together with the single function CW_Filter_GetStoredFilter(). GetStoredFilter takes a single parameter, an integer. That integer is the global index (from CW_Globals_Store()) at which the table is stored. Since it's available through a global function via just a number, anything you can pass that number to can load the filter.

Using these functions, it would be really easy to convert a card with protection to a card with an exposed protection filter. This would allow other cards to check if a given card falls within that protection. It would be a pretty big undertaking (there are about 250 cards with protection), but it would be a really simple edit to make to them.

This would allow cards like Avalanche Tusker and anything else that requires knowing if Card A could target/block Card B, like Mirrorwing Dragon (we can already load the TargetDefinition).

I think Monday I'll test the functions thoroughly and if they hold up, I'll see about getting the protection cards converted over. In the meantime, if anyone has thoughts on this, let me know.

http://pastebin.com/7GBuq0y7
Last edited by Xander9009 on 11 Sep 2016, 17:07, edited 2 times in total.
_______________________________
Community Wad - Community Wad Website - How to Help and Report Bugs
Discord: discord.gg/4AXvHzW
User avatar
Xander9009
Programmer
 
Posts: 2820
Joined: 29 Jun 2013, 07:44
Location: Indiana, United States
Has thanked: 101 times
Been thanked: 421 times

Re: Storing and Retrieving Filters

Postby migookman » 11 Sep 2016, 16:45

This sounds awesome! Can add potential to some cards that are deemed impossible at the moment. If you need some testing, shoot me a message. Right now I'm just coding older cards (thought I would leave the newer cards to newer coders). I have done all I could for cards A and B with my limited ability. Working on 'C's now. I'm also making a percentage of cards done for the CW similar to what Forge does for new releases that would probably look good on the opening of the CW thread.
User avatar
migookman
 
Posts: 113
Joined: 05 Aug 2014, 06:37
Has thanked: 18 times
Been thanked: 6 times

Re: Storing and Retrieving Filters

Postby Xander9009 » 11 Sep 2016, 17:21

Feel free to try them out. They're in CW_FILTER.LOL. The first two functions in there aren't part of this set (they were made a long time ago, and were actually never even used).

Note that CW_Filter_GetGlobalIndex() changed to CW_Filter_GetFilterIndex().

There's a quick bit of instructions if you scroll down, which is this right here:
Code: Select all
   For basic usage, nothing more is needed except the following information:
   1: Precede all filter functions with "CW_Filter_" to get the name of the function you should use.
   2: Place the filter you get from "CW_Filter_ClearFilter()" as the first parameter of all other function calls.
   3: Call CW_Filter_GetFilterIndex(aoFilter) of that filter to get an index.
   4: Store that index somewhere other cards that needs it can access it.
   5: Call CW_Filter_GetStoredFilter(iIndex) using that index to remake the filter from anywhere in a usable format.
   
   NOTE: The "aoFilters" (array object filters) these functions deal with are not directly compatible with normal filters.
   They're tables. If you /need/ to deal with them as normal filters, you need to call CW_Filter_GetNormalFilter(aoFilter).
   The only exception to this is the reconstructed filters. When you call CW_Filter_GetStoredFilter(iIndex), you get a normal
   filter, like you would have from ClearFilter().
   
   Nearly every normal filter function is supported, including EvaluateObjects and similar functions.
   Only a few (ones which have never been used) are missing. If they're needed, you can call
   CW_Filter_GetNormalFilter(aoFilter) to get the actual filter to work with. However, any changes you make to the
   base filter will not be stored for later retrieval.
In the last paragraph, you'll notice I added all of the other functions. Supported are:
  • CW_Filter_ClearFilter
  • CW_Filter_Add
  • CW_Filter_AddSubFilter_Or
  • CW_Filter_AddSubFilter_And
  • CW_Filter_SetZone
  • CW_Filter_SetFilterType
  • CW_Filter_SetPortion
  • CW_Filter_SetReversePortion
  • CW_Filter_SetUnique
  • CW_Filter_SetMarkedObjectsOnly
  • CW_Filter_SetUnmarkedObjectsOnly
  • CW_Filter_Count
  • CW_Filter_CountStopAt
  • CW_Filter_EvaluateObjects
  • CW_Filter_GetNthEvaluatedObject
  • CW_Filter_GetRandomEvaluatedObject
  • CW_Filter_EvaluatePlayers
  • CW_Filter_GetNthEvaluatedPlayer
  • CW_Filter_ChromaCount
  • CW_Filter_Invalidate

I make no promises they'll work as advertised yet, though lol. Since I made the change to store everything in one global (rather than potentially taking up dozens), I haven't tested it at all. That'll all come either tonight or tomorrow (I'm busy today).

As for the percentage thing, yeah. That's a great idea. :)
_______________________________
Community Wad - Community Wad Website - How to Help and Report Bugs
Discord: discord.gg/4AXvHzW
User avatar
Xander9009
Programmer
 
Posts: 2820
Joined: 29 Jun 2013, 07:44
Location: Indiana, United States
Has thanked: 101 times
Been thanked: 421 times

Re: Storing and Retrieving Filters

Postby Xander9009 » 13 Sep 2016, 00:05

I'm pleased. I ended up rewriting them from scratch when I found a problem with the subfilters not working. Trying to keep everything straight in my head was a bit too difficult, so I recoded everything from scratch. It works basically the same way. All of the functions that need called from cards and stuff are the same.

Internally, however, it's completely different. Now, "smart filters" or "aoFilter" ideas have been replaced with "Screen". "Screen" was chosen because a screen is the same concept as a filter (you can screen objects for certain qualities), but others can see the screen, too.

They've now been tested. This code worked as it should:
Code: Select all
<RESOLUTION_TIME_ACTION>
   local oFilter = CW_Filter_ClearFilter()
   local oSubFilter_Or = CW_Filter_AddSubFilter_Or(oFilter)
      local oSubFilter_Land = CW_Filter_AddSubFilter_And(oSubFilter_Or)
         CW_Filter_Add(oSubFilter_Land, {FE_CONTROLLER, OP_NOT, EffectController()})
         CW_Filter_Add(oSubFilter_Land, {FE_TYPE, OP_IS, CARD_TYPE_LAND})
      local oSubFilter_Creature = CW_Filter_AddSubFilter_And(oSubFilter_Or)
         CW_Filter_Add(oSubFilter_Creature, {FE_CONTROLLER, OP_IS, EffectController()})
         CW_Filter_Add(oSubFilter_Creature, {FE_TYPE, OP_IS, CARD_TYPE_CREATURE})
   MTG():DuelDataChest():Set_Int(0, CW_Filter_GetFilterIndex(oFilter))
</RESOLUTION_TIME_ACTION>
That code was on one card. This code was on another:
Code: Select all
<RESOLUTION_TIME_ACTION>
   local oFilter = CW_Filter_ReconstructFilter(MTG():DuelDataChest():Get_Int(0))
   EffectController():ChooseItem("CHOOSE_ONCE_MORE", EffectDC():Make_Targets(3))
</RESOLUTION_TIME_ACTION>
The second card allowed me to choose a land I didn't control OR a creature I did control, which is exactly what it was supposed to do. I think that means they're working, now. :)

Also, in the process of getting this all working, I had to list out table values a lot to see what was going on. As a result, the function Debug() has been updated. It's now a LOT more powerful, especially where tables are concerned.

Debug(sMessage, oParameter)
If sMessage is a string, then the two inputs are put together with ": " between them. So...
Code: Select all
local S = "Some string"
Debug("S", S)
results in "[S: Some string]" being displayed in game (except all caps, due to the game's displaymessage function).

However, either sMessage or oParameter can also be a table/array. They'll be run through a function to convert them to a string before being concatenated. It's a recursive function, so it can even show the contents of tables inside tables.

If it comes across a value that isn't a number or a string, it'll list its type instead of breaking.

Hopefully this helps when coding.
_______________________________
Community Wad - Community Wad Website - How to Help and Report Bugs
Discord: discord.gg/4AXvHzW
User avatar
Xander9009
Programmer
 
Posts: 2820
Joined: 29 Jun 2013, 07:44
Location: Indiana, United States
Has thanked: 101 times
Been thanked: 421 times

Re: Storing and Retrieving Filters

Postby Xander9009 » 13 Sep 2016, 04:07

Alright, update...

Everything seems to be working. I wrote a couple more functions specifically for storing and retrieving protection filters. Because we don't want the filters being stored constantly, the normal filter is left as it already appears on the cards. However, the screen version is added to a one-time RTA at the start of the game. It then calls: CW_Filter_RegisterProtectionFilter(oFilter). From this point on, a few other functions become usable.

CW_Filter_HasProtection(oCard) - Returns true if the cards has registered protection.
CW_Filter_GetProtectionFilter(oCard) - Creates the protection filter (normal filter, which will override any currently active filters) and returns a link to it.
And most importantly:
CW_Filter_HasProtectionFrom(oCardA, oCardB) - Returns true if oCardA is protected from oCardB.


Also useful:
CW_Filter_FilterToDC(oFilter, oChest, iFilterType) - Evaluates the filter and stores the resulting objects in oChest. Note that it can process both players and cards. If players are included (whether alone or with cards) iFilterType must be set to either FILTER_TYPE_CARDS + FILTER_TYPE_PLAYERS or FILTER_TYPE_PLAYERS. If it's both, the it will return two chests, not one. The first contains the objects and the second contains the players.

Both can be captured by simply providing two variables.
Code: Select all
local filter = ClearFilter()
filter:SetFilterType(FILTER_TYPE_CARDS + FILTER_TYPE_PLAYERS)
filter:Add(FE_TYPE, OP_IS, CARD_TYPE_CREATURE)
local Cards, Players = CW_Filter_FilterToDC(filter, EffectDC():Make_Chest(0), FILTER_TYPE_CARDS + FILTER_TYPE_PLAYERS)
Boths Cards and Players should be valid chests with all of the found creatures and players.



------


As a complete example, Abbey Gargoyles was put into a deck. Then, Favor of the Gods (my test card) was given this code:
Code: Select all
<RESOLUTION_TIME_ACTION>
   local oFilter = ClearFilter()
   oFilter:Add(FE_TYPE, OP_IS, CARD_TYPE_CREATURE)
   local oCreatureChest = CW_Filter_FilterToDC(oFilter, EffectDC():Make_Chest(9000))
</RESOLUTION_TIME_ACTION>
<RESOLUTION_TIME_ACTION mode="1" repeating="1">
   local oCard = EffectDC():Get_Chest(1):Get_CardPtr(0)
   local i = MTG():GetActionRepCount()
   local oCreature = EffectDC():Get_Chest(9000):Get_CardPtr(i)
   if oCreature ~= nil then
      if CW_Filter_HasProtectionFrom(oCard, oCreature) then
         oFilter = ClearFilter()
         oFilter:Add(FE_CARD_INSTANCE, OP_IS, oCreature)
         EffectController():ChooseItem("Has protection from this card", EffectDC():Make_Chest(9001), QUERY_FLAG_MAY)
      end
   end
   return i &lt; EffectDC():Get_Chest(9000):Count()-1
</RESOLUTION_TIME_ACTION>
The result was that Abbey Gargoyles successfully registered its protection filter. Favor of the Gods was then able to completely separately test all creatures on the battlefield and check if Abbey Gargoyles has protection from that particular creature. (I set it up so that if it does have protection, then it highlights it on the battlefield and lets you look until you click it. Nothing special, just a way to see it successfully cycling through them.)

Also, since the initial protection filter is left alone, even if these do somehow break, the cards that use them won't suddenly stop working.

It all appears to be working. I'm really happy with this progress. :)

but now it's time for bed. Since it's all set up and working, I think I'll spend tomorrow sorting through the cards with protection and implementing new functions. (The protection check actually needs one tweak: a way to make sure the protection ability is still active. But Neo and I already came up with a method for that a long time ago.)
_______________________________
Community Wad - Community Wad Website - How to Help and Report Bugs
Discord: discord.gg/4AXvHzW
User avatar
Xander9009
Programmer
 
Posts: 2820
Joined: 29 Jun 2013, 07:44
Location: Indiana, United States
Has thanked: 101 times
Been thanked: 421 times

Re: Storing and Retrieving Filters

Postby Xander9009 » 13 Sep 2016, 19:52

Update

Alright, it took a lot of trial and error, but Mirrorwing Dragon is working. Three things still need worked out, but the hard part is done. With 4 creatures on the battlefield, one of which was Mirrorwing Dragon, and one of which was Abbey Gargoyles, I cast Kindled Fury on Mirrorwing Dragon and it made two copies. Each copy targeted one of the two other creatures I had out, leaving Mirrorwing Dragon and Abbey Gargoyles untargeted by the copies.

The things that still need fixed are
1: Mirrorwing Dragon triggers when it's targeted, as opposed to when it's the only target.
2: Abbey Gargoyles is currently the only protection card that has the new functions.
3: A manager token needs made to reset a particular global variable at layer 0. Protection cards might need their protection moved from layer 0.
_______________________________
Community Wad - Community Wad Website - How to Help and Report Bugs
Discord: discord.gg/4AXvHzW
User avatar
Xander9009
Programmer
 
Posts: 2820
Joined: 29 Jun 2013, 07:44
Location: Indiana, United States
Has thanked: 101 times
Been thanked: 421 times


Return to Programming Talk

Who is online

Users browsing this forum: No registered users and 3 guests


Who is online

In total there are 3 users online :: 0 registered, 0 hidden and 3 guests (based on users active over the past 10 minutes)
Most users ever online was 279 on 11 Jul 2013, 22:03

Users browsing this forum: No registered users and 3 guests

Login Form