Stage 4 - Character Types¶
Introduction¶
So far we have created a multiple-room dungeon that the user can move between. We have also populated the dungeon with characters that the user can interact with.
During this stage we will refine our characters by:
defining two character types:
friend
enemy
change our current characters to one of these types of characters
adjust our interactions to allow for different types of characters
Class Diagram¶
Our new class diagram has two new classes Enemy
and Friend
.
Notice that they both have arrows pointing towards the Character
class, that’s because they are both child classes of the parent class. A child class inherits all the attributes and methods from the parent class. In addition, they may have extra attributes and methods, or they can even overwrite an attribute or method they inherit. Let’s look at our class diagram to see this in action.
Inheritance
Inheritance is a concept in object-oriented programming (OOP) that allows you to create a new class based on an existing class. Think of it like a family tree, where a child class inherits characteristics from its parent class, just like how a child inherits traits from their parents.
Inheritance makes it easier to reuse code and add new classes without having to rewrite the same information over and over again. It also makes it easier to keep track of different types of animals and what they have in common and what makes them unique.
Enemy class¶
The Enemy
class:
inherits from the
Character class
thename
,description
, andconversation
attributes as well as thedescribe
,talk
, andhug
methods.adds the
weakness
attributeoverwrites the
Character
fight
method with its ownfight
method
Friend class¶
inherits from the
Character class
thename
,description
, andconversation
attributes as well as thedescribe
,talk
, andfight
methods.overwrites the
Character
hug
method with its ownhug
method
Why use inheritance?¶
In the end our two child classes operate similarly to two classes with the following class diagrams (blue text indicates overwritten methods).
So why don’t we just two separate classes?
Remember the DRY principle? → Don’t Repeat Yourself?
If we have two describe methods that are exactly the same, we want to only write it once. This ensures code that is more accurate and easier to maintain.
For example, if I want to change the wording of the describe
method, I will only need to change it in the Character
class. The change will flow down to the Friend
and Enemy
classes. Similarly, if there is an error in the talk
method, then I only need to fix it in the Character
class.
OOP Terminology
OOP can have several names for the same concept. I will be consistent throughout this course, but if you use other resources, they may use different terminology.
parent class → superclass or base class
child class → subclass or derived class
Let’s make these changes to the code.
Define different character types¶
Open your character.py file and add the highlighted code below to create the Friend
class:
Create Friend class¶
1# character.py
2
3class Character():
4
5 def __init__(self, name):
6 # initialises the character object
7 self.name = name
8 self.description = None
9 self.conversation = None
10
11 def describe(self):
12 # sends a description of the character to the terminal
13 print(f"{self.name} is here, {self.description}")
14
15 def talk(self):
16 # send converstation to the terminal
17 if self.conversation is not None:
18 print(f"{self.name}: {self.conversation}")
19 else:
20 print(f"{self.name} doesn't want to talk to you")
21
22 def hug(self):
23 # the character responds to a hug
24 print(f"{self.name} doesn't want to hug you")
25
26 def fight(self):
27 # the character response to a threat
28 print(f"{self.name} doesn't want to fight you")
29
30class Friend(Character):
31
32 def __init__(self, name):
33 # initialise the Friend object by calling the character initialise
34 super().__init__(name)
Investigating that code:
class Friend(Character):
→ defines theFriend
class(Character)
→ tells Python thatCharacter
is the parent class ofFriend
def __init__(self, name):
→ automatically runs when you create aFriend
object# initialise the Friend object by calling the character initialise
→ method descriptive commentsuper().__init__(name)
→ this is very newtells Python to run the
__init__
method of the parent class (superclass)running
Character
__init__
will inherits all the attributes and method fromCharacter
the
__init__
ofCharacter
requires aname
so we pass thename
argument
Create Enemy class¶
To create the Enemy
class, add the highlighted code:
1# character.py
2
3class Character():
4
5 def __init__(self, name):
6 # initialises the character object
7 self.name = name
8 self.description = None
9 self.conversation = None
10
11 def describe(self):
12 # sends a description of the character to the terminal
13 print(f"{self.name} is here, {self.description}")
14
15 def talk(self):
16 # send converstation to the terminal
17 if self.conversation is not None:
18 print(f"{self.name}: {self.conversation}")
19 else:
20 print(f"{self.name} doesn't want to talk to you")
21
22 def hug(self):
23 # the character responds to a hug
24 print(f"{self.name} doesn't want to hug you")
25
26 def fight(self):
27 # the character response to a threat
28 print(f"{self.name} doesn't want to fight you")
29
30class Friend(Character):
31
32 def __init__(self, name):
33 # initialise the Friend object by calling the character initialise
34 super().__init__(name)
35
36class Enemy(Character):
37
38 def __init__(self,name):
39 # initialise the Enemy object by calling the character initialise
40 super().__init__(name)
41 self.weakness = None
Now unpack the code that create the Enemy
class:
class Enemy(Character):
→ define theEnemy
class as a child of theCharacter
classdef __init__(self,name):
→ automatically runs when anEnemy
object is created# initialise the Enemy object by calling the character initialise
→ method descriptive commentsuper().__init__(name)
→ runs the parent class’__init__
method which causes inheritanceself.weakness = None
→ adds an additionalweakness
attribute to allEnemy
objects
Now that we have two character types, we need to change the characters that we have created.
Change character types¶
Return to main.py, and change the highlighted code:
1# main.py
2
3from room import Room
4from character import Friend, Enemy
5
6# create rooms
7cavern = Room("Cavern")
8cavern.description = ("A room so big that the light of your torch doesn’t reach the walls.")
9
10armoury = Room("Armoury")
11armoury.description = ("The walls are lined with racks that once held weapons and armour.")
12
13lab = Room("Laboratory")
14lab.description = ("A strange odour hangs in a room filled with unknownable contraptions.")
15
16# link rooms
17cavern.link_rooms(armoury,"south")
18armoury.link_rooms(cavern,"north")
19armoury.link_rooms(lab,"east")
20lab.link_rooms(armoury,"west")
21
22
23# create characters
24ugine = Enemy("Ugine")
25ugine.description = "a huge troll with rotting teeth."
26ugine.weakness = "cheese"
27
28nigel = Friend("Nigel")
29nigel.description = "a burly dwarf with golden bead in woven through his beard."
30nigel.conversation = "Well youngan, what are you doing here?"
31
32# add characters to rooms
33armoury.character = ugine
34lab.character = nigel
35
36'''
37# describe the rooms
38cavern.describe()
39armoury.describe()
40lab.describe()
41'''
42
43# initialise variables
44running = True
45current_room = cavern
46
47# ----- MAIN LOOP -----
48while running:
49 current_room.describe()
50
51 command = input("> ").lower()
52
53 if command in ["north", "south", "east", "west"]:
54 current_room = current_room.move(command)
55 elif command == "talk":
56 if current_room.character is not None:
57 current_room.character.talk()
58 else:
59 print("There is no one here to talk to")
60 elif command == "hug":
61 if current_room.character is not None:
62 current_room.character.hug()
63 else:
64 print("There is no one here to hug")
65 elif command== "fight":
66 if current_room.character is not None:
67 current_room.character.fight()
68 else:
69 print("There is no one here to fight")
70 elif command == "quit":
71 running = False
72 else:
73 print("I don't understand.")
Investigating that code:
from character import Friend, Enemy
→ we will no longer haveCharacter
objects, but ratherFriend
andEnemy
objectsugine = Enemy("Ugine")
→ changesUgine
to anEnemy
objectugine.weakness = "cheese"
→Enemy
object have aweakness
attribute, Ugine’s is cheesenigel = Friend("Nigel")
→ changesNigel
to aFriend
object
Refactoring testing¶
What we have just done is called refactoring our code. That is, we have made a change to our code, without changing what it does. Whenever you refactor your code the next step should always be testing, so let’s test.
What do we need to test. We need to make sure that we can still have all the same interactions with both Ugine and Nigel. Draw up the testing table below and then complete it.
Character |
Interaction |
Expected Result |
Actual Result |
---|---|---|---|
Ugine |
talk |
||
Ugine |
hug |
||
Ugine |
fight |
||
Nigel |
talk |
||
Nigel |
hug |
||
Nigel |
fight |
If all your expected results match your actual results then there is no problems, otherwise, you need to troubleshoot where your mistakes.
Adjusting the interactions¶
We want to change our interactions according to the character’s type. We don’t want to hug our enemies, nor do we want to fight our friends. In OOP this is called polymorphism.
Polymorphism
Polymorphism is a concept in object-oriented programming (OOP) that allows objects of different classes to respond to the same method call in different ways. This is like having multiple people with different jobs, all able to perform the same action, but in their own unique way.
Polymorphism allows for objects of different classes to be treated as objects of their class or as objects of a parent class, without having to know the exact type of the object. This makes it easier to write generic code that can work with objects of multiple classes, making your code more flexible and adaptable to changes in the future.
Adjusting the hug method¶
Currently, the hug
method is inherited from the Character
class, which basically says the character doesn’t want to hug you. This is fine for enemies, so we don’t have to change the Enemy
class, but this is not what we want our friends to do, so let’s change the Friend
class.
Return to the character.py file and add the highlighted code:
1# character.py
2
3class Character():
4
5 def __init__(self, name):
6 # initialises the character object
7 self.name = name
8 self.description = None
9 self.conversation = None
10
11 def describe(self):
12 # sends a description of the character to the terminal
13 print(f"{self.name} is here, {self.description}")
14
15 def talk(self):
16 # send converstation to the terminal
17 if self.conversation is not None:
18 print(f"{self.name}: {self.conversation}")
19 else:
20 print(f"{self.name} doesn't want to talk to you")
21
22 def hug(self):
23 # the character responds to a hug
24 print(f"{self.name} doesn't want to hug you")
25
26 def fight(self):
27 # the character response to a threat
28 print(f"{self.name} doesn't want to fight you")
29
30class Friend(Character):
31
32 def __init__(self, name):
33 # initialise the Friend object by calling the character initialise
34 super().__init__(name)
35
36 def hug(self):
37 # the friend responds to a hug
38 print(f"{self.name} hugs you back.")
39
40class Enemy(Character):
41
42 def __init__(self,name):
43 # initialise the Enemy object by calling the character initialise
44 super().__init__(name)
45 self.weakness = None
Investigating the code:
def hug(self):
→ defines thehug
method for theFriend
classsame name as
Character
method → replaceshug
method for allFriend
objects
# the friend responds to a hug
→ method’s explanatory commentprint(f"{self.name} hugs you back.")
→ display message using object’sname
Adjusting the fight method¶
Now it’s time to adjust the fight
method for our Enemy
class. We have a simple fight mechanic. Each Enemy
has a weakness
. If you use their weakness
to fight them, you win, otherwise you loose.
The highlighted code below enacts this mechanic.
1# character.py
2
3class Character():
4
5 def __init__(self, name):
6 # initialises the character object
7 self.name = name
8 self.description = None
9 self.conversation = None
10
11 def describe(self):
12 # sends a description of the character to the terminal
13 print(f"{self.name} is here, {self.description}")
14
15 def talk(self):
16 # send converstation to the terminal
17 if self.conversation is not None:
18 print(f"{self.name}: {self.conversation}")
19 else:
20 print(f"{self.name} doesn't want to talk to you")
21
22 def hug(self):
23 # the character responds to a hug
24 print(f"{self.name} doesn't want to hug you")
25
26 def fight(self):
27 # the character response to a threat
28 print(f"{self.name} doesn't want to fight you")
29
30class Friend(Character):
31
32 def __init__(self, name):
33 # initialise the Friend object by calling the character initialise
34 super().__init__(name)
35
36 def hug(self):
37 # the friend responds to a hug
38 print(f"{self.name} hugs you back.")
39
40class Enemy(Character):
41
42 def __init__(self,name):
43 # initialise the Enemy object by calling the character initialise
44 super().__init__(name)
45 self.weakness = None
46
47 def fight(self, item):
48 # fights enemy with provided item and returns if player survives
49 if item == self.weakness:
50 print(f"You strike {self.name} down with {item}.")
51 return True
52 else:
53 print(f"{self.name} crushes you. Puny adventurer")
54 return False
Investing that code:
def fight(self, item):
→ defines thefight
method for theEnemy
classaccepts the
item
argument which is the weapon the player uses
# fights enemy with provided item and returns if player survives
→ method’s explanatory commentif item == self.weakness:
→ checks if theitem
is this enemy’s weaknessprint(f"You strike {self.name} down with {item}.")
→ displays success messagereturn True
→ informs main.py of victory in the fightelse:
→ when theitem
is not this enemy’s weaknessprint(f"{self.name} crushes you. Puny adventurer")
→ displays failure messagereturn False
→ informs main.py of loss in the fight
Now that our fight
method is ready, we need to change our fight event handler in main.py. Use the highlighted code below:
1# main.py
2
3from room import Room
4from character import Enemy, Friend
5
6# create rooms
7cavern = Room("Cavern")
8cavern.description = ("A room so big that the light of your torch doesn’t reach the walls.")
9
10armoury = Room("Armoury")
11armoury.description = ("The walls are lined with racks that once held weapons and armour.")
12
13lab = Room("Laboratory")
14lab.description = ("A strange odour hangs in a room filled with unknownable contraptions.")
15
16# link rooms
17cavern.link_rooms(armoury,"south")
18armoury.link_rooms(cavern,"north")
19armoury.link_rooms(lab,"east")
20lab.link_rooms(armoury,"west")
21
22
23# create characters
24ugine = Enemy("Ugine")
25ugine.description = "a huge troll with rotting teeth."
26ugine.weakness = "cheese"
27
28nigel = Friend("Nigel")
29nigel.description = "a burly dwarf with golden bead in woven through his beard."
30nigel.conversation = "Well youngan, what are you doing here?"
31
32# add characters to rooms
33armoury.character = ugine
34lab.character = nigel
35
36'''
37# describe the rooms
38cavern.describe()
39armoury.describe()
40lab.describe()
41'''
42
43# initialise variables
44running = True
45current_room = cavern
46
47# ----- MAIN LOOP -----
48while running:
49 current_room.describe()
50
51 command = input("> ").lower()
52
53 if command in ["north", "south", "east", "west"]:
54 current_room = current_room.move(command)
55 elif command == "talk":
56 if current_room.character is not None:
57 current_room.character.talk()
58 else:
59 print("There is no one here to talk to")
60 elif command == "hug":
61 if current_room.character is not None:
62 current_room.character.hug()
63 else:
64 print("There is no one here to hug")
65 elif command== "fight":
66 if current_room.character is not None:
67 weapon = input("What will you fight with? > ").lower()
68 if current_room.character.fight(weapon):
69 current_room.character = None
70 else:
71 running = False
72 else:
73 print("There is no one here to fight")
74 elif command == "quit":
75 running = False
76 else:
77 print("I don't understand.")
Investigate the code:
weapon = input("What will you fight with? > ").lower()
→ asks the user to input their weaponif current_room.character.fight(weapon):
→ checks to see if user wins the fightcurrent_room.character.fight(weapon)
→ calls thefight
method displaying a messageif
→ since thefight
method returns a Boolean indicating the player’s success, we can use this to check the fight result.
current_room.character = None
→ if the player won the fight, the room now has no characterelse:
→ if the player looses the fightrunning = False
→ set the main loop flag toFalse
so the game will finish
Testing¶
Now we changed both the hug
and fight
methods, time to do some testing. Again we will use our testing table, and focus on the code we have changed.
Character |
Interaction |
Weapon |
Expected Result |
Actual Result |
---|---|---|---|---|
Ugine |
fight |
cheese |
||
Ugine |
fight |
not cheese |
||
Ugine |
hug |
- |
||
Nigel |
fight |
- |
||
Nigel |
hug |
- |
Friend fight error¶
Did you get the following error?
1Traceback (most recent call last):
2 File "h:\GIT\python-oop-with-deepest-dungeon\python_files\stage_4\main.py", line 66, in <module>
3 if current_room.character.fight(weapon):
4 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5TypeError: Character.fight() takes 1 positional argument but 2 were given
Why did we get the error? Let’s read the error message:
line 2 → the error is at line 66 of main.py
line 3 → the error is contained in
if current_room.character.fight(weapon):
line 4 → the error is specifically in the call to
fight
line 5 →
fight
was only expecting one argument (self
), but we gave two (self
,weapon
)
So let’s think about this. We have two fight
methods, which one was causing the problem? Well, Ugine worked fine, but Nigel didn’t, so it must be the fight
method for friends.
That method is in our character.py file, so let’s look at it.
1# character.py
2
3class Character():
4
5 def __init__(self, name):
6 # initialises the character object
7 self.name = name
8 self.description = None
9 self.conversation = None
10
11 def describe(self):
12 # sends a description of the character to the terminal
13 print(f"{self.name} is here, {self.description}")
14
15 def talk(self):
16 # send converstation to the terminal
17 if self.conversation is not None:
18 print(f"{self.name}: {self.conversation}")
19 else:
20 print(f"{self.name} doesn't want to talk to you")
21
22 def hug(self):
23 # the character responds to a hug
24 print(f"{self.name} doesn't want to hug you")
25
26 def fight(self):
27 # the character response to a threat
28 print(f"{self.name} doesn't want to fight you")
29
30class Friend(Character):
31
32 def __init__(self, name):
33 # initialise the Friend object by calling the character initialise
34 super().__init__(name)
35
36 def hug(self):
37 # the friend responds to a hug
38 print(f"{self.name} hugs you back.")
39
40class Enemy(Character):
41
42 def __init__(self,name):
43 # initialise the Enemy object by calling the character initialise
44 super().__init__(name)
45 self.weakness = None
46
47 def fight(self, item):
48 # fights enemy with provided item and returns if player survives
49 if item == self.weakness:
50 print(f"You strike {self.name} down with {item}.")
51 return True
52 else:
53 print(f"{self.name} crushes you. Puny adventurer")
54 return False
Looking closely at the code:
lines 30 - 38 → the
Friend
class does not have afight
method, so it is using the inheritedfight
method from theCharacter
classline 26 → the
Character
fight
method only accepts one argument(self)
, but how does this compare to theEnemy
fight
method?line 47 → the
Enemy
fight
method accepts two arguments(self, item)
Ok so we’ve found a discrepancy, but which one do we want to change? Remember we changed our main.py code to deal with fighting with a weapon, so the easiest way to solve this error is to add another argument to the Character
fight
method.
So make the following changes to character.py:
1# character.py
2
3class Character():
4
5 def __init__(self, name):
6 # initialises the character object
7 self.name = name
8 self.description = None
9 self.conversation = None
10
11 def describe(self):
12 # sends a description of the character to the terminal
13 print(f"{self.name} is here, {self.description}")
14
15 def talk(self):
16 # send converstation to the terminal
17 if self.conversation is not None:
18 print(f"{self.name}: {self.conversation}")
19 else:
20 print(f"{self.name} doesn't want to talk to you")
21
22 def hug(self):
23 # the character responds to a hug
24 print(f"{self.name} doesn't want to hug you")
25
26 def fight(self, item):
27 # the character response to a threat
28 print(f"{self.name} doesn't want to fight you")
29
30class Friend(Character):
31
32 def __init__(self, name):
33 # initialise the Friend object by calling the character initialise
34 super().__init__(name)
35
36 def hug(self):
37 # the friend responds to a hug
38 print(f"{self.name} hugs you back.")
39
40class Enemy(Character):
41
42 def __init__(self,name):
43 # initialise the Enemy object by calling the character initialise
44 super().__init__(name)
45 self.weakness = None
46
47 def fight(self, item):
48 # fights enemy with provided item and returns if player survives
49 if item == self.weakness:
50 print(f"You strike {self.name} down with {item}.")
51 return True
52 else:
53 print(f"{self.name} crushes you. Puny adventurer")
54 return False
Test again¶
Now we changed both the hug
and fight
methods, time to do some testing. Again we will use our testing table, and focus on the code we have changed.
Character |
Interaction |
Weapon |
Expected Result |
Actual Result |
---|---|---|---|---|
Ugine |
fight |
cheese |
||
Ugine |
fight |
not cheese |
||
Ugine |
hug |
- |
||
Nigel |
fight |
- |
||
Nigel |
hug |
- |
Wait, another problem fighting Nigel, but this one is different. There is no error message, the program just ends when you fight him. This is what we call a logic error.
Types of programming errors
There are three basic categories of programming errors:
syntax errors
caused by not following the programming language rules
Python will not even run the program, and immediately display an error message
runtime errors
caused when Python tries to execute a command, but something is wrong
Python will run the program, but display an error when it comes across a runtime error
our
fight
method error was a runtime error
logic errors
caused when the program does exactly what you tell it to do, but not what you want it to do
Python will never display an error, but the program doesn’t do what you want it to do
these are the hardest to troubleshoot
Here is the interaction I got from running the code before it ended:
1You are in the laboratory
2A strange odour hangs in a room filled with unknownable contraptions.
3Nigel is here, a burly dwarf with golden bead in woven through his beard.
4To the west is the armoury
5> fight
6What will you fight with? > dog
7Nigel doesn't want to fight you
Troubleshooting a logic error¶
Troubleshooting logic errors is a bit like detective work. You need to trace the program flow to work out where the error is.
So we’ll start our investigation in the main.py. Looking at the main loop, we can be confident that the problem involves the fight
event handler, so let’s zoom into that.
65 elif command== "fight":
66 if current_room.character is not None:
67 weapon = input("What will you fight with? > ").lower()
68 if current_room.character.fight(weapon):
69 current_room.character = None
70 else:
71 running = False
72 else:
73 print("There is no one here to fight")
In the test when the user fought Nigel:
the user got the message
Nigel doesn't want to fight you
this comes from the call to the
fight
methodline 68 must of been executed
the game ended
therefore
running
needed to be changed toFalse
line 71 must of been executed
the only way that line 71 could have been executed would be if the user lost their fight with Nigel
line 68 determines if the user won the fight, so lets look closely at this.
if current_room.character.fight(weapon):
→ makes a call to thefight
method and gets a Boolean response indicating successsince Nigel is a friend we need to look at the
Friend
fight
method
So zooming into the fight
method in the Character
class in character.py:
26 def fight(self, item):
27 # the character response to a threat
28 print(f"{self.name} doesn't want to fight you")
Now I can see the problem. If main.py is expecting a Boolean value, it won’t get one because the Character
fight
method doesn’t return anything.
Well, that’s not entirely correct. All Python functions (including methods) return a value. If the return
statement is not used, then the default values of None
is returned, but why does that stop our game?
Let’s zoom back in to the fight handler in main.py to understand.
65 elif command== "fight":
66 if current_room.character is not None:
67 weapon = input("What will you fight with? > ").lower()
68 if current_room.character.fight(weapon):
69 current_room.character = None
70 else:
71 running = False
72 else:
73 print("There is no one here to fight")
Looking at line 4:
for Nigel
current_room.character.fight(weapon)
will returnNone
line 4 becomes
if None:
which equates toif False:
jumps to the
else
statement on line 6which means line 7 is executed changing
running
toFalse
Ok, that all makes sense. Now we have to fix the problem. What we need is for line 4 to receive a True
when it calls the Character
fight
method.
Jump back to character.py and add the highlighted code below to solve our logic error.
1# character.py
2
3class Character():
4
5 def __init__(self, name):
6 # initialises the character object
7 self.name = name
8 self.description = None
9 self.conversation = None
10
11 def describe(self):
12 # sends a description of the character to the terminal
13 print(f"{self.name} is here, {self.description}")
14
15 def talk(self):
16 # send converstation to the terminal
17 if self.conversation is not None:
18 print(f"{self.name}: {self.conversation}")
19 else:
20 print(f"{self.name} doesn't want to talk to you")
21
22 def hug(self):
23 # the character responds to a hug
24 print(f"{self.name} doesn't want to hug you")
25
26 def fight(self, item):
27 # the character response to a threat
28 print(f"{self.name} doesn't want to fight you")
29 return True
30
31class Friend(Character):
32
33 def __init__(self, name):
34 # initialise the Friend object by calling the character initialise
35 super().__init__(name)
36
37 def hug(self):
38 # the friend responds to a hug
39 print(f"{self.name} hugs you back.")
40
41class Enemy(Character):
42
43 def __init__(self,name):
44 # initialise the Enemy object by calling the character initialise
45 super().__init__(name)
46 self.weakness = None
47
48 def fight(self, item):
49 # fights enemy with provided item and returns if player survives
50 if item == self.weakness:
51 print(f"You strike {self.name} down with {item}.")
52 return True
53 else:
54 print(f"{self.name} crushes you. Puny adventurer")
55 return False
Third test lucky¶
Let’s test and make sure that our logic error has been solved. Again, complete the test table below.
Character |
Interaction |
Weapon |
Expected Result |
Actual Result |
---|---|---|---|---|
Ugine |
fight |
cheese |
||
Ugine |
fight |
not cheese |
||
Ugine |
hug |
- |
||
Nigel |
fight |
- |
||
Nigel |
hug |
- |
Hopefully all your test have passed.
Stage 4 task¶
Now it is time for your to implement the Make phase.
Consider the additional character or characters that you have added, and change them into either a Friend, or an Enemy. Don’t forget their weakness if they are an enemy.