Card Development Questions
Post MTG Forge Related Programming Questions Here
Moderators: timmermac, Blacksmith, KrazyTheFox, Agetian, friarsol, CCGHQ Admins
Re: Card Development Questions
by Sloth » 22 Jun 2013, 06:33
The reason they haven't been added yet is the interaction with "All creatures able to block CARDNAME do so.", "CARDNAME must be blocked if able.", "CARDNAME blocks each turn if able.", etc.friarsol wrote:Sloth, is there enough AI in there now for these cards to be scripted? I know the reason they weren't added before wasn't due to the complexity of the script, but the complexity of the AI needed to support them.Max mtg wrote:Just added keywords to restrict a custom number of blockers.
Already implemented Pathrazer of Ulamog and Gorilla Berserkers.
Not only does the AI need to make legal blocks, but we also have to make sure the blocking input for the human can't get stuck.
-
Sloth - Programmer
- Posts: 3498
- Joined: 23 Jun 2009, 19:40
- Has thanked: 125 times
- Been thanked: 507 times
Re: Card Development Questions
by Max mtg » 22 Jun 2013, 07:01
Looks like these need to be implemeneted.
Who is to take this assignment?
(I'll take it if noone else accepts this challenge)
Who is to take this assignment?
(I'll take it if noone else accepts this challenge)
Single class for single responsibility.
- Max mtg
- Programmer
- Posts: 1997
- Joined: 02 Jul 2011, 14:26
- Has thanked: 173 times
- Been thanked: 334 times
Re: Card Development Questions
by Sloth » 22 Jun 2013, 08:27
I can take care of the AI.Max mtg wrote:Looks like these need to be implemeneted.
Who is to take this assignment?
(I'll take it if noone else accepts this challenge)
For the human finishedMandatoryBlocks has to be tested a lot and fixed if necessary. I would be glad if you could do the fixing in this case Max.
EDIT: Be sure to check rule 509.1c.
-
Sloth - Programmer
- Posts: 3498
- Joined: 23 Jun 2009, 19:40
- Has thanked: 125 times
- Been thanked: 507 times
Re: Card Development Questions
by Max mtg » 22 Jun 2013, 10:42
I am not satisfied how Combat class is designed... will have to change it.
Why would AI directly assign new values to combat? AiAttackController thinks in terms of single opponent... What is use of Combat instance outside of Combat phase?
Attacking band - why would it know if it is blocked? It's just a set of cards attacking a given target.
I've found a good field to refactor a lot of aspects. )
Why would AI directly assign new values to combat? AiAttackController thinks in terms of single opponent... What is use of Combat instance outside of Combat phase?
Attacking band - why would it know if it is blocked? It's just a set of cards attacking a given target.
I've found a good field to refactor a lot of aspects. )
Single class for single responsibility.
- Max mtg
- Programmer
- Posts: 1997
- Joined: 02 Jul 2011, 14:26
- Has thanked: 173 times
- Been thanked: 334 times
Re: Card Development Questions
by friarsol » 22 Jun 2013, 12:56
Because if all blockers are removed it still is blocked. Or if a card (like Dazzling Beauty) is cast on a Band, it's blocked without blockers. Max, you do understand you don't need to rewrite every single file you touch, right?Max mtg wrote:Attacking band - why would it know if it is blocked? It's just a set of cards attacking a given target.
- friarsol
- Global Moderator
- Posts: 7593
- Joined: 15 May 2010, 04:20
- Has thanked: 243 times
- Been thanked: 965 times
Re: Card Development Questions
by Max mtg » 22 Jun 2013, 13:47
No =)friarsol wrote:Because if all blockers are removed it still is blocked. Or if a card (like Dazzling Beauty) is cast on a Band, it's blocked without blockers. Max, you do understand you don't need to rewrite every single file you touch, right?
Attacking Bands had some unneeded data - like blockers, defender etc. Blocked flag is not excessive, I see.
What do we have in Combat class? A lot of collections:
* List of bands
* Map: Attacker -> Band
* Map: Blocker -> List<Band>
* Map: Defender -> List<Card>
meanwhile all these data can be held in just 2 maps:
- Code: Select all
// Defenders, as they are attacked by hostile forces
private final MapOfLists<GameEntity, AttackingBand> entitiesAttacked = new HashMapOfLists<GameEntity, AttackingBand>(CollectionSuppliers.<AttackingBand>arrayLists());
// Blockers to stop the hostile invaders
private final MapOfLists<AttackingBand, Card> bandsBlocked = new HashMapOfLists<AttackingBand, Card>(CollectionSuppliers.<Card>arrayLists());
Last edited by Max mtg on 22 Jun 2013, 14:11, edited 1 time in total.
Single class for single responsibility.
- Max mtg
- Programmer
- Posts: 1997
- Joined: 02 Jul 2011, 14:26
- Has thanked: 173 times
- Been thanked: 334 times
Re: Card Development Questions
by friarsol » 22 Jun 2013, 14:05
If you think that's a lot of collections, you should have seen before I started working on Banding.Max mtg wrote:Attacking Bands had some data - like blockers, defender etc. Blocked flag is not excessive, I see.
What do we have in Combat class? A lot of collections:
* List of bands
* Map: Attacker -> Band
* Map: Blocker -> List<Band>
* Map: Defender -> List<Card>
meanwhile all these data can be held in just 2 maps:So I cannot just leave this as it is.
- Code: Select all
// Defenders, as they are attacked by hostile forces
private final MapOfLists<GameEntity, AttackingBand> entitiesAttacked = new HashMapOfLists<GameEntity, AttackingBand>(CollectionSuppliers.<AttackingBand>arrayLists());
// Blockers to stop the hostile invaders
private final MapOfLists<AttackingBand, Card> bandsBlocked = new HashMapOfLists<AttackingBand, Card>(CollectionSuppliers.<Card>arrayLists());
Anyway, merging the List of Bands with the Defender->Bands should be fine (at least glancing at it quickly), but if you get rid of the Attacker->Band Map that slows down the lookup for removing attackers, and similar things that take single Attackers into account instead of AttackingBands as a whole.
(Unless I'm missing something, you would need to grab all Bands via the Defender map, and then check if each one contains the Attacker.)
- friarsol
- Global Moderator
- Posts: 7593
- Joined: 15 May 2010, 04:20
- Has thanked: 243 times
- Been thanked: 965 times
Re: Card Development Questions
by Max mtg » 22 Jun 2013, 14:19
It's fine then - each developer makes his iteration improving code over time. No wonder I didn't dare to change Combat before you cleaned it up and introduced bands. =D
How many creatures have to be involved into combat to notice the performance gain granted by the map from attacker card to AttackingBand?
Exactly.
How many creatures have to be involved into combat to notice the performance gain granted by the map from attacker card to AttackingBand?
Exactly.
- Code: Select all
public final AttackingBand getBandOfAttacker(final Card c) {
for(Collection<AttackingBand> abs : entitiesAttacked.values()) {
for(AttackingBand ab : abs) {
if ( ab.contains(c) )
return ab;
}
}
return null;
}
Single class for single responsibility.
- Max mtg
- Programmer
- Posts: 1997
- Joined: 02 Jul 2011, 14:26
- Has thanked: 173 times
- Been thanked: 334 times
Re: Card Development Questions
by friarsol » 22 Jun 2013, 14:41
You don't find that triple nested loop ugly? I do.Max mtg wrote:It's fine then - each developer makes his iteration improving code over time. No wonder I didn't dare to change Combat before you cleaned it up and introduced bands. =D
How many creatures have to be involved into combat to notice the performance gain granted by the map from attacker card to AttackingBand?
Exactly.
- Code: Select all
public final AttackingBand getBandOfAttacker(final Card c) {
for(Collection<AttackingBand> abs : entitiesAttacked.values()) {
for(AttackingBand ab : abs) {
if ( ab.contains(c) )
return ab;
}
}
return null;
}
- friarsol
- Global Moderator
- Posts: 7593
- Joined: 15 May 2010, 04:20
- Has thanked: 243 times
- Been thanked: 965 times
Re: Card Development Questions
by Max mtg » 22 Jun 2013, 14:54
Triple loop... well, it looks like one.
There is a field for doubts: first, index can be re-introduced. Meanwhile the performance gain is minimal and you have to maintain another map.
There is a field for doubts: first, index can be re-introduced. Meanwhile the performance gain is minimal and you have to maintain another map.
Single class for single responsibility.
- Max mtg
- Programmer
- Posts: 1997
- Joined: 02 Jul 2011, 14:26
- Has thanked: 173 times
- Been thanked: 334 times
Re: Card Development Questions
by swordshine » 30 Jun 2013, 05:07
Plane Jund has a trigger "Whenever a player casts a black, red, or green creature spell, it gains devour 5". Animate an etbreplacement effect? Currently the "Devour" keyword in Forge does not create a perfect replacement effect.
- swordshine
- Posts: 682
- Joined: 11 Jul 2010, 02:37
- Has thanked: 116 times
- Been thanked: 87 times
Re: Card Development Questions
by jsv » 08 Jul 2013, 12:26
There was this report recently in the 1.4.2 beta thread:
I've fixed it by changingcc-drake wrote:- My Tolarian Entrancer is blocked by Village Ironsmith , but at end of combat, I don't get control of it.
- Code: Select all
T:Mode$ AttackerBlocked | ValidCard$ Card.Self | ValidBlocker$ Creature
- Code: Select all
T:Mode$ Blocks | ValidCard$ Creature | ValidBlocked$ Card.Self
Re: Card Development Questions
by swordshine » 08 Jul 2013, 12:52
These two scripts are different. "T:Mode$ Blocks" should only trigger once when it blocks any creatures (Lairwatch Giant and Guardian of the Gateless), this was implemented by ArsenalNut during GTC spoiler season. "T:Mode$ AttackerBlocked" should trigger multiple times for each blocking creature. I have not tested if these scripts are still working as supposed.jsv wrote:There was this report recently in the 1.4.2 beta thread:I've fixed it by changingcc-drake wrote:- My Tolarian Entrancer is blocked by Village Ironsmith , but at end of combat, I don't get control of it.to
- Code: Select all
T:Mode$ AttackerBlocked | ValidCard$ Card.Self | ValidBlocker$ Creature
Still I wonder, if it used to work as scripted and we have some regression there.
- Code: Select all
T:Mode$ Blocks | ValidCard$ Creature | ValidBlocked$ Card.Self
- swordshine
- Posts: 682
- Joined: 11 Jul 2010, 02:37
- Has thanked: 116 times
- Been thanked: 87 times
Re: Card Development Questions
by Max mtg » 08 Jul 2013, 12:56
This is a very useful comment.swordshine wrote:These two scripts are different. "T:Mode$ Blocks" should only trigger once when it blocks any creatures (Lairwatch Giant and Guardian of the Gateless), this was implemented by ArsenalNut during GTC spoiler season. "T:Mode$ AttackerBlocked" should trigger multiple times for each blocking creature. I have not tested if these scripts are still working as supposed.
If there are any problems with incorrectly firing triggers, I can fix it for you (because I changed Combat a couple of weeks ago and the very declare blockers step last night)
Single class for single responsibility.
- Max mtg
- Programmer
- Posts: 1997
- Joined: 02 Jul 2011, 14:26
- Has thanked: 173 times
- Been thanked: 334 times
Re: Card Development Questions
by Sloth » 08 Jul 2013, 13:11
I didn't know about the new functionality of "T:Mode$ Blocks" and i think i broke it some month ago. But i think it can't really work that way.swordshine wrote:These two scripts are different. "T:Mode$ Blocks" should only trigger once when it blocks any creatures (Lairwatch Giant and Guardian of the Gateless), this was implemented by ArsenalNut during GTC spoiler season. "T:Mode$ AttackerBlocked" should trigger multiple times for each blocking creature. I have not tested if these scripts are still working as supposed.
We actually need three triggers:
1. One that triggers only once per attacker (currently "AttackerBlocked"). Example: Alley Grifters.
2. One that triggers for each pair of attacker-blocker (currently "Blocks"). Example: No Quarter, Righteous Indignation.
3. One that triggers only once per blocker (a new trigger?). Example: Lairwatch Giant.
-
Sloth - Programmer
- Posts: 3498
- Joined: 23 Jun 2009, 19:40
- Has thanked: 125 times
- Been thanked: 507 times
Who is online
Users browsing this forum: No registered users and 15 guests