|
Post by Multiple abiltiies on Jun 8, 2018 5:30:29 GMT
does anyone know how i would make it so that i could have multiple abilities added to this
for instance draw a card and deal 2 damage
orr even maybe even more difficult
deal 2 damage and increase attack by 2 or something like?
i am thinking to in the json have 2 abilities { 1 that deals 2 damage which already exists in the game and the other 2 increase the attack by 2....the problem is im not sure how that would look as far as the coding goes - 2 abilities could cause dictionary issues?
|
|
|
Post by Admin on Jun 8, 2018 12:51:58 GMT
It's not a problem to add more than one ability. If you look at the JSON the "abilities" key is already configured as an array of dictionary. If you're not familiar with the syntax, notice that the root level "cards" is also an array of dictionary. You just use commas to separate such as this example showing an array of two dictionaries:
[{ key: value }, { key: value }]
In short, simply add another dictionary in the "abilities" array to add another ability to the card. I cant remember if I already programmed support for multiple abilities when the card is being played, but if not, it shouldn't be hard to modify logic to be in a loop so that it can. Try it out and let me know if you get stuck.
|
|
|
Post by Multiple abilities on Jun 14, 2018 5:33:07 GMT
Hmm yaa i tested it out - i dont think json would have an issue my issue and what i was thinking was the dictionary key being duplicate which i am getting
"abilities": [ { "action": "DrawAction", "info": 1, "targetSelector": { "type": "ManualTarget" } }, { "action": "DamageAction", "info": 2, "targetSelector": { "type": "ManualTarget" } } ]
dont know if i need that targetselector yet but have it in there - not sure what will happen exactly but im not even at that point yet- ill get to that targetting logic when i can add the ability to the card.
basically i am getting duplicate Key: Ability - so the key name is Ability of the dictionary trying to find where this dictionary is created - pretty sure it would be deckfactory but still looking - as i thought it might be addabilities but cant find it --- its somewhere in and between the addabilities and the mechanics cause i can put a debug statement in there and i dont get the output instead i get the duplicate key error
|
|
|
Post by Admin on Jun 14, 2018 13:23:58 GMT
Gotcha, I went ahead and tried it so I would see the same issue. The problem is in the way that an ability is attached to a card. If you look in the "DeckFactory" there is an "AddAbilities" method that looks like I had considered the need to support more than one ability per card. However, within the loop each parsed ability is added to the card via "AddAbility" which attaches the ability to the card as an "aspect". The aspect container is just a dictionary, and if you use the simple generic method like I did here, then it will use the name of the generic type itself as a "key" to add the "value" with. This is why it fails when trying to add the second ability, because it cant reuse the generic ability key. There are a couple of ways to solve this:
1. You can provide your own key so there is no naming conflict - such as by giving each ability its own "id" and using that to add it to the card with. The downside to this approach is that it becomes slightly more difficult to get the ability again later, since you need to loop over all the aspects of a container and check their type.
2. You could create a new aspect, perhaps one called "ability container" which holds an array of ability. Then the ability wouldn't need to be an aspect itself. Just make sure all cards have this aspect, and when adding the ability to the card, get a reference to the container and append it to the array.
Either approach will likely require you to refactor code elsewhere in the project. It's a great challenge to learn with though, so I hope you give it a try!
|
|
|
Post by Legend on Jun 14, 2018 20:14:54 GMT
Order maybe instead of adding another ability...within the ability allow for multiple actions...so like have a key for multaction : actionname
Then do something like call the action when loading it or something...think that would work and wouldn't have to restructure to much...would have to do some if not nulls for the single ability cards
|
|
|
Post by Admin on Jun 15, 2018 13:27:56 GMT
That could work, but keep in mind that each action of the ability may need its own targeting as well. For example, a spell which destroys an enemy, then gives the enemy's HP to the caster. It might be hard to tell the line between what an action is and what the ability is, but so long as you consider all of your intended functionality it could work.
Also, if I were going to take this approach, I would want to refactor the card's ability in the json to not be an array. Then I would make the actions of the ability an array. Then there is no need to worry about nulls, you simply put the logic in a loop over the actions found.
|
|
|
Post by Arghonaut on Jun 23, 2018 21:50:33 GMT
Firstly - Thankyou for the blog posts, inspired me to dust of an old single player CCG idea. I came on here to ask about something else and saw this post, and i'm happy to see the way i ended up implementing multiple abilities is a way you suggested. I went with your second approach - an Abilities class that implements IAspect and has a list of Ability. Then changed the Ability class so it's still a container, but is no longer an aspect. Then I implemented a trigger system, and an enum of triggers, and added a trigger to the ability class:
[Flags] public enum Trigger { None = 0, OnEnterPlay = 1 << 0, //battlecry EndOfTurn = 1 << 1, OnDeath = 1 << 2, //deathrattle StartOfTurn = 1 << 3, OnOpponentSpell = 1 << 4, OnAllySpell = 1 << 5, OnAllyMinionDeath = 1 << 6, OnOpponentMinionDeath = 1 << 7, OnAttack = 1 << 8, OnAllyMinionAttack = 1 << 9, WhenAttacked = 1 << 10, WhenTargettedBySpell = 1 << 11, OnAnySpell = OnOpponentSpell | OnAllySpell, OnAnyMinionDeath = OnAllyMinionDeath | OnOpponentMinionDeath }
The Triggersystem class caches a list of all abilities in play(via minion summon / death notifications), and subscribes to every appropriate notification with a "CheckForTrigger" method that checks for a valid trigger event, and if found, adds it as a reaction. Seems to be working well so far!
|
|
|
Post by Admin on Jun 24, 2018 23:52:51 GMT
Sounds like a good approach Arghonaut, and I'm glad to hear you've got it all working!
|
|
|
Post by Arghonaut on Jun 25, 2018 10:22:49 GMT
The class started getting pretty big so i broke it down further, I created an abstract AbilityTrigger class that has a list of abilities and a protected ApplyTrigger method that applies the reaction, and a derived class for each game action that can trigger reactions. The TriggerSystem class adds and removes abilities to each of these derived classes as minions/abilities enter/exit play via summon, death, polymorph, silence etc. Feels much tidier now, each derived class only has to subscribe to the one notification type, and handles the logic for all triggers that react to it. For example, a change turn action can trigger end of turn and start of turn triggers. Now only have to look through a list of abilities with triggers for that game action, instead of a list of every ability in play, to find a valid trigger.
Your posts really helped me think about where logic should go. My previous method was pretty much to put it wherever it had access to the information it needed...which meant i inevitably ended up with a "Game Manager" singleton thousands of lines long. So much easier working with this approach. I can already see how these systems will make implementing secrets a breeze because of the compartmentalisation (is that even a word?).
|
|
|
Post by Admin on Jun 26, 2018 14:38:07 GMT
That's perfect - anytime a class starts growing I also start looking for ways to break it up. I'm really glad you've got the inspiration and motivation to try adding new features, and I hope secrets work well for you! You were close, "compartmentalization" is a word
|
|
|
Post by Legend on Jul 5, 2018 11:59:22 GMT
nice Arghonaught!
I might add a few more triggers for some other abilities as well for the future
OnDraw OnDiscard OnDamaged OnHealed
going to eventually give the secrets a try (although its going to be a little bit different) but gotta try to release the game first and will probably be in an update - along with multiple abilities in a card - alot of other stuff to do right now - but this helped me out alot to get a good idea for the future!
|
|