Overview Stage 0 Stage 1 Stage 2 Stage 3 Stage 4 Stage 5 Stage 6 Download

Mario's back!

and Toad has taken control




Super Mario 64: Toad's Terror is a text-based horror adventure game that will send shivers down your spine. Players will follow their own path through the story in order to defeat the monster that is Toad, or descend into madness trying.


Super Mario 64: Toad's Terror is no Baldi's Basics. We make our sprites in Word, not Paint. SM64TT will have HD 4K 60fps graphics that will blow your mind.



In this course, we’ve expanded our collection of tools used to program. We learned the societal issues involving computer technology. This involves things like privacy, security, and ethical use of information. We learned 2 new programming languages, Java and PHP. We learned how to create and use algorithms in our code. And lastly, we learned how to use Object Oriented Programming to organize and compact our code.

Mario Quiz (Unit 1)

Using php, we were reminded of the basics of coding and were taught new content related to the new language, used for server-side scripting.

Connect 4 (Unit 3)

Using Java, we learned how to use 2D arrays and apply them to create a game of Connect 4 in the Java console.

Waluigi’s Taco Stand (Unit 3 part 2)

Using Java, we learned how to use algorithms in our project to create a game of our choice, so we made the best thing we could think of.

Crazy 8’s (Unit 4)

We learned how to use Object Oriented Programming to our advantage to create a game of Crazy 8s. It was crazy.

Summative

The point of this summative project is to combine everything that we have learned this course and test our skill.




Kevin is the lead writer and graphic designer.

Owen is the lead programmer.



A little more detail about the game...

As a text-based game, story and narration will be essential elements in the finished product. As of now, we expect the game to utilize a Player class, a StoryEvent class, an Inventory class, an Item class, a Diary class, and a DiaryPage class.

The Player class will contain the player's name as well as score/time data (to be determined).

The StoryEvent class will be a basic template, copies of which will be used to display each event in the story. The class will have a large string, holding the narration/dialog for that event as well as the options the player has at that point in the game. It will also have two Image objects, one for the large image showing the situation the player is in and one for an image of whomever is speaking (Think ICS Sim 2017 style dialog). Since the player will likely be presented with many options, the StoryEvent class needs a variable to hold the 'correct' option so we know if the user is on the right path. The game will likely be very linear, with only one path the user can take to victory, and multiple wrong choices will cause the player to die. There will be different types of StoryEvents, ones where the player must choose where to go or what to do, and ones where the player must use an item from their inventory. StoryClass objects will have an int representing it's "chapter," so that as users progress throughout the story, they can see what chapter they are on. This will serve as an indicator of progress.

The Inventory class will extend ArrayList in order to be able to add/remove the Items the player collects. Players can access their inventory at any time. The Item class will contain the name of the item, path to the image of the item, and a short description of the item. A button will be present in the game window to open the inventory window, which will display the images and descriptions of each item in the player's inventory. Items will be collected by the player, and will become essential to the player's quest, meaning that if the player does not collect an item, they will find that eventually they will no longer be able to proceed.

The Diary class will be a child of the Inventory, and it will hold all of the DiaryPages the user collects. Unlike Items, DiaryPages are not essential to the quest and cannot be dropped/used once collected. DiaryPages will contain clues and serve a purpose to provide more in-depth story. The user will be able to search diary pages for certain keywords (using binary search algorithm, think of a ctrl+f type thing) to uncover hints at what the user must do. Another variety of DiaryPages will be present, where instead of having a String containing all of the text, they will simply have an image. Both types will have a number corresponding to their page number in the diary, and the Diary will have a private method to sort the pages in order of their page number whenever a new one is collected. The Diary can be looked at anytime the user wishes, in a manner similar to the inventory.

How are we going to apply everything we've learned?

That's a good question! We've got it all planned out, mostly.

HTML/CSS

Well, you're looking at it! There's really not much more to say. Websites don't look this good naturally, you know.


PHP

A whole lot of PHP runs under the hood of this website. PHP is used to register a new user, log a user into the site, kick out users who try to access content without logging in, load top times from the server, and add and sort new times.



File IO

File IO is used by our PHP scripts to match the given username and password to those in our database, as well as add the information of a new user. Speedrun times are saved in a file on the server, so File IO is used to read and write to it when users wish to add their times.


Recursion

Recursion

Recursion

Recursion
Recursion
Recursion

Recursion

Recursion

Recursion

Each StoryEvent object has a function to display their narration, as well as the player's next options. Another function will be made to accept the user's input. If the player inputs an invalid option, the function will be made recursive to simply accept another input until the input is valid.


