-
Notifications
You must be signed in to change notification settings - Fork 7
Missions (Achievements and Quests) System
The MissionManager
is a class which manages and tracks all in-game Mission
progress. It stores an array of all Achievement
s, a list of active Quest
s* (Quest
s that the player is currently attempting to complete), and a list of selectable Quest
s (Quest
s that the player is able to accept, although has not started).
* Note: Completed quests are to be deleted once their reward is collected
The MissionManager
provides the following publicly accessible methods which all classes can use to interact with the system:
-
MissionManager()
(constructor) - callsregisterMission()
on all achievements in the array. Also sets up listening for hourly events with theTimeService
and adds thehourUpdate()
method as the event handler for this event. -
addQuest()
- adds aQuest
to the list of selectableQuest
s -
acceptQuest()
- accepts aQuest
by removing it from theselectableQuests
(if inselectableQuests
), adding theQuest
to theactiveQuests
, and by calling itsregisterMission()
method -
getEvents()
- returns a reference to theMissionManager
’sEventHandler
-
getSelectableQuests()
- returns theList
of selectableQuest
s -
getActiveQuests()
- returns theList
of activeQuest
s
The MissionManager
will update the time to expiry for all active Quest
s via the private updateActiveQuestTimes()
method. This method will only update the expiry for all active Quest
s, using the Quest
s’ updateExpiry()
methods. This method also checks if any mandatory Quest
s have expired, and call a game over if so.
Additionally, when a Quest
is added to the MissionManager
’s List
of selectable Quest
s (the event triggered is given by MissionManager.MissionEvent.NEW_QUEST.name()
). The MissionManager.MissionEvent.QUEST_EXPIRED.name()
event is triggered when a Quest
expires.
The Mission
class is an abstract class, which can be extended to specify an in-game mission (including an Achievement, Quest
or MandatoryQuest
. It stores all information related to the mission, and contains methods to allow the MissionManager
to determine whether the player has completed the mission.
The following methods have a default implementation:
-
getName()
- returns the name of the Mission -
notifyUpdate()
- triggers theMissionManager.MissionEvent.MISSION_COMPLETE.name()
event on theMissionManager
’sEventHandler
if theMission
is completed (as determined by the implementation ofisCompleted()
). This should be called any time aMission
’s state is updated
Below are descriptions of a variety of methods which should be overridden by anyone who would like to create their own in-game Missions.
The registerMission()
method is called when the Mission is registered to the MissionManager
. In this method, you should add all of the event listeners to the MissionManager
which your Mission will listen to (see the Event listeners section for more details), using an enum from the MissionEvent
enum class.
Say, for instance, you would like your Mission to listen to the “plant” event (triggered when a plant is planted, and given a reference to the type of plant planted), then you would add the following line to your Mission
’s registerMission()
method:
ServiceLocator.getMissionManager().getEventHandler().addListener(MissionEvent.PLANT);
When an Mission
is registered to the MissionManager
, it should begin listening to events on the MissionManager
’s EventHandler
. The idea is that certain interactions and occurrences in game may cause events to be triggered. Internally, the Mission should have methods which update the state of the tracked stats when certain key events are triggered (e.g., the planting of a corn crop causes an Mission to increment an int numCornCropsPlanted
property through some private method).
Returns a boolean value, representing whether an Mission has been attained by the player. This should be overridden by any Mission
class to specify the criteria for which an Mission has been reached.
Returns a string description of the Mission
. This should be overridden by any Mission
class. If you would like the Mission to display information about the player’s progression through the Mission, this should be included in the text description returned by this method.
Similar to getDescription()
, although should return a shorter description of at most 50 characters, to be displayed in the mission NPC’s UI before the player chooses to view a Mission
in its entirety.
This method returns an object which holds information about the progress of the mission (any stats tracked by the Mission
which change overtime).
The returned object should be easily serialized by libGDX's Json
serialiser. The best options are returning primitive types (e.g., int
, boolean
), String
s, or Array
s of these primatives. Basic classes packaging these serialisable types are also easily serialised by the Json
serialiser. For more information, read the libGDX wiki.
This should read a JsonValue
storing the progress of the Mission
. The precise JsonValue.ValueType
of this JsonValue
is given by the type of object returned in getProgress()
(e.g., if you returned an Integer
in getProgress()
, you can safely call jsonValue.asInt()
and expect no errors to occur). Read the javadocs for JsonValue
for more information on how to read from a JsonValue
(you should also use this to inform how you implement getProgress
).
Many examples of how these 2 methods should be implemented now exist in the quests
package, so look there (or ping team 7 in discord) if you need more help.
Achievement
s are abstract missions which are tracked statically throughout the course of the game. Once a player completes an achievement, it is completed permanently.
It also contains a write()
method for save/load purposes. See the save/load wiki page for more details.
Quest
s are abstract missions with the addition of a Reward
class instance property representing the reward that one gets from completing the Quest
. Quest
s, also have a time limit, and store an int
duration representing the number of hours the Quest
should active before it expires (the actual amount of time left before the Quest
expires is stored in timeToExpiry
).
As of Sprint 3, a secondary constructor was added to the Quest
class. This constructor does not have the parameters int expiryDuration
or boolean isMandatory
. Quest
s made with this constructor never expire, and are made to be non-mandatory. This constructor is currently used for all story-quests which aren't MainQuest
s. We recommend you do not create Quest
s with this constructor unless it is a story Quest
, since non-mandatory Quest
s should probably have an expiry duration as per the original vision of the mission system.
It provides the following method implementations by default:
-
isExpired()
- returns aboolean
value, representing whether thisQuest
has expired. If thisQuest
can't expire it will always return false. -
isMandatory()
- returns aboolean
value, representing whether thisQuest
is mandatory. MandatoryQuest
s will result in a game over if not completed before expiry -
collectReward()
- callscollect()
on thisQuest
’s reward instance if theReward
is uncollected and theQuest
is completed -
updateExpiry()
- decrements the expiry time by 1 hour if thisQuest
can expire and is not completed (otherwise it will do nothing) -
resetExpiry()
- resets the expiry time for theQuest
, but resetting thetimeToExpiry
variable, and calling theresetState()
method -
resetState()
- an abstract method which, when implemented, should reset the internal state of theQuest
’s stats (for instance, when an expiredQuest
gets reactivated) -
isRewardCollected()
- returns aboolean
value representing whether thisQuest
'sReward
has been collected.
This class also provides an override for notifyUpdate()
, so if the reward of a Quest
has been collected, the Alien NPC is no longer notified of Quest
completion (otherwise completed Quest
s whose Reward
has been collected would continually notify the Alien NPC that a new Quest
has been completed).
The methods read()
and write()
also exist for save/load purposes. Refer to the save/load wiki page for more information.
Any Quest
class implementation created by members of the studio should be instantiated by a method in the QuestFactory
(found in the quests
package). You can call these methods in other methods in QuestFactory
. That is, you should make your Quest
s be Reward
s (using the QuestReward
class) for completing various story Quest
s in game. We recommend introducing your non-story Quest
s in Act II or Act III of the game.
The MissionEvent
enum is an enum class which stores all events handled by the MissionManagerService
’s EventHandler
. Each enum corresponds to a string representation of the event. This decision was made to reduce the chance that an event listener or trigger is mis-typed, and allows the precise string representation of these events to change easily.
The Reward
class is an abstract class representing an in-game reward which can be collected as a result of completing an Mission. The public isCollected()
method is provided by default, and returns true
iff the reward’s collect()
method has been called.
This method executes the logic associated with collecting this Reward
. This may include adding some items to the player’s inventory, permanently boosting a player’s stat, or enabling some in-game progression.
Below is UML overview of the core classes in the system (ignoring specific implementations).
Here is a UML diagram showing the core Quest
classes implemented for the main storyline of the game (that is, the MainQuest
, AutoQuest
and the QuestReward
which triggers them). See the storyline wiki page explaining how the storyline is told in the game. For more information about all of the specific Quest
implementations for the storyline of the game, please read the JavaDocs
Here is a UML diagram showing the Reward
classes implemented for the main storyline of the game. See the storyline wiki page explaining how the storyline is told in the game. For more information about all of the specific Reward
implementations for the storyline of the game, please read the JavaDocs
The classes MissionManager
, Mission
, Achievement
, Quest
and Reward
all have 100% testing code coverage except (as of Sprint 3) methods made for save/load purposes (read
/write
methods). Quest
class implementations made for the storyline of the game (i.e., implemented by team 7 for Sprint 3) have 100% coverage. Most Reward
s made for the storyline of the game (i.e., implemented by team 7 for Sprint 3) also have 100% coverage, except for TriggerHostilesReward
and DialogueReward
, which contain portions of logic implemented by other teams. These classes will be covered by tests early in sprint 4, once the other teams have added their logic.
Studio members are welcome to and are encouraged to add JUnit5 testing for any Achievement
s, Quest
s or Reward
s they add. In-game testing is also necessary for these Mission
s.
In a previous iteration of the Missions System design, the way through which Quest
s would offer Reward
s to the player was different. Instead of a Quest
simply being complete or incomplete (and only allowing the player the ability to receive a reward upon the completion of the entire Quest
), the team considered implementing Quest
completion through the use of Milestone
s.
Milestone
s were an abstract class which had names, descriptions, and rewards. They would define a subset of the Quest
that needed to be completed to attain their reward, meaning the player could receive multiple rewards for a single Quest
.
This idea was scrapped, as it would require studio members creating a Quest
to implement and create a string of Milestones
for each Quest
, which would not only reduce the flexibility of the system, but also introduce additional complexity to the process of adding Quest
s.