1. Introduction RAD was sort of a waste of time, but it may give you some idea of how I will now plan out the actual implementation of the game. Now we can get into the development meat of the project. 1.1. Purpose of the System The purpose of Kouriku Snow is to replace GemSlider in such a fashion that adding and defining new types of tiles should be relatively easy for expansions in the future. The game design should be simple enough, and the level editor should be intuitive enough to realistically expect some people who would be interested in designing levels with me. 2. Current Software Architecture The current architecture is GemSlider. The fundamental flaw is with the game engine itself. Everything else I'm pretty okay with at the moment. The problem is that the level is simply an array of letters. Whenever the player moves in a direction, an appropriate procedure scans the level and determines what each letter should do in this circumstance. Eventually I put a layer (3D array) underneath the level so that certain letters could be pushed down when another letter went past it. There was no variety in the kinds of tiles or gameplay. It used to be, the player pushes the button: -Determine the direction. Scan from the end and work way back to the start, moving each appropriate tile as I found them. -Continue repeating this scan until nothing is moving. 3. Proposed Software Architecture The first change I want to make is instead of having a letter, have a Tile structure (remember, I'm using C. It may look O-O the way I use it, but it's not). This way, I can find out all sorts of things about the properties of the Tile without having a procedure "memorize" what the letter is supposed to do in all circumstances. Another thing I noticed was that I scan the whole level when I want things to move in a direction. This is kinda dumb. I think I should have a "list" of co-ordinates which tells me the 2D co-ords of all the current Moveable objects in this array. The level will still be an array, but instead of having an extra layer to "push" tiles down when other tiles go past, have a linked list. So, when I "push down", just add a Tile to the previous and have that take it's place. That way I can push down as many times as I wish on just one tile, and I don't waste space everywhere else. Now when the player pushes a button: -Each moveable tile is told to move. The tile returns it's co-ords if it is Moveable. -Level takes all co-ords. It then iterates through this list. It goes to the next set of co-ords. It asks the tile which direction it will move in. It compares it with the object ahead and does whatever. -It continues to iterate until the list of moveables is null. -NOTE: If it finds a co-ord with more than one tile, it will ask each tile, determining first if it is Moveable. 3.1. Persistent Data Management All userfiles will be stored as simple flat files. All levels will be stored as simple flat files. All graphics, sound, music, and anything else associated with the world, worldmap, or menu will be stored as a datafile (zipped serialized data). 3.2. Access Control and Security Access will be controlled through a keyboard driven UI. No security issues. 3.3. Global Software Control Procedural-driven control flow. 4. Subsystem Services I've decided to use a Tile structure. It will be general enough to be able to define any type of tile, so I will not have any subclassing whatsoever. Tile.c PlayTile -Type : An enumerated type that will tell us the name of the Tile. This is mostly for some basic logic and painting. -Moving : Is used to tell us in which direction the tile is moving in, if it has stopped, or if it must be pushed. -Liveable : Is the tile alive? -Moveable : Will the tile move when key is pressed? -GivesDirections: The tile will give a direction to another if asked. -ForceDirections: The tile will force it's pointat direction on another. -PointAt : This is set to NONE or N, E, S, W. If the PointAt is set, then it will give that direction to a tile it touches. Otherwise it will give the direction it is moving in (N, E, S, W). -Colour : This tells us the tile's colour. -Alignment : Tells us if the tile is a Hero, an Enemy, or a Neutral. Heroes and Enemies kill eachother. -Murderer : Will the tile kill *every* Liveable it touches? -Suicidal : Will the tile die when it kills? -Important : If an important tile dies, the level is unsuccessful. -Collect : Set to either NO, COLLECTWAIT, COLLECTMEWAIT, COLLECTOR, or COLLECTABLE. Collectors will collect collectables. When all collectables are removed, collectors become collectables and COLLECTWAITs become Collectors. COLLECTMEWAITs become Collectables. If Collectors collect all collectables a second time, the level is completed successfully. -DirType : Enum type that tells us if it accepts keypress moves like Pid, like Flames, or like Blocks. -Movement : These four fields are boolean flags, they tell us what directions are allowed to be taken by this object when it is ordered (not by keypresses, but another tile). If a direction is ordered upon this tile and it isn't allowed, we ignore the order. -InTheWay : Does it take up the rest of this tilespace, or will it be pushed down? -CoordX : -CoordY : The current 2D coords of the object. The logic on the interactions between two tiles when they meet: -Tile A is the tile that is currently being moved by the engine. Only one tile is moved at any time; it is when all moveable tiles have taken a single step that the screen is updated. -Obviously if Tile A touches more than one Tile (due to multiple tiles in the same tilespace), it will have conversations with the topmost tile and continue downwards to the bottom. If at any point in 1st conversation a tile is 'killed' and was considered important, the board ends unsuccessfully. 1) Tile A runs into Tile B. Tile A asks Tile B about colour. If one of the tiles is inactive, the conversation jumps immediately to 3rd conversation. Tile A asks if Tile B is a murderer. If it is, Tile A dies if Liveable. If not liveable, continue conversation. Tile B will ask itself if it's suicidal when it performs a kill. If it is, Tile B is also removed from the board. Tile A asks Tile B about alignment. If Tile A and Tile B have opposing alignments, they kill eachother. Tile A asks Tile B about collection status. If a Tile is collectable and another is collector, the collectable tile is removed and recorded. If Tile B is removed, then Tile A moves into place. If there are still tiles remaining, Tile A has second conversation. Now we move into another conversation where Tile A and Tile B must determine who gets right of way or is shoved off. 2) If Tile A forces directions Tile A will force a new direction upon Tile B if TileB is in the way. If Tile B forces directions Tile B will force a new direction upon Tile B if TileB is in the way. Tile A asks about the DirType of Tile B. If Tile B is of type Block, Tile A will give a direction if it GivesDirections. If Tile B says it is now moving, then Tile A will not stop. else If Tile B says it won't or can't move, Tile A will stop. If Tile B is given a direction, then it WILL be the next tile to be checked for motion. Then Tile A will again be checked for motion. For this current action, we simply abort and wait to repeat after checking TileB. Forcing gives PointAt direction. Giving gives current motion. The final conversation determines where Tile A stops. Either Tile A is going to be in the same place as Tile B by the end of this whole thing, or Tile A will stop in it's current position. 3) If Tile A or Tile B has an INACTIVE colour, it is considered not InTheWay. Simplify. If Tile A is InTheWay and Tile B is, then Tile A remains at current position. If Tile A is and all tiles at Tile B is not, then push down tiles at position of Tile B. Tile A is at top. If Tile A is not, then append Tile A to bottom. After all motion on the board has finally stopped, all tiles of Block must be set to Push in their Moving type. Push and Stop are equivalent. The difference is that if a Push type is given a direction, then it will become moving. If a Moving is stopped, then it becomes Stopped. WallTile (Defines Walls and Holes) -Colourful : Tells us if it has colour. -StopType : Enum telling us how the wall stops things that touches it. Also, we'll need a level. The level keeps track of the array and also has functions it can call. Level.c -Has a linked list that keeps track of the co-ordinates of all current Moveables that are Moving. -The current number of Crystals left in the level. -The name of the level that has been loaded. -The current number of moves that the player has used. -The previous score, or told unfinished. -World Name. -The level array such as it is. -A set of functions that test interactions between tiles. World.c -The filename locations of all 15 levels. -The co-ord locations of each level on the map. -A datafile which it passes to the Paint function to tell it what to do. -A collection of all the information from Level.c, such as #moves, #crystals. -A reference to the playerfile. Worldmap.c Menu.c Kouriku.c (This is the main driver). Player.c (To keep track of and write to player files) Paint.c (The paint subsystem that will do the paint functions for any of the other subsystems). Sound.c WorldList.c The single linked list that keeps track of all Worlds for WorldMap. LevelList.c -The single linked list that keeps track of all the levels loaded by World. MovingList.c -The single linked list that keeps track of all moving co-ords for level. PlayerList.c -File called "Players.lst" will tell the PlayerList the filename for all players in the system. -The single linked list that keeps track of Playerfiles. -It also loads all the Players into existence. -A Player Filename contains the following information: Name #Moves #Crystals Found #Crystals Used #Bonuses #Levels Complete The Datafiles Local Datafile World Datafile All bonuses and features will be accessed through Menu.c, but will not be documented here.