Binary Search

Binary search will come in handy when the user is given the option to scan the diary pages they collect throughout the game for clues or hints. The user will input a word, and the program will use binary search to look for that word in the content of the diary page. Binary search is also used in the login system, to find the inputted username in our database, as well as to ensure that new users don't choose a name that is already taken.


Sorting

Bubble sorting is used in the online leaderboard to sort the times from fastest to slowest. The game itself will use sorting to put the collected diary pages in order by page number. Sorting may also be used for a local high score system.


Immutability

Certain strings in the game can be made immutable, like the player's name. Story text won't be changed during the course of the game either, so it can remain immutable as well.


Visibility Modifiers

Most class members will be private because there is no need for state variables to be modified outside of their class. In some circumstances, visibility may be elevated, similar to the Player's hand in Crazy 8s.


Overridden Methods

Child classes such as Diary and DiaryPage will override some of their parent methods, since their behavior is slightly different. DiaryPages cannot be removed or used like normal Items, and Diary will have no method of removal. DiaryPage will have different methods than Item, because their content can be viewed by the user.


Multiple Constructors

DiaryPage will have two methods of being constructed, one with a String for the text, and one with an Image object for those pages with drawings instead of words. Pages with images would not the searchable. Both types of page would also take an int in their constructor to represent their page number.


Overloaded Methods

Functions to use an item, where some items can be used multiple times. In most cases, items are single use, but some items can be reused in multiple instances, so we can have another item use function that takes both the item to be used and the amount of times it can be reused.


Access Methods

Since we make use of classes extending ArrayList, we will need access methods to use the inherited methods. Access methods will also be used to do operations with state variables of Items and such which have private visibility. With access methods, we can avoid direct manipulation of each object's state variables.


Polymorphism

DiaryPages are children of Items, and are acquired in the same way, therefore since a DiaryPage is a Item, we can add it to the player's inventory in the same way and not create a whole new method of collecting diary pages.


Encapsulation

We will strive to keep the scope of variables as narrow as possible, as we have had memory issues in previous projects (ICS Sim 2017 flashbacks). We will avoid global variables as often as possible, but some objects like the player's inventory will need to be public.


Inheritance

The Inventory Class is where all of the player's collected Items are stored. It will be a child of Java's ArrayList. The Diary class will be a child of Inventory, and will be optimized to hold on the DiaryPage objects the player can collect throughout the story.


Constants

Most story events are unique, but there are a few that will be used it multiple places, such as "You died!" and "You can't go to that area!" events. These can be made constant.


Static Members

The StoryEvent and Item classes may have some static members used when initializing the class. Each particular item has a unique purpose and is usually essential to progressing in the story. StoryEvents will be numerous, there will be one for each narration-decision the player makes.


The Design Phase

Otherwise known as coding in your head.


Website sketches



Rough design for the login page.



Rough design for the homepage.



Rough design for the speedrun times modal box.


Rough Game Window Design





Prototype

Our progress so far.


UPDATE: I FIXED IT, I FORGOT TO ADD THE FILE THE GAME LOADS THE STORY FROM. WHOOPS


Super cool video!


Sorry for the horrible quality. We made up for it with good music.


Beta Version

Almost done!



How did we implement everything we said we would?

That's a good question! We managed to, mostly.

HTML/CSS

COMPLETED: Hahahaha. We couldn't have made this website without HTML and CSS. Designing this site, I've actually come up with a few ideas for my own website. Look at that, we're learning things!


PHP

