Here is the description of the Ability/Effect module of the game, to allow everyone to create new abilities for the game.
Typographical convention: As the same word can have different meanings, I'll try to use some convention to distinguish these meanings. For example, "Ability" means the Ability class of the java code (or maybe an instance of this class) while "ability" is the ability as seen from the game design point of view (the word in the common language and not in the programming meaning).
1) How things work (roughly)
Each character has abilities. This is represented by each Character having a List of instances of Ability.
These instances are "owned" by the Character, and not shared with other Characters.
But the code of the class Ability only contains the cast/cooldown mechanism and, it does not contain the actual "effects" of the ability. This is where the Effect class comes in.
The instances of the Effect class contain the code that will apply modifications to the gameContent. By design, and due to the fact that anonymous lambda functions are not serialisable, most of the components of the Ability/Effect system use keys to define what they do, rather than actual code. Whenever the Ability is cast, the server is notified of it, get the keys of the Ability, uses its factories to generate the relevant Effects, thanks to the keys, and execute these Effects. The keys: Several enums are used as keys in the factory patterns implemented in the Ability/Effect modules, here is a list of them, and the concepts they are bound to:
- AbilityKey: represent an ability (from game design perspective). They are bound to Supplier (the type of functions that can generate instances of Ability by calling their "get" method) in the AbilityFactory.
- EffectKey: bound to EffectGenerators (see below) in EffectFactory.
- Abilities can only be attached to Characters
- Abilitites and Effects can only impact Characters
2) The plan of this page
- I) Overview
- II) Definition of the concepts
- III) These concepts in action
- IV) How to design new abilities
II) Definition of the concepts
Here is the main method of an Effect, which defines a modification of the gameContent:
/** * What the Effect does to its targets, in a given gameContent * @param targetCharacterIDList a List of the IDs of the Characters to apply this effect on * @param gameContent the gameContent in which the target characters lives * @param casterCharacterID the ID of the Character that casted the Ability containing this Effect */ abstract public void effect(List<Integer> targetCharacterIDList, GameContent gameContent, int casterCharacterID);
For example a damage effect will query the gameContent for for the Characters that have the ID stored in targetCharacterIDList and remove let's say 5 HP to each of them.
b) How Effects can be defined/created
Effects are built using the methods from EffectBuilder and composing them. There are "base case" methods, that just produce an Effect that does something to the gameContent, and there are "induction" methods, that takes an existing Effect, plug something before it and create a new Effect whose effect method does this. To illustrate this, here is an extract of the documentation of the "randomTest" method:
* Take an instance of Effect and return another instance of Effect that, for each Character it receives as input, * makes a random test that has chances/outOf probability of success. On a success, the character is added to a list l. * After this loop, the original Event is applied to the list l.
Here is the doc on them:
* Contains an EffectKey and an array of int. The EffectKey defines an Effect (basic or composed), and the array of int * is the set of parameters required by the Effect to be instanciated.
An EffectDescriptor contains all that is needed to instanciate an Effect from the EffectFactory. The effects an ability has are defined thanks to a list of EffectDescriptor in the Ability.
Here is the doc on them:
* The type of functions able to generate instances of Effect out of the ID of the character that cast the ability triggering this effect, * and a given number (this number depends on the actual EffectGenerator instance) of int values, provided in an array.
The Ability class essentially contains:
- The cast/cooldown mechanism
- A key (a member of the AbilityIconKeys enum) to define which icon should be displayed on the player's screen to represent the ability
- A member of the Action enum (used to animate the character when she casts the ability)
- A list of instances of EffectDescriptor
The Abilities a Character has access to depend on his Specy (every Character is created from a Specy).
III) These concepts in action
So, here is what happens under the hood where the player presses the 'A' keys on his keyboard. The "Followed Character" (and by extension the "Followed Relayer") corresponds to the Character the player is playing.
- Player presses key 'A'
- The signal goes through the gui modules, which calls the "tryToCastAbility(0)" method of the followed Relayer. The '0' is the number (in the list of Abilities of the followed Character) of the ability being potentially cast. The '0' corresponds to the first weapon ability (which is mapped to 'A' by default).
- Through processes I won't describe here, the followed Relayer sends a new AbilityEvent(CasterCharacterID, 0) to the server (note that there wasn't a cooldown check, this will be done on the server)
- Execute the received AbilityEvent: Gets the local instance of Ability corresponding to the ability cast by the followed Character and call its "cast" method.
- The "cast" method checks the cooldown and return a list of EffectDescriptor. It's a null if the Ability was not ready to be cast. Otherwise, it's simply the list of EffectDescriptors that the Ability contains.
- If the EffectDescriptor list was not null, add the Action defined in the Ability to the caster Character (for animation purpose)
- For each EffectDescriptor in the list:
- Use the local EffectFactory to generate an instance of Effect corresponding to the EffectDescriptor
- Call the "effect" methods of the newborn Effect, passing as arguments a List containing only the ID of the caster Character, the GameContent and the ID of the caster Character. This applies the Effect and modify the GameContent accordingly.
- The AbilityEvent is sent back to all the clients, so that they can update their GameContents
IV) How to design new abilities
Normally, if you make any mistake (declaring unconsistent things), an exception will be thrown just after launching Igniter_Main, telling you what was wrong. So you can try->fail->learn alone. If you have questions, then keep them for yourself and, above all, DO NOT TELL THEM TO ANYONE.
Yes, I'm joking. Feel free to ask questions.
1) How to design (and register at the EffectFactory) new Effects
Go to EffectGeneratorRoster and copy-paste a block of code. Then modify. Go to II)/1)/b) for additional help. Note that in order to register your newborn EffectGenerator, you'll have to define a new key in EffectKey.
2) How to design (and register at the AbilityFactory) new Abilities
Go to AbilityRoster and copy-paste a block of code. Then modify. Note that in order to register your newborn AbilityGenerator, you'll have to define a new key in AbilityKey.
3) How to add an Ability to a Character
Note: you'll have to add the Ability to the Specy the Character is built on, rather than on the specific Character. Go to the file "species.txt" (where species are defined), and look for the line "#abilityList" under the Specy you want to modify, then modify the AbilityKey listed under it. Currently, only the first Ability can be tested in game (with the 'A' key).