-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WIP: initial contributor documentation #18
Conversation
@@ -0,0 +1,95 @@ | |||
# Module Contributor Guide | |||
<special git conventions for the module?> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As of present none other than exists for all Terasology modules.
- Defence field with four entries and a shrine in the center | ||
- Field is filled with a random block pattern on the floor | ||
|
||
<can the world generator be extended?> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As of present no. There is a stretch goal to allow this as well as a bunch of other features like having multiple defense fields, each with different layout types.
|
||
### Towers | ||
Towers are block entities and contain a core, an effector and a targeter. | ||
<How are different towers defined and how can new towers be added?> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Towers themselves are not actually anything defined by the module.
They are all created from the block listed below by the player.
I have however considered adding in some preset tower designs, as well as allowing the user to 'save' a tower design to an item which then can then reuse elsewhere in the field. Does this seem like something that would be useful? It's not included in the main proposal but I could add it as a goal to work on after GSoC
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would a preset be like a combination of different effectors/targeters?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup. I would use Structure Templates.
#### Effectors | ||
Effectors represent the tower effect and cause a drain on the tower power. | ||
Most effectors can be upgraded via the upgrade system. | ||
New effectors can be created via prefabs and by extending the `TowerEffector` component. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a few more steps to it than that, in order to get the Effector functioning.
Firstly you'll need to make the new component. This needs to be a subclass of TowerEffector
and thus must either extend that, or some other effector. The benefits of extending an existing effector is that it allows you to build on fields defined within that. For instance, FireEffector
and PoisonEffector
both extend DamageEffector
, as they apply damage to the target and thus can reuse the latter.
An effector also needs to implement (or override if extending from another effector) the following methods
getEffectCount()
This method is used to indicate how many times the effect should be applied onto the target. The options are defined in the EffectCount
enum and are as follows:
PER_SHOT
: Every single time the tower attacks, this effector is applied.CONTINUOUS
: The effect is only applied when the enemy is first attacked.
getEffectDuration()
This method indicates how long the effect should last for. There are three options defined in the EffectDuration
enum.
INSTANT
: The effect has no duration.LASTING
: The effect has a duration for as long as the enemy is being attackedPERMANENT
: The effect has a duration, but it's not determined how long.
After that, the effector needs to be added to a block, this is the same as the method of adding a core block, and details are in that section.
Finally, a System needs to be created to apply the effect to the enemy. The system should listen for an ApplyEffectEvent
. This event will be sent against the effector itself, to allow for the system to filter for the correct component. The event will always only be sent with a single enemy target, with multiple events being sent for each enemy targeted.
If the effector has EffectDuration.LASTING
then a second event will be sent to remove the effect from enemies, RemoveEffectEvent
. This is the same as the prior event and is sent against the effector with a single enemy target.
Of note, is that the event will contain a strength multiplier, this should be used to weaken or strengthen an effect, and is used as a balancing tool on a per-targeter basis. It is gauranteed that the value will be the same for both the ApplyEffectEvent
and RemoveEffectEvent
The system may otherwise do whatever it needs to, in order to apply the effect. This includes listening for other events, injecting managers and other things common for a system.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I may end up changing effectors to use the Alteration Effects module in future. If I do, then the mechanism for extending effectors will obviously also alter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then we can document the current state and extend it later on :) The concept sounds solid.
One possible case which is harder with the enums could be an extension with special cases, e.g. effect count per second shot or effect durations based on special conditions. However this should be easy to change so we can keep it for now as is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool. I did poke around in Alteration Effects and it seems like it doesn't quite have all the functionality I would want, so I'd have to extend it anyway. Thus for now I'll stick with the current system
Most effectors can be upgraded via the upgrade system. | ||
New effectors can be created via prefabs and by extending the `TowerEffector` component. | ||
|
||
#### Targeters |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The method for extending this is similar to the effector with a few key differences, which will be outlined here.
Firstly, the component must extend TowerTargeter
. Likewise with effectors, the targeter can instead extend an existing targeter component. TowerTargeter
also includes some fields by default which are as follows:
drain
: The amount of power the targeter will consumerange
: The range of the targeter in blocksattackSpeed
: How often the targeter will attack, in milliseconds. Eg, 200 means it will attack every 0.2s, or 5 times a secondselectionMethod
: The method used to select a target, more info below. This should not be set in the prefabslastTarget
: The enemy targeted last attack, more info below. This should not be set in the prefabsaffectedEnemies
: All enemies effected last attack, used internally. This should not be set in the prefabs
The component must also implement (or override if extending an existing targeter) the getMultiplier
method. This returns a float which is passed to the effectors when they apply their effects. It's used as a balancing tool in order to strengthen or weaken effects. For instance, the Sniper Targeter has a high multiplier, but the Aoe Targeter has a low one.
The selectionMethod
of a tower is an optional enum that indicates how the tower should choose a target from the enemies within range. It is not required to be used. There are four possible options:
FIRST
: The enemy closest to shrineWEAK
: The enemy with the least healthSTRONG
: The enemy with the most healthRANDOM
: A random enemy within range
Following on from this a new block must be made. This is the same as effectors, prefab must extend GooeyDefence:PlainBlock
etc.
Lastly, a system must be created in order to actually select the targets to attack. The system should listen for the SelectEnemiesEvent
which will be sent against the targeter entity. A number of helper methods are provided in the BaseTargeterSystem
, such as getSingleTarget
which selects a single entity from a list, given the selection method to use; canUseTarget
which does a basic check to see if the enemy is within range and exists; and getTarget
which gets a single entity, based on the range, selection method and location of the tower.
EnemyManager
also contains a method to get all enemies within a radius of a position. It is not required to use any of these methods however.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know that I implemented components with private fields but I seem to remember that someone told me they are not supposed to have any methods. Maybe cervator or someone else closer to the gestalt library can clarify this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This particular concern is also in issue #8
<How are different towers defined and how can new towers be added?> | ||
|
||
#### Core | ||
The core defines the power level of a tower which can be affected with upgrades. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In order to extend a core, all that is needed is for the new component to extend TowerCore
or an existing core component.
After that, the core needs to be added to a block, this follows the standard method of adding a Terasology Block. The only requirements here are that the block have an associated prefab, who's parent is GooeyDefence:PlainBlock. This will ensure the block can be added to the tower and be breakable. (Although obviously the prefab should also contain the new component created as well) Best practices also include adding a DisplayNameComponent and a BlockUpgradesComponent. Details for the latter are included in the extending content section.
<how to add extra features with new modules> | ||
|
||
# Open Points | ||
- World size and properties are defined hardcoded in DefenceField, can be moved to a configuration prefab |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a good suggestion an I will attempt to do this. However, do you know of a way to retrieve a prefab from a static context when the module is loaded?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That does seem like it would be perfect for doing that.
Issue #21 has been opened for this.
|
||
# Open Points | ||
- World size and properties are defined hardcoded in DefenceField, can be moved to a configuration prefab | ||
- Shrine template could be extracted to something else than hardcoded block positions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is something I also wish to do. I considered Structure Templates, but that would be adding the whole module just for the shrine, and I'm unsure if you can use it in world generation.
If I end up adding in template functionality for the towers, then I will also switch this across to use a Structure Template.
# Open Points | ||
- World size and properties are defined hardcoded in DefenceField, can be moved to a configuration prefab | ||
- Shrine template could be extracted to something else than hardcoded block positions | ||
- Paths all entrances in PathfindingManager can be stored in something more readable than a List of Lists |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there any data structures you suggest using in place of a 2d list?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A custom class which provides the methods you need (something like List<Vector3i> findPathForEntrance(int)
?) would work :) you can use the nested list inside.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you feel this would improve readability then I can easily change it across. Issue #22
- Shrine template could be extracted to something else than hardcoded block positions | ||
- Paths all entrances in PathfindingManager can be stored in something more readable than a List of Lists | ||
- EnemyWalkingPlugin.areAllBlocksPenetrable is a code duplication with a part of the WalkingPlugin from FlexiblePathfinding. | ||
The method could be extracted in flexible pathfinding and then reused in GooeyDefence. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will take a look at the duplication and see what I can extract into a method.
Superseded by #65 |
First draft of a contributor documentation with the goal to describe the high level concepts and give a first entry point for further module extensions or submodule development.