COMPLETED: We got a bunch of PHP in this site, and we managed to get that binary search working (try registering with a username that's already taken), so props to us for that.
We made a whole chart explaining our PHP code in Stage 2, but here it is again if you want it.



We got all of our PHP goals accomplished, hooray!


File IO

COMPLETED: Oh boy.
This game wouldn't work without file IO. In addition to it's uses in our PHP code (see stage 2), we use file IO to load in all story data to the game (there's a file called story.txt, open it and you'll see what I mean). Each line in the file contains the information for that particular StoryEvent. Most of the work was actually done making the story, the code was the easy part. We didn't expect that.


Recursion

Recursion

Recursion

Recursion
Recursion
Recursion

Recursion

Recursion

Recursion + Binary Search

COMPLETED: This is our wombo-combo. Our binary search function in our PHP code is recursive.

NOT COMPLETED: We didn't end up making any of the StoryEvent methods recursive, though, it didn't really make sense to.


Sorting

COMPLETED: We have bubble sorting in our game to put the various diary pages the player collects in order by page number. This is helpful because the diary pages aren't mandatory to collect, so you could collect #3, #6 and #7 and they would still be in order.
There's also the bubble sorting we use for our leaderboard system here, as mentioned back in stage 2.


Immutability

COMPLETED: Like we said we would, we made strings like the player's name and some hard-coded story events at the beginning and end of the game immutable.

NOT COMPLETED: There's not that much of it.


Visibility Modifiers

COMPLETED: Most class members are private, requiring access methods, but there was one instance where the Diary window (a member of the main window) was made public and static, so it was not found in individual Window objects, and was referenced through the Window class (Window.DiaryView).

BONUS: We managed to not have a whole bunch of public static variables at the top of our game class for the first time ever. I guess OOP is working.


Overridden Methods

COMPLETED: The classes Diary and Inventory both inherit from ArrayList, and we override the add() and size() methods of them.


Multiple Constructors

COMPLETED: There are 3 different constructors for StoryEvent
1. Normal info
2. Normal info + int (for when we get a diary page)
3. Normal info + boolean + string (For when we get an item (true), or need an item (false))
These different constructors made writing the story.txt file a lot easier.

NOT COMPLETED: Remember what we said about DiaryPages having multiple constructors? that was a lie, we changed our minds about how DiaryPages would work.


Overloaded Methods

NOT COMPLETED: What we said about being able to use items multiple times never came to be implemented, and the item system we had in mind proved a little to complex for the type of game we were making, so we had to scrap most of it. There are 2 items in the game, neither are mandatory to beating the game.


Access Methods

COMPLETED: Since all of the members are private, all of the ones that change overtime need an access method. We're not really gonna explain all of them, but for example there are access methods to change the text/image in the Window components, because those change very frequently.


Polymorphism

COMPLETED: Like we said in stage 2, DiaryPages are subclasses of Items, so we can treat them both in the same manner. If only we hadn't scrapped the item system.


Encapsulation

COMPLETED: Keeping the scope of variables as narrow as possible was the name of the game, and we beat that game. We were very careful about our variables, and when to instantiate new objects. Keeping the amount of garbage low was our goal while making this game, and I think we did it pretty well.


Inheritance

COMPLETED: Inventory and Diary inherit from ArrayList, storing Items and DiaryPages. Window and DiaryView extend JFrame. That's some good inheritance right there.

SLIGHTLY CHANGED: Diary was originally planned to inherit from Inventory, but it proved wiser to keep them apart because the purpose of Diary shifted a bit from what we first planned. Diary required too many methods and variables that Inventory didn't, and it wouldn't have been logical for it to inherit from Inventory.


Constants

COMPLETED: In the DiaryView window, the player can scroll through the collected DiaryPages, and we use variables to keep track of the current index the player is viewing, the minimum index, and the maximum index. The maximum index changes depending on how many pages they have collected, but the minimum index won't ever change. That's why it's constant.
The Scream class (you read that right) has a String representing the path to the audio file, which never changes and so is constant.


Static Members

COMPLETED: As mentioned somewhere above, the DiaryView object is made to be a static member of the Window class, so there is only one of them.
We also use static members in the Window and DiaryView classes in the form of a couple objects used to load a font from a file. This font object is used in creating the objects, and aren't needed within the object.


Why aren't you seeing a lot of "NOT COMPLETED"?
Well we've actually managed to meet most of our expectations for this game. Compared to last year's final, this one seems like a breeze, because we didn't try and go too big and end up in over our heads. About 90% of our initial goals were met, the only big thing we had to scrap was the majority of the item system. We found that the hardest part wasn't the actual code, but creating a story that was in-depth enough to be even a little bit fun. There are 24 different endings, only one of which is the correct one. The rest are deaths.


Screenshots















Class Map


Our class map is broken up into sections, because the images are so large it'd be unreadable if I stitched them together.

Part 1 - Stuff that extends from JFrame


The Window class is the main window the user interacts with. It contains multiple graphical components, which require access methods, since their contents change frequently.

The DiaryView class is a second window that allows the user to view all of the DiaryPages they have collected so far. It has an array of file paths as Strings that point to the image for each collected DiaryPage. There are int values used to determine which page to show on screen. A DiaryView object is attached to the Window object as a static member, as we want only one of them.

Both of these classes extend Java's JFrame, which is the basis for a GUI in a Java program. They also implement ActionListener, which allows us to have code for certain events. We use ActionListener in Window to check for user input, and in both to check if they are clicking a button.


Part 2 - Stuff that extends from ArrayList


The Diary class is used to store all of the collected DiaryPages. It is from here that the DiaryView class gets it's information. It overrides the add() and size() methods of ArrayList

The Inventory class is used to store the player's items. It really isn't used as much as we planned, but oh well. It overrides the add() method of ArrayList.

A Diary object and and Inventory object is assigned to each Player object.


Part 3 - Item and DiaryPage


The Item class is used to represent an object the player can collect on the quest. It has a name. that's basically it, because we scrapped items when it became clear we wouldn't have time to implement them how we wanted to. These are stored in the Inventory.

The DiaryPage class is a special type of item that we did not scrap, because it adds to the spookiness of the game. These are scattered throughout the story, and are numbered. We store this page number as a String and an int. They also have an image associated with them, represented by a String file path. These are stored in the Diary, and viewed in the DiaryView.


Part 4 - Various other classes


The Player class contains a String to hold the user's name, two Date objects: one to hold the time they started playing, and one to hold the time they finished. There are access methods for both of those objects to set their values, and a third method calculates the elapsed time between the two so we know how many seconds it took to beat the game. This is the time code you enter in the online leaderboard. The Player object contains a method taking an item name as a String and will determine if that item exists in the player's inventory. Player also contains a method that uses bubble sorting to order the pages in the player's Diary.

The Game class is the main class, it's the starting point for our code. It has the classic fan favourite delay function.

The Scream class is mostly a joke. You'll hear what it's used for when you start the game. It contains a static String containing the path to that lovely audio file, and a File and Clip object to hold the file data. There are two methods: scream() and unscream(). scream() is what plays the file, just like the music in our other games, and unscream() is a failsafe that stops the audio from playing if there's an error.


Part 5 - StoryEvent


That's really big! You're gonna be scrolling back up to read it, this is the most complex element in our game.

The StoryEvent has 17 state variables, most of which are read from story.txt. The game starts off by making a StoryEvent object from the data from line 1 of story.txt, and that data plus the user's input (if needed) tells the game which line to make the next StoryEvent from. I'll explain the state vars in the order they appear in story.txt.

The eventText string is what contains the story for that event. It's the text that you see in the window. ("Mario arrived at Peach's Castle", etc.).

The imagePath string is the path to the large image that corresponds to whatever is happening in the story.

The npcPath is the path to the little image of whoever is talking (usually an image of Mario, sometimes others.)

The npcName string is the name that goes with the image of whoever is talking ("Mario", most of the time).

The options boolean represents whether the player is presented with options. If true, the game waits for the player to choose one of the options. If false, it advances automatically after 5 seconds.

The strings opt1 through opt4 are the actual options the player is presented with. These are the same words that appear underlined on screen. If there are only 2 options, opt 3 and 4 are set to "n/a", and if there are no options, (the above boolean is false), they are all "n/a".

The 4 ints opt1-4chap correspond to the 4 option strings. They represent which line in story.txt to read from next for each option, so for example if the player chooses yes we read from line 5 next, or if they choose no, we read from line 6. If an option is "n/a", the int that goes with it will be 0. If it is an automatic story event, the game will simply look at the first int option to determine where to go, all the rest are 0.

Sometimes we append an additional String at the end of the above stuff (we call the above stuff the "normal info"). This additional string represents the page number of the DiaryPage we pick up in that StoryEvent, and we use the diary sting for that. This is the second constructor.

Other times, we put an additional boolean and string at the end of the normal info. The boolean is stored in the item variable, and the String is the item's name, stored in the itemPickUp string. This is the third constructor.

On to the methods, we have access methods for basically all of the state vars, especially those that are shown in the window (eventText, the images, etc.) The access methods for the option strins and ints are special, because they take an int argument indicating which option we want to look at.

Sorry this was long, but since this is kind of crucial to the game we needed this.



Resources


We used a couple of resources in our game we found online.

The StretchIcon class was used to make sure the images we show would fill the JLabel entirely, instead of being rendered in their native size. It can be found here.

The PointyCaret class is adapted from the first answer found here.



Downloads



Walkthrough, so Mr. Krnic can actually see the end of the game without having to waste time dying a million times. Happy teacher = good mark



How to play....

The game is pretty straight-forward. If you downloaded the exe, just run it. If you downloaded the zip, extract all the files to somewhere else, and run the .bat file.

Take a look at this image. The words that are underlined are the options that the player has. The box at the bottom is where you type in your choice.
Some story events won't have anything underlined. Read these carefully, they will either be a yes/no question, or the story will advance automatically after 5 seconds.