MinStory
MinStory is a program that is designed to enable you to make your own “Choose your own Adventure”-stories and play them. You can use the editor to make your own stories, or create them by hand. The program comes with a “welcome”-story that you can use as a reference for how to make your own, and there is information in the manual.
System Requirements
- A 64-bit Linux installation
Download
File | MinStory-1_2_0.zip (36.1 MiB) |
---|---|
Release | Player: 1.2.0; Editor: 1.2.0, |
MD5-Sum | f2abc9f6ac50ec9331849eba7bd18f57 |
SHA1-Sum | b4cfc54feaa7d96a815af8137825e9999f9eeedc |
SHA256-Sum | 4f94f6f07ffe911999c9db9f4acbed36bb5544e4eec8925ee0697cf015e46ab9 |
GPG Signature | MinStory-1_2_0.zip.sig |
Languages
- English
- Norwegian nynorsk
- Norwegian bokmål
Features
- Play your own (and other people’s) stories
- Open stories packed in zip-files, or as xml-files
- Images, text and hotspots
- Create your own stories by hand or by using the editor
- Validate your stories using the xml-schema
- Export your stories to zip-files using the editor
Missing features
Things that might be implemented in later versions
- Better XML-schema, better validation of the story-files
- Safer Zip-export
- More informative error-messages
- Binaries for Windows and Mac
- The ability to scale/zoom in the story
- The ability to move/resize elements using the mouse
Known Bugs
- Sometimes an element that is overlapped by other elements does not show up on the screen
- If you export a zip-file that should contain two different images with the same name, only one of them will be used
Tools Used
Apache Maven, Cloc, Git, GNU Emacs, gnuplot, Inkscape, JavaFX, JUnit, OpenJDK 18, Org Mode, PlantUML, The Gimp
Versions
Player v. 1.2.0 and Editor v. 1.2.0
Under the hood much of the code has been updated to use features from Java 8 and later, such as Optional, streams, lambda expressions and method references for example. The build system has been changed from Apache Ant to Apache Maven, and the Java version upgraded from Oracle JDK 8 to OpenJDK 18. It also produces modular executables (using javafx:jlink), instead of a cross-platform jar file.
Some refactoring of the code has also been done, trying to favor composition over inheritance, and preferring immutable values. It’s possible that a bit too much has been done on the last point with regards to the practicality of using the TreeView. The code has also been refactored to create more specific observers/listeners instead of using java.util.Observer all over the place.
A lot of new unit tests have been added as well, which caught some mistakes while refactoring the code. There have also been some updates to the javadoc, including package documentation.
There are still unresolved issues in the code. While there are more specific observers/listeners, a lot of them have method signatures that are quite similar, making it difficult to spot which one is used. The new granularity has not been exploited fully in all places either, both the TreeView and the ScenePane do more work than strictly necessary when something is changed about an Element. The use of the TreeView probably also leaves a bit to be desired.
Player v. 1.1.2 and Editor v. 1.1.0
The most time-consuming thing this time was to create an xml-schema for the story files, but I managed it in the end.
Apart from that and bugfixes, the most prominent features are the preferences dialog, and the zip-export in the editor.
The zip-export uses standard java libraries. It works, but it might need some optimization. There is at least one problem with it—if a user tries to export a story that is using different images with the same name, only one of the images will be used.
Player v. 1.1.1 and Editor v. 1.0.0
The main new thing in this release is the story editor that you can use to create your own stories. The manual has also been updated with more information about the format in case you want to create one by hand. There are no new features in the player.
I’ve changed the way the graphical representations of the elements are made. In earlier versions each element had methods for creating a graphical representation of itself. That code is now removed, and the responsibility has been given to PlayerGUIFactory and EditorGUIFactory.
Version 1.1.0
The main new features are the ability to open stories contained within zip-files, which was implemented using the standard java libraries, and undo/redo functionality.
The undo/redo functionality is implemented in the class org.toregilhk.minstory.util.History, which is a generic list. Internally a standard ArrayList is used.
When adding a new undo/redo-point (moment) to the history, some additional calculations are taking place:
addMoment(moment):
If history is not empty, and the current moment is not the last in the history:
Remove all moments that occur later in the history than the current moment
Add the new moment
Set the current moment to the new moment
prune()
prune():
If the size of the history is less than or equal to its capacity:
Return
Remove the oldest moments so that the history once again is within its capacity
There is no method to remove a moment, since old moments are removed using prune(). If you want to reset the history you must create a new one.
While testing the program by opening story-files, I discovered that some files took a long time to open, and then popped up an error. The files in question were valid xml, but not story-files.
The reason that those files took a long time to open, turned out to be that they contained references to a DTD, and the program then started looking for them on the Internet. During this time it seemed like nothing was happened. To fix it, I’ve stopped the program from trying to look up DTDs.
“Under the hood” I’ve stopped using Subversion for version control, and now use Git instead. There has also been some refactoring to make the underlying code better. The manual is now written using Docbook. I’m also using reStructuredText to write notes for myself about what still needs to be done.
Version 1.0.0
The program uses DOM-parsing to parse an xml-file containing the story. The resulting tree is then traversed to create the internal representation of the story.
The program underwent a major rewrite during its initial construction. At first there was only support for Images and Hotspots. All the images were drawn onto a JPanel, and to detect clicks on a hotspot I checked if the mouse coordinates were within one of the hotspots. I wasn’t too happy about this design, since much of what I needed to do already was offered by awt and swing.
After reading a bit, I found that with some changes, awt/swing supported overlapping elements and custom layout managers. So I set out to redesign it to use that approach instead.
In order to support overlapping elements, I changed ScenePanel to override isOptimizedDrawingEnabled() to return false, thereby ensuring that a component would be drawn even if it was partially obscured by another. I also wrote a custom layout manager, OverlapLayoutManager. This uses the difference between the story’s preferred and current size to determine how to resize and place the components. It is designed to keep an aspect ratio of 1:1, and does not scale things smaller than the preferred size of the story.
The Hotspots are now created using NonOpaquePanel, where paintComponent(Graphics), paintBorder(Graphics) and paintChildren(Graphics) are overridden to do nothing. In addition, isOpaque() is overridden to return false. This leads to an invisible hotspot that can react to mouse manipulation and change the mouse pointer (to a hand to more clearly show that it is clickable).
The Images are created using a standard JLabel with no text and an ImageIcon. The ImageIcon, however, is a custom one. I found that the standard ImageIcon did not scale the image, so I subclassed javax.swing.ImageIcon and overrode paintIcon(Component, Graphics, int, int) so that it does.
The Text is just a standard JTextArea inside a JScrollPane.