1. Introduction
1.1. Learning Outcomes
After completing this assignment, you will have learnt to:
Design a class hierarchy using UML
Apply Object-Oriented principles (encapsulation, reuse, etc.) and Design Patterns to the
software design
Implement the software design in C++ using class inheritance and polymorphism features
Write well-behaved constructors and destructors for C++ classes
Use C++ pointers (including smart pointers) and dynamic memory allocation and
management
Use stream I/O and manipulators for formatted input and output
Write code adhering to coding standards, guidelines and good programming practices
2. Task Description
Roguelike Dungeon Crawler games are a genre of game that exhibit features typically attributed to the 1980s computer game Rogue [https://en.wikipedia.org/wiki/Rogue_(video_game)]. In general, the goal of a Roguelike game is to clear a dungeon, level-by-level, until the final level is completed. Common features of a Roguelike game include:
procedurally generated dungeons,
randomised items and weapons,
permanent death, and
a variety of creatures to fight that get progressively more difficult deeper into the
dungeon.
Within each level of a dungeon there typically exists distinct rooms where creatures are encountered and items are waiting to be looted.
In this assignment, you will design and implement a simple text-based Roguelike Dungeon Crawler game that fulfils the following specification. Unlike the original Rogue, text-based does not mean ASCII art but instead will be driven by a text-based menu interface inspired by another genre of text-based adventure game originating from Multi- User Dungeon (MUD) [https://en.wikipedia.org/wiki/MUD1]. Moreover, combat will be
turn-based with only one opposing creature at a time.
The aim of the assignment is to allow you to practise creating an object-oriented design and implementing it in C++ using the features learnt so far, namely: class inheritance and polymorphism, dynamic memory allocation, and smart pointers. The focus of the assignment is on identifying and applying appropriate Design Patterns to help develop the game in such a way that components are easily reusable and extensibleremember the DRY (Do Not Repeat Yourself) principle.
In this second part of the assignment you will need to implement the game in
C++ based on the requirements in the remainder of this specification and the design you created in the first part of the assignment. Strict adherence to your initial design is not required, but it is good practice to follow a design when performing your implementation
and to maintain it to be consistent with your code if you determine changes need to be made. Additionally, you should review your design against the rubric for the UML Class Diagram, which will be released after the due date of the UML Class Diagram component. The rubric will provide you with indicators of how your design can be improved to help you perform your implementation. Once the marking of the first part is complete, you may want to incorporate the feedback to further improve your design and implementation.
You will be provided with an initial Dungeon Crawler Qt Creator Project containing skeletons of the original classes with some provided functions matching what was illustrated in the provided UML Class Diagram. Some of the underlying elements (such as the basic menu interface code) is provided to get you started; however, much of the provided code will be incomplete and needs to be modified to fit your class design. Parts of the provided code that must not be modified will be marked as such.
For this assignment the game has been simplified to a certain extent, e.g., dungeon creation is not completely procedural. A brief example of how the game will be played is provided below. For additional examples, please play through the Dungeon Crawler Reference Implementation provided. The text descriptions of your implementation do not have to exactly match the reference implementation, but you may use it as a guide to see how the user interaction works and the game plays out. The remainder of the section describes the requirements of the game in more detail.
Note: the following conventions will be used when illustrating example output:
a > at the beginning of a line indicates the command line prompt
bold orange text indicates input entered by the user
user input surrounded by square brackets [] indicates a specific key press
hitting after other input is implied
[Enter]
> dungeon_crawler.exe
Welcome to Ashes of Software Development: Rite of Passage!
Developed by Matt Selway
COMP 3023 Software Development with C++
*Press any key to continue* > [Enter]
What would you like to do?
(p)lay the game
(q)uit
>p
You need to create a character what is your name? > Dungeon Crusher
Welcome Dungeon Crusher, you have *6* stat points to allocate. A high Strength stat will boost your damage in combat.
How many points do you want to add to your Strength?
>3
You have *3* stat points remaining.
A high Dexterity stat will increase your ability to dodge creature attacks. How many points do you want to add to you Dexterity?
>2
You have *1* stat point remaining.
A high Wisdom stat will boost the effectiveness of magical items. How many points do you want to add to your Wisdom?
>1
*** Character Summary ***
Dungeon Crusher
Strength:
Dexterity:
Wisdom:
Health:
Damage:
Dodge:
Weapon:
4 3 2
50 / 50
10 10
20%
you look down at your fists and shrug, these will do
While roaming the country side you encounter a strange fork in the road.
To the left lies a dark cave, the foul stench of rotting flesh emanates from it. To the right is a mysterious tower, a strange magical energy lights the path. What would you like to do?
Go left: create a (b)asic dungeon
Go right: create a (m)agical dungeon
(r)eturn the way you came: back to main menu
>b
You enter the dark cave and see
A dark and empty chamber.
To the NORTH you see an opening to another chamber.
To the SOUTH you see the entrance by which you came in. What would you like to do?
Go (n)orth
Go (b)ack the way you came
View your (c)haracter stats
Return to the main (m)enu
>m
After exploring *0* levels, you run out of the cave as quick as your legs can carr y you.
As you emerge from the cave you are startled by the bright light and pause while y our eyes adjust.
What would like to do?
(p)lay the game
(q)uit
>q
*Are you sure you want to quit? (y/n) * >y
Goodbye!
The description that follows is the detailed requirements necessary to perform your implementation of the Dungeon Crawler game.
2.1. Work Plan
Important: All classes and functionality that relate only to the Magical Dungeon type are optional, including the builder class, rooms, walls, weapons, etc. They are not required to complete this assignment. Some bonus marks are assigned if the Magical Dungeon type and its components are implemented. See section Dungeon Types for the table of classes and to which dungeon type they relate.
To complete the second part of this assignment, you will need to perform the following steps:
1. Readtheassignmentspecificationcarefully.
2. ReadtheImplementationRulesandHintsSectionagain.
3. FamiliariseyourselfwiththeprovidedDungeonCrawlerQtCreatorProject.
4. Initialise a Git repository within the project folder.
5. ImplementcharactergenerationrefertosectionPlayerCharacter
6. Implement the basic dungeon classes, including their creation according to the
standardised layout: walls and doors only, no creatures nor weaponsrefer to section Dungeon (Rooms, Walls, Doors) for component structure and
sections Dungeon Types and Standard Dungeon Layout for their construction.
7. Implement dungeon navigation: at this point you should be able to play the
game and transition between rooms and dungeon levels without combatrefer to sections Dungeon (Rooms, Walls, Doors) and General Gameplay
8. AddweaponsandweaponpickupsfocusingonthoserequiredforBasic Dungeon onlyrefer to sections Weapons & Enchantments and General Gameplay. Suggestion: Start with the core weapon components then add enchantments later.
9. Implement the CsvFile class according to the provided test casessee
sections Creatures and Loading Data From CSV.
10. Implement creatures and populate the dungeon with creatures according to
the standardised layout, no combat yetrefer to sections Creatures and Loading
Data from CSV.
11. Implement combat interactions: you should now be able to play the game with
all general gameplay requirements/features complete (except the second dungeon
type)refer to section Combat.
12. (Optional) Implement the second dungeon type: Magical Dungeon and all of its
componentsrefer to section Dungeon (Rooms, Walls, Doors) ; also see Weapons & Enchantments and Creatures, if you have not yet implemented the dungeon type specific elements of those sections.
13. Generate Doxygen-based HTML documentation.
Important: As you implement the functionality you should tick, highlight, or otherwise mark the requirements that you have completed. This will help you keep track of your progress and ensure you have addressed all of the requirements in your submission. If you are unsure of a requirement, ask and/or use the reference implementation for
guidance.
After completing the implementation (or even earlier) be sure to generate your HTML documentation from your Doxygen comments included in your project files. You will then need to gather your entire project, including the git repository, and submit it to LearnOnline. See section Submission Details for the full requirements of submission.
Note: The above sequence of tasks is a suggestion that will lead you through a logical progression of incremental functionality until you have a completed game. It is highly recommended that you follow the suggestion to maximise your marks, as marking is allocated based on functional completeness. For example, completing all of the structural elements for all classes (i.e., data members and constructors) without any game
functionality will receive less marks than having some game functionality that only incorporates the structural implementation necessary to achieve that functionality.
2.2. General Gameplay: Overview
The gameplay state will be controlled by a Game object. There can only ever be one game in play at one time, i.e., it is a Singleton. The user interaction will be performed
through the MenuInterface class. Many of the general requirements describe the
functionality in terms of the user interaction, you will need to implement both the menu interactions and the actions that they trigger. Be sure to keep the responsibilities in the correct location, i.e., gameplay state is managed by Game and IO is handled
by MenuInterface . Most of the interactions will result in delegating to the Game object. Some constraints of the menu interface are detailed in the Menu section.
When the term game is used in lower-case, we are referring generically to the application, while Game is explicitly referring to the class.
The game allows the user to create a player character ( ) and to explore a
dungeon of the users choice, room-by-room. Along the way they may encounter creatures that they will have to defeat before they can continue exploring (unless they can find a way around them). They will also come across weapons to loot that will help them defeat the creatures they encounter. The last room in the dungeon typically has a more powerful monster (a boss monster) that needs to be defeated for the exit to reveal itself.
There are two types of dungeon that the user can explore: a basic dungeon
( BasicDungeon ), and a magical dungeon ( ). Each dungeon type will be
populated with their own sets of room types ( and its class hierarchy), creature
types ( Creature and its class hierarchy), and weapon types ( Weapon and its class hierarchy). Each of these elements will require descriptions that are displayed to the
user as they traverse the dungeon and encounter them.
2.3. General Gameplay: Starting a Game
When the game is first started, a welcome message will be displayed and the user will be given the option to play the game or quit from the main menu.
MagicalDungeon
Room
Character
Note: You must specify the values of AUTHOR and TITLE at the top of main.cpp to give
your game a name and say by whom it has been developed. You do not need to modify anything else in main.cpp .
If the user chooses to quit, the game will prompt the user to confirm that they want to quit:
If the user selects yes, the game will end
If the user selects no, the game will return to the main menu
If the user chooses to play the game (from the main menu), the game will prompt the user to create character. Refer to section Player Character for details of character creation.
After the user has created their character, the game will prompt the user for the type of dungeon they would like to explore. There must be three options: a basic dungeon,
and a magical dungeon, or go back. Refer to section Dungeon (Rooms, Walls, and Doors) for details of the types of dungeon and their construction.
If the user chooses basic, the game must create a BasicDungeon object according
to the standardised layout
If the user chooses magical, the game must create a BasicDungeon object
according to the standardised layout
If the user chooses go back, the game will return to the main menu.
If a dungeon is created, the game must place the character in the first room, display that rooms description, and prompt the user for the next action.
2.4. General Gamplay: Playing the Game
To play the game, the user must be able to take one of several actions in each turn. The exact options that are available depends on the configuration of the room (i.e., which sides have doors), whether a creature and/or item is present, and the weapon the character currently possesses. The user must be able to select from the
following actions as appropriate:
1. Movethecharacterinagivendirection:North,South,East,orWest
2. Movethecharacterbacktothepreviousroom(whetherthisisNorth,South,
East, or West depends on the door the user came through)
3. Pickupaweapon
4. Compare the weapon in the room with that currently held by the character
5. Attackthecreature
6. Usetheweaponsspecialability
7. Returntothemainmenu
1.
If the user chooses to move North, South, East, or West, and there is a traversable door in that direction: the current room will be updated to the room that was selected, the new rooms description will be displayed, and the user prompted for the next action. If there is no door in the selected direction, nothing happens and a message may be displayed to the user.
2. If the user chooses to return to the previous room, the current room will be updated to the previous room, the rooms description will be displayed, and the user prompted for the next action.
3. If the user chooses to pick up a weapon, the game will prompt the user to confirm as it will replace their existing weapon. If the user says no, nothing happens; if the user says yes, the characters current weapon is removed and replaced with the item from
4.
5. 6. 7.
the room: the room will no longer have an item.
If the user chooses to compare weapons, the description and stats (minimum and maximum damage) of both weapons will be displayed. It must be clear which weapon is currently owned by the character and which is present in the room.
If the user chooses to attack the creature the rules for combat will be applied. Please refer to the Combat section for details.
If the user chooses to use the weapons special ability, the abilitys effect will be applied. Refer to section Weapons & Enchantments for details of each special ability.
If the user chooses to return to the main menu, the game will prompt the user for confirmation warning that the action will lose all progress for the character.
a. Iftheusersaysno,theuserwillbepromptedtotakeanaction.
b. Iftheusersaysyes,thenumberofdungeonlevelssuccessfullycompletedmust be displayed followed by the main menu, and the current dungeon and character
must be made unavailable (i.e., choosing to play the game again will behave as describe in Starting a Game above).
Restrictions on Actions
There are several restrictions on what actions can be taken in what context, summarised in the table below. You can handle these restrictions by hiding the actions from the menu or by displaying an appropriate failure message if the user attempts to perform an action that is not allowed.
Note that the disabling condition overrides any enabling conditions. E.g., if a weapon and
creature is present in a room, the weapon actions are disabled.
Action Restrictions
Action Allowed When Disabled When
Move in direction: NORTH, SOUTH, EAST, WEST
Door is traversable in direction
Creature is present
Move back to previous room
Always
Pick up weapon
Weapon is present
Creature is present
Compare weapon
Weapon is present
Creature is present
Attack the creature
Creature is present
Use weapons special ability
Weapon has special ability
Special ability is a damage effect
and no creature is present.
Return to main menu
Always
2.5. General Gameplay: Ending a Level and Other Considerations
Once the user reaches the final room of the dungeon level (i.e., the room with
the exit door), the user will be able to finish the level by selecting the direction (NORTH, SOUTH, EAST, or WEST) at which the exit door is positioned in the room.
If the user selects the direction of the exit door, the game will update the number of levels the character has successfully completed and return to the main menu. The character must remain available to play additional dungeon levels.
From the main menu, if a valid character exists and the user chooses to play the game (again), the game must create a new dungeon level (which may be constructed using the standardised layout) of the previously selected type, position the existing character in the first room, display the rooms description, and prompt the user for the next action.
If the character is in the first room of the dungeon level (i.e., the room containing the entrance door) and the user chooses the direction of the entrance door, the game will return to the main menu as if the user had selected the return to main menu action.
During the game, if the characters current health stat drops to zero (or below), the game will display a game over message, the number of dungeon levels that were successfully completed, and return to the main menu. This will make the current character and dungeon level unavailable as if the user has selected the return to main menu action.
Other Considerations
At any time that a valid character exists, the user must be able to select an option to view the characters details (stats, weapon, etc.). If the user chooses to view the character details, the game will display the character stats as described in section Player Character: Details Display, then prompt for another action from the same menu as prior to viewing the character details. For example, if the user chooses to view the character details from the main menu, the main menu options will be redisplayed afterwards.
All user inputs must be validated. If an invalid input is given, a warning must be displayed to the user and menu options redisplayed.
Note that the MenuInterface class already provides some helper functions to assist with input validation.
All classes must have appropriate constructors and destructors, even if they are only the default implementations. Take particular care of destructors when dealing with polymorphic classes, i.e., those classes with functions, and those classes that
virtual
use pointers (particularly bare pointers).
All objects that can be described must overload the output stream operator << . This will facilitate the display of objects by the class.MenuInterface 2.6. MenuUser interaction with the game will be performed through the MenuInterface class. Thisclass has the sole responsibility of commandline IO in the application, i.e., it handles the display of the menu options and processes the inputs from the user. The basic structure of the MenuInterface class and its interface will be provided for you; you will need toimplement the transitions between menus and the interactions with the Game class, which is responsible for maintaining and updating game state.While the descriptions of menu items do not have to exactly match the samples provided, the keys typed to select a particular action must conform to the table below for consistency across implementations. Note that it should not matter if the typed character is uppercase or lowercase. If in doubt, refer to the reference implementation of follow its example. Character Command Character Command CommandMain MenuPlay gameCharacter DetailsQuitDungeon Selection MenuBasic DungeonMagical DungeonCombat MenuCharacter DetailsAction MenuCharacterneswpo Go l back/Returncmbp Go backb Go Northc Attacka Go Eastq Use Special Abilityl Go South c Go Westb Main Menum Pick-up ItemmCompare ItemsrUse Special Ability Character DetailsMain MenuGo back2.7. Player CharacterThe player character is represented by the Character class. This class will maintain the state regarding the player’s character as well as define behaviours appropriate to thecharacter (i.e., update the game state as appropriate based on the character’s actions).A character has a name (provided by the player), properties that may impact the gameplay and the characters actions, and a weapon. These are collectively referred to as the player’s “stats”. When the player chooses the option, the characters stats must be displayed.There are three basic properties that are defined at character creation (based on choices made by the user) and are not changed during gameplay, including: Strength: allowable values 1-6, each value > 1 contributes to the damage of the
character
Dexterity: allowable values 1-6, each value > 1 contributes to the dodge chance of
the character
Wisdom: allowable values 1-6, each value > 1 contributes to the effects of magical
items
There are also three dynamic properties that may change during gameplay or based on the above basic properties:
Health points: starts at 50 and is reduced by taking damage from creatures (whole
numbers only). Once it reaches zero (or less) the game is over. Various items and
special abilities may increase the amount of health, but not above the original value.
Damage: calculated from the current weapon and Strength. The strength bonus is equal to 2(Strength1)2(Strength1). That is, each point of Strength above 1
adds twice as much to the damage.
Dodge chance: percentage, used to determine whether the character will get hit by a
creature when it attacks. 100% means the character will dodge every attack. Calculated as: 1005(Dexterity1)1005(Dexterity1)
That is, each Dexterity point above 1 adds 20% to the dodge chance.
When the game is first started the user must create their character following the character creation process described in the next section.
2.8. Player Character: Character Creation
The user must make a few choices to create their character. This section describes the
character creation process.
When the user chooses and option which requires a new character to be created, the game will prompt the user to enter the characters name.
After the user as entered a name, the game will prompt the user to allocate points to the three basic properties (Strength, Dexterity, and Wisdom) according to the following rules:
1. The user will start with 6 available points to allocate
2. The user will select the number of points to allocate to each property in turn: 1)
Strength, 2) Dexterity, 3) Wisdom
3. Theselectednumberofpointswillbeaddedtothebasevalueof1;theresulting value will be assigned to the matching property of the character:
1. The selected number of points must not exceed the current number of
available points
2. The selected number of points must not exceed 5 to prevent the total points
for the stat from exceeding 6.
3. The selected number of points must not be a negative number.
4. The select number of points may be zero, i.e., no points will be added to the
stats base value of 1
4. Aftertheuserselectsavalidnumberofpoints,theselectednumberwillbe
removed from the number of available points 5. The user may leave some points unallocated
6. The game must not allow a base property to exceed the value 6
After point allocation is complete, the game must display the character description and stats to the user. This is the same description that would be displayed if the user chose to display their character details from the menu.
When a character is created it must start with the Fists weapon type (refer to section Weapons & Enchantments).
It is important that you do not stumble at the first hurdle. If you have difficulty implementing the character creation process, hard-code the instantiation of
a Character object and continue with another step in the assignment.
2.9. Player Character: Details Display
When displaying the character details, the following information must be included:
The characters name
Strength
Dexterity
Wisdom
Health: current and maximum (original value)
Damage, calculated as described in the Player Character section
Dodge Chance, calculated as described in the Player Character section
The characters weapon, short description only (refer to section Weapons &
Enchantments)
For example, the character details may appear as follows (the exact layout is not a requirement):
***Character Summary***
Dungeon Disaster
Strength: 4
Dexterity:3
Wisdom:
Health:
Damage:
Dodge:
Weapon:
2
50 / 50
10 10
40%
you look down at your fists and shrug, these will do
2.10. Dungeon (Rooms, Walls, Doors)
A dungeon level consists of a connected set of rooms and are to be represented by the class. Each room of a dungeon (represented by the class) must be
Dungeon
Room
identifiable by a number ( ) so that they can be retrieved from the dungeon
object using the numeric identifier. Each room has 4 directions: North, South, East, and West. In each of these directions, there may be a wall (the Wall class) or a door
(the Door class). Doors are connected to adjacent rooms via a door in the opposing
direction. For example, if a room has a door to the north, the northern room has another door to the south and these doors are connected to one another.
integer
Door objects must be connected to one another using bare pointers in the C++ implementation.
Most doors are connected to each other to allow movement between rooms in both directions. There are two exceptions: the entrance to the dungeon level, and the exit. Your design/implementation will need to consider how the entrance and exit are represented. When the user chooses to go through the dungeon entrance or exit they
will be returned to the main menu as describe in section General Gameplay: Ending a Level.
Each room may contain a creature ( Creature ), a weapon ( Weapon ), or both. If both are present in the room, the description should not indicate the presence of the weapon until
after the user defeats the creature, revealing the weapon.
When the user enters a room, a description of that room must be provided to the user. The description includes what the room looks like (this is up to you, or you can use the text of the examples) and what the character sees, that is, where the doors are located, whether a creature or item is present. Descriptions of walls may be included. An example description for a RockChamber with an entrance to the North, and OpenDoorways to the South and East may look like the following:
Looking around you see a dark and empty chamber
To the NORTH you see the entrance by which you came in.
To the SOUTH you see you see an opening to another chamber
To the EAST you see you see an opening to another chamber
When a dungeon level is being created, various elements must be selected randomly, including: the type of room, the type of creature (if present), and the type of weapon (including enchantments, if present). We will use the Builder Pattern to control the dungeon creation.
Note: for simplicity, the size of the dungeon (i.e., the number of rooms) and the connections between rooms will not be randomly generated for this assignment. Moreover, it is not required to do any complex registration of types: a simple switch statement will be acceptable, for example.
Dungeon Element Combinations
Element Name Class Name Type Dungeon? Dungeon?
In Basic In Magical
Rock Chamber
RockChamber
Room
Yes
No
Quartz Chamber
QuartzChamber
Room
Yes
No
Enchanted Library (optional)
EnchantedLibrary
Room
No
Yes
Alchemists Laboratory (optional)
AlchemistsLaboratory
Room
No
Yes
Rock Wall
RockWall
Wall
Yes
No
Magic Wall (optional)
MagicWall
Wall
No
Yes
Open Doorway
OpenDoorway
Door
Yes
Yes
Boomerang
Boomerang
Weapon
Yes
Yes
Short Sword
ShortSword
Weapon
Yes
No
Battle Axe
BattleAxe
Weapon
Yes
No
Wizards Staff (optional)
WizardsStaff
Weapon
No
Yes
Magic Wand (optional)
MagicWand
Weapon
No
Yes
Creatures
Creature *
Creature
Defined per creature type in the data file.
2.11. Dungeon Types
The game will include two dungeon types: a basic dungeon ( BasicDungeon class), and a magical dungeon ( MagicalDungeon class). Each dungeon type can contain different types
of rooms, walls, doors, creatures, and/or weapons. (Refer to
sections Creatures and Weapons & Enchantments for details of the creatures and items,
respectively.)
Each dungeon type will have its own concrete builder class
( BasicDungeonBuiler and MagicalDungeonBuilder , respectively) that manages the creation of the dungeon object and each of its components. The Game will need to instruct the
builder on what type of component to build in a general sense (i.e., dungeon, room, door, creature, or weapon), along with any information needed to put the component in the correct location (e.g., weapon in a room) or connect them together (e.g., the rooms to be connected by doors). The builder will then use the provided information to instantiate an appropriate object (according to the allowable combinations below), insert the object where it belongs, and connect the objects as required.
Note: For components that have a choice (e.g., room type), the builder can simply choose one at random. For weapons, you could use a weighting of 50% for a basic weapon, 30% for a weapon with 1 enchantment, and 20% for a weapon with 2 enchantments.
The supported combinations of dungeon elements are listed in the following table.
Note: the constraints below do not have to be encoded into the design as hard restrictions. They can be knowledge that the builders have about what components are allowed to be combined, which would be represented simply as dependencies. It is important not to over-constrain the design at this point. Imagine, for example, if a new dungeon type is created that mixes Rock Chambers and Enchanted Library room-types, you do not want to need to modify all the strict associations that enforce the original combinations. Make appropriate use of abstractions and interfaces.
Note: the class may be a concrete class that you introduced in your own
design.
Creature
2.12. Standard Dungeon Layout
Dungeon levels would normally be randomly generated; however, to simplify the assignment and make it easier to test and mark, you are not required to implement randomly generated dungeon levels. However, your design and implementation should allow such a change in the future. Some elements of the dungeon are still randomised, for example, the type of each room, the type of creature (if present), and the type of item (if present).
The structure of the (first) dungeon level must conform to the standard structure defined below. There is no constraint on the structure of dungeon levels after the first.
The layout diagram uses the following symbols:
Large green rectangles represent rooms with the numbers indicating their ID
Small blue bars joining rooms represent connected pairs of doors
Entrance and Exit are labelled blue bars and indicated by a directional arrow
Orange smiley faces represent creature locations
Yellow suns represent weapon locations
2.13. Creatures
Dungeons, specifically rooms, can be inhabited by numerous foul creatures. There can be at most one creature per room and a creature never leaves the room in which it is created. All creatures must derive from the class Creature and conform to
the Prototype Pattern, as the creature types will be loaded from a data source at runtime. When the user encounters a creature in a room they must defeat it in combat before moving on or picking up an item (if present). Alternatively they can return the way they came and attempt to find a way around it. Each type of creature has different stats, but otherwise has the same types of stats as the player character. These stats are:
Strength Dexterity
Wisdom
Health
Damage
Dodge chance
The bonuses provided by the basic stats are calculated in the same manner as that of the player character and then halved. If a creature is a boss (i.e., it is in the room with the exit door) they receive the full bonus the same as the player character.
In contrast to the player character, creatures also have a long description which is displayed when the creature is encountered in a room. For example, encountering a Goblin in a room may display as follows:
Blocking your path you see a Goblin: a small nimble creature who favours the short sword
This follows the pattern:
Blocking your path you see a
All creatures will using a weapon in the same manner as the player character. If
the weapon has a special ability, the creature may choose to use the weapons special ability rather than a standard attack. Refer to the section on Weapons & Enchantments for details.
The specific types of creature, that is, the creature prototypes (since we are using the prototype pattern) will be defined in a data file and loaded by the application at runtime. Details of the file format are given in the next section.
attack
When instantiating creature prototypes from the data file, defensive programming should be used to ensure you are not loading invalid data that may corrupt the program. Therefore, you must ensure the following:
A name is provided: if not you should discard the creature type;
A description is provided: if not you could just add
rather than discarding the creature type entirely;
Maximum Health stat is within the range 1 100 (inclusive);
Strength stat is within the range 1 6 (inclusive);
Dexterity stat is within the range 1 6 (inclusive);
Wisdom stat is within the range 1 6 (inclusive);
A Weapon Type is defined: if not you can discard the creature type or give it a
default weapon of some type, e.g. Fists;
A Dungeon Type is defined: if not you can discard the creature type or make it
applicable to all dungeon types;
You cannot always trust that your data files will not be modified by a malicious user (or just trying to cheat), so you must always be careful when loading data from file.
2.14. Loading Creatures from CSV
In this assignment, the creature types will be loaded from a CSV (comma separated values) file. You are required to implement a simple CSV parser in the CsvFile class. The
interface for the class is provided, along with a set of Unit Tests, to which you
CsvFile
must implement a conforming solution. Refer to the documentation in
the CsvFile and Testing classes ( csvfile.h and testing.h , respectively).
The CSV file used by the application will be generated by the class. There is a database module on LearnOnline in which you can enter the details of a Creature type (if each student enters 1 creature type there will be 160+ types in the game). You will then be able to download the CSV file from LearnOnline to be used by the application at runtime.
Go to the Creature Types Database to contribute your own creature to the growing collection or export the CSV file.
The Qt Creator project is configured with an initial CSV file creature_types.csv that will be copied into the output directory when the project is built. When reading this file into the game, you may hard-code the filename directly. If you download an updated CSV file from the Creatures Types database, simply overwrite the existing file in your project folder with the new one (it should be version controlled so you should always be able to revert if desired).
For the design, you will need to identify the best place for the CsvFile class to be used,
its associations, and dependencies. Remember the principles of loose coupling, minimising dependencies, and separation of concerns. It is suggested you load the data file as close as possible to where you need to process its contents to instantiate the creature prototype instances.
For the implementation, you can refer to the IETF RFC 4180, which distils the format of the CSV file down to about 7 common rules. In this assignment, we make a slight modification to number 6: you do not need to worry about real linebreaks occurring
within a quoted field. Instead, the text sequence
(i.e., backslash followed by n as two characters and not an escape sequence meaning a single newline character) may appear within a quoted field and you must convert it into a proper linebreak character. This allows you to simply process each line of text as a row of data, instead of worrying about a row of data spanning multiple lines.
There are several ways for you to implement the parsing of the CSV file format including delimiter based or character-by-character parsing. You may use functions such
as std::getline , the overloaded input operator >> of the input stream classes, or any
other method(s) you think are necessary. However, you must use C++ streams and not old-style C IO functions.
Be aware of any manipulators that may impact your parsing, e.g., the default for streams is to skip whitespace on input, so you may need to configure your stream appropriately using the noskipws manipulator.
Remember the different types of streams such as file streams (which give you access to file content) and string streams (which you can use as temporary buffers that you manipulate internally without affecting the any other stream).
Refer to the lecture slides, and online reference material (e.g., cppreference.com) for information on streams and manipulators.
The provided tests are also a good place to determine what the supported format is and how to use the CsvFile class according to its interface. This is a common thing,
particularly in modern open source projects, where the Unit Tests are considered the documentation on how to use a class.
It is important that you do not get stuck trying to perfectly parse the CSV files. If you have difficulty implementing the parsing you have a couple of options depending on where you get stuck.
If you get stuck once your implementation reaches the more difficult aspect of handling quoted fields, then run your application using a modified data file that ensures no quoted fields exist. An easy solution for that is to take the initial sample file and remove the Evil Wizard creature type as that is the only row that requires quoted fields (due to a comma in its description field).
If you get stuck trying to parse the file format altogether, revert to hard-coding a creature prototype instance and use that to instantiate new creatures within the dungeon and continue to a step you think you can achieve.
2.15. Weapons & Enchantments
The game allows characters and creatures to carry a weapon (only 1 weapon, and always 1 weapon), which they use in combat or at any time to affect their environment. In addition, weapons can be enchanted to give them extra bonuses or special effects for the character to use. Special effects may have an arbitrary effect on the game state. Creatures that have weapons can attack with them or use their special ability (if they have one). The weapon enchantments will be handled using the Decorator Pattern, which allows additional behaviour of the enchantment to be dynamically added to the basic
behaviour of the underlying weapon.
Weapons (represented by the Weapon class) have a name, a short description (used on
the character details display), a long description (used on the weapon specific display), and a damage stat (minimum and maximum value). Their primary use is for attacking a creature (or the character if owned by a creature) during combat. Some weapons may also have a special ability that the character (or creature) may use during combat, while some special abilities may also be usable outside of combat (character only).
When displaying the details of a weapon (either when viewing the character details or when comparing two weapons) the display must include:
name
long description
damage range (min. and max. values)
description of the special ability, if present
For example, the details of the Fists weapon may appear as follows (the exact formatting is not mandatory):
Fists
Min. Damage: 4
Max. Damage: 4
Fists are the weapon of choice for someone who has nothing else
Weapons can be enchanted (represented by the class), which add bonuses
and/or special abilities to the weapon on which they are placed. Each weapon may have up to two enchantments. Enchantments change the reported name of the item and can
Enchantment
be either prefix enchantmentsadd a term (or terms) to the beginning of the nameor suffix enchantmentsadd a term or terms to the end of the name. Only one of each type may enchant a weapon at the same time, i.e., if there are two enchantments on a weapon then one will be a prefix and one will be a suffix. For example, the Flaming short sword of healing is a short sword weapon with a prefix enchantment named flaming and a suffix enchantment named of healing.
Enchantments on a weapon may change the standard damage of the weapon when it is used to attack, or it may add a special ability to the weapon. Special abilities added by an enchantment follow the same rules as special abilities directly of the weapon. When a weapon with an enchantment has its details displayed, the display must include the additional details of the enchantment(s).
Note: you do not have to worry about both an enchantment and the weapon providing a special ability. The allowed combinations preclude that from occurring.
The following section will provide the details of each weapon and enchantment type that must appear in the game.
2.16. Weapon & Enchantments: Properties
The following weapons and enchantments MUST be included in the game:
Fists
The standard weapon type all characters are created with. Should never be
constructed with enchantments.
Property
Value
Short Description
you look down at your fists and shrug, these will do
Long Description
Fists are the weapon of choice for someone who has nothing else.
Damage (Min. Max.)
4-4
Special Ability
None
Boomerang A weapon type common to both dungeon types. No special abilities.
Property
Value
Short Description
an effective ranged weapon that returns to your hand when used
Long Description
You scratch your head struggling to understand how this weapon can return even *after* it hits its target?
Damage (Min. Max.)
6-8
Special Ability
None
Short Sword
A small weapon with no innate special abilities. Basic Dungeon only.
Property
Value
Short Description
a sharp and pointy instrument, good for stabbing
Long Description
Not very large, but with a sharp point. Short swords are designed more for stabbing than for slicing. The hilt is surprisingly ornate for such an inconspicuous weapon.
Damage (Min. Max.)
5 10
Special Ability
None
Battle Axe
A large weapon with no innate special abilities. Basic Dungeon only.
Property
Value
Short Description
heavy, but effective
Long Description
A large and heavy weapon. The battle axe must be wielded with two hands but even then you are almost as likely to cut off your own limbs as those of an enemy.
Damage (Min. Max.)
10 15
Special Ability
None
Wizards Staff
A magical weapon that can shoot Fireballs (special ability). Magical Dungeon
only.
Property
Value
Short Description
it would break if you leant on it, but it shoots fireballs so thats something
Long Description
Not a very sturdy staff, but the swirl of magical fire around its top belies a magical secret: it shoots fireballs!
Damage (Min. Max.)
1-2
Special Ability
Fireball: deals 10 20 damage to the opponent
(plus the bonus from the creature or characters Wisdom stat). Always hits, regardless of dodge chance.
Magic Wand
A magical weapon that can Heal its user (special ability). Magical Dungeon only.
Property
Value
Short Description
birch with angels feather core and rubberised leather grip
Long Description
Apparently, there is no other wand like this one in existence. The angels feather at its core allows the bearer to perform unbelievable feats of healing.
Damage (Min. Max.)
5 10
Special Ability
Healing: returns character to full health.
Flaming
An enchantment that applies additional (fire) damage on attack.
Property
Value
Prefix/Suffix
prefix
Long Description
Holding it feels warm to the touch and sparks leap out when it makes contact with something.
Effect
Deals an extra 5 damage when the weapon is used to attack (if the attack hits).
Property
Value
Can appear on
Boomerang, Short Sword, Battle Axe, Wizards Staff, and Magic Wand
Electrified
An enchantment that applies additional (lightning) damage on attack.
Property
Value
Prefix/Suffix
prefix
Long Description
The air crackles around it making the hairs on your arm stand on end.
Effect
Prefix/Suffix
Deals an extra 5 damage when the weapon is used to attack (if the attack hits).
Can appear on
Boomerang, Short Sword, Battle Axe, Wizards Staff, and Magic Wand
of Healing
An enchantment that allows the user to Heal themselves (special ability).
Property
Value
Suffix
Long Description
Just being near it makes you feel all warm and fuzzy inside.
Effect
Special ability: heals the owner for 5 health points.
Can appear on
Boomerang, Short Sword, Battle Axe
of Vampirism
An enchantment that heals the user the when damage is dealt from (normal)
attacks. Does not trigger for special abilities (e.g., Fireball or Heal).
Property
Value
Prefix/Suffix
Long Description
Suffix
Occasionally drops of blood appear on the surface but you are unsure from whence they came.
Effect
Half of the damage dealt during an attack is given bac to the owner as an increase in health points.
Can appear on
Boomerang, Short Sword, Battle Axe, Wizards Staff, and Magic Wand
Note: while it is possible to apply the Prototype Pattern to weapons in the same way as it is applied to creatures, we will not do so. The purpose of doing it without the Prototype Pattern for weapons is to force the use of inheritance and polymorphism. If designed correctly, each subclass should require minimal additional implementation.
2.17. Combat
Combat between a character and a creature will be performed in rounds. Each round the user will choose their action and then the creature will perform an attack or use the special ability of their weapon (if present). The user actions include:
1. attack:willperformanattackusingtheowners(characterorcreature)weapon
dealing damage if the opponent does not dodge the attack;
2. use special ability (if available): weapons special ability effect will be applied,
which could affect the owner (character or creature) or opponent (character or
creature) depending on the ability; and
3. return the way you came: will leave the room through the door by which the
character entered ending up in the room from which the character came (no other door can be used by a character while a creature is in the room).
If options 1 or 2 are chosen, the creature will take its turn after the effect of the users action is applied. If option 3 is chosen, the creature does not get to take its turn and the creature must not follow through the door, i.e., it stays in the room. The result of combat will update the character, creature, and/or game states, for which appropriate behaviour needs to be defined.
Each time an action is performed (whether it be the player or the creature) an appropriate message and the actions description will be displayed to the user. However,
only the
can access
provided to the
class is to handle IO and, therefore, only the class
. You will need to consider how the textual descriptions are
for display, taking into account the effect an enchantment
MenuInterface
MenuInterface
std::cout
MenuInterface
may have on the description. For example, if an enchantment deals additional damage over that of the underlying weapon, the description must include additional text indicating the extra damage dealt and its source.
There are any number of ways in which this can be implemented. Some examples include:
using return values (may have problems if there is more than one value that needs to be returned, but could use a std::tuple in that case)
passing in an object of an existing type that can collect the results, e.g.,
a
using one or more out parameters, i.e., reference parameters that are modified within the function so that the caller can access the value once the caller completes (similar to the previous but with different implications)
creating a new helper class to track the action events and results and pass it to the behaviour or return it from the behaviour to build the final result
std::vector
If an attack succeedsi.e., if the target character or creature does not dodge itthe targets health is reduced by the damage amount as determined by the weapons damage properties and the bonus provided by the Strength stat of the character or creature performing the attack. Since weapons have a damage range, the damage incurred by an attack must be calculated by first generating a random number between the minimum and maximum damage values (inclusive) of the weapon.
Whether a creature or character dodges an attack is determined randomly based on their percentage Dodge Chance stat. This can be determined by representing the Dodge Chance as a real number ( float or double ) and by generating a random real number
between 0 and 1: if the randomly generated number is less than the Dodge Chance, the character or creature dodges the attack. For example, if a character has a 60% dodge chance, 0.6 as double, and the random number 0.4 were generated then the character would dodge the attack; if 0.63 were generated, the character would take damage.
If a special ability is used that deals damage, the targets health is reduced by the damage amount as determined by the special abilitys definition and the bonus provided by the Wisdom stat of the character or creature using the ability. If the item specifies a damage range for the special ability, the actual damage value of the ability will be determined by obtaining a random value within the range (inclusive).
If the ability has a healing effect then the health of weapons user (character or
creature) is increased by the healing amount (as defined by the weapon or enchantment) and the bonus provided by the Wisdom stat of the character or creature using the ability. If the item specifies a healing range for the special ability, the actual heal amount of the ability will be determined by obtaining a random value within the range (inclusive).
When the creatures health reaches zero or below, a win message must be displayed to the user and the creature must be removed from the room.
When the players health reaches zero or below, the user is returned to the main menu and the character is destroyed, as per the General Gameplay rules.
2.18. Documentation
Your code must be documented appropriately using Doxygen comments. Read pages 48- 53 of the course textbook for guidelines on good commenting, as well as the style guide. Document as you go, not all at the end. Document sparingly: most of the marks are for implementation not comments.
Comment blocks must be used in your header file to document your classes and class members.
Private members should also be documented when it is not obvious for what they are usedbut first check if the code can be improved as clean code is better than comments.
Use comments sparingly in source files, document blocks of code (switch statements, if else groups, loops, etc.) rather than individual statements: do not comment individual
statements, unless the outcome of the statement is not obvious.
Optionally, you can add comments to main.cpp to document the main page of the generated HTML.
2.19. Code Style
You must write you code conforming to the code style set for this course. See http://codetips.dpwlabs.com/style-guide
2.20. Version Control
You must use version control to keep track of your progress during implementation, using git. You should perform regular commits as you implement features and fix errors. Your commit comments should reflect the context of the changes that were made in each commita fellow developer can always diff the contents to see exactly what changed but that does not provide the context. You should try to ensure each commit comment contains a short subject line.
Your submission will comprise your entire version control repository, so it should be specific to the assignment. For example, if you use git, you must create the git repository in the root directory for your assignment. Do not commit your assignment to a repository created in a parent folder or any other location. Your repository must contain all source files required to compile and run your program (including a Doxygen config file) but must not include any generated or extraneous files.
You can ensure a clean folder for submission by cloning your assignment and zipping the new folder. This will not modify your working directory while providing all committed files and their version history.
You do not have to use an online version control repository such as GitHub. If you do use an online repository, ensure that the assignment is private, i.e., cannot be seen
by people other than yourself.
3. Implementation Rules and Hints
! You must consider when and where it is appropriate to use smart pointers vs. bare pointers and the effect this choice may have on constructors, destructors, etc. In most cases the choice is up to you with the exception of the connection between two
doors, doors must be connected via bare pointers.
! Be sure to check for null pointers ( nullptr ) before attempting to use an object through a pointer and reset pointers to null where appropriate.
! Smart Pointers the Dungeon class uses the smart pointer to
store and retrieve the rooms (among other things). You must use
the template function to create the rooms to pass to the
function . The below code snippet is an example of adding a room to a
dungeon:
std::make_shared
Dungeon::addRoom
std::shared_ptr
Dungeon d = Dungeon{};
d.addRoom(std::make_shared
! The and classes may not be the only occurrence of smart pointers in your
implementation.
! The provided project uses namespaces. Be careful to ensure you are accessing classes with appropriate scopes. Remember to use the scope operator ,
Dungeon
Room
::
e.g., .
! The game will need to keep track of (at least) the current room, the character, and the previous room/door.
! Casts in your code, casts should only need to be performed between a base class pointer and a derived class. When doing so, a dynamic cast should be performed (using ). For example, to cast an Weapon shared pointer to
a pointer you would use the following code snippet:
dynamic_pointer_cast
Enchantment
core::dungeon::BasicDungeon
std::shared_ptr
! Remember, if the cast is successful, the pointer will be non- .
! It is recommended that you test individual components as you go, rather than trying to test the whole application through the menu-driven interface. Writing code to test specific elements will speed up development as you will not need to constantly enter data through the menu interface.
! You may change the descriptions of items, creatures, actions, etc., if you like.
! Type defines if you know what you are doing, you may define type aliases for the
shared pointer types for use in the MenuInterface and your classes. Alternatively use appropriate using declarations.
nullptr
4. Submission Details
You MUST submit your complete Qt Creator Project, including git repository, inside a single ZIP file to LearnOnline (Assessment Item 2: Assignment Part 2 Implementation). The ZIP file MUST include the following:
All source files required to compile and run your program
The Doxygen config file and the HTML documentation generated using Doxygen tools
Your version control directory (.git folder)
You do not need to resubmit your design diagram, but if you have been keeping it up-to- date and version controlling it within the folder, you MAY include it.
Your ZIP file MUST NOT include any generated or extraneous files.
A cover-page is not required as one is generated for you by LearnOnline upon submission.
The deadline for submission is 22 September 2019 11:59 PM. After which time the submission will be considered late and attract a penalty as detailed in the course outline.
5. Marking Criteria
Your assignment will be marked both automatically and manually; automatically using unit testing, shell scripts, and static code analysis tools. Your code will be inspected for style: remember that consistency is the primary goal of all style guides, the easier it is to understand your code the easier it is to allocate marks. The following criteria will be used to mark your assignment.
Note: the criteria with negative marks are penalties that will be applied if the submission does not meet the expected criteria. They are structured such that an otherwise perfect submission will be unable to receive an HD if and only if the full penalties are applied.
Marking Criteria
Criteria Mark Correct implementation of functional requirements
General Gameplay 10 Menu Interface 5 Player Character 10 Dungeon Creation 10 CSV File Parser Implementation 10 Creatures 10 Weapons & Enchantments 10 Combat 10
Correct use of pointers: bare pointers and smart pointers. Bare pointers on 10 Door-Door association, smart pointers used where appropriate (shared vs.
unique vs. weak)
Correct implementation of classes: inheritance, constructors/destructors, 10 data members, member functions, public/private accessibility, return types, parameters (value vs. reference, const), keyword declarations (virtual, const, override, etc.), initialisation of data members, etc.
Correct separation of code in the header file and source files: declaration vs. 5 definition
Implementation of components related to the Magical Dungeon (bonus) (10) Inappropriate use of version control (-5)
Source code does not follow style guide (-5) Inadequate/inappropriate use of comments or no generated HTML (-5)
(Doxygen)
Total Possible Marks 100
Reviews
There are no reviews yet.