7DRL: Zoo Tycoon Roguelike
When I discussed the 7DRL challenge with a friend, she suggested to make a roguelike modeled on Zoo Tycoon. Never having played Zoo Tycoon, I created a mockup, influenced by my friends description of how Zoo Tycoon works and memories of having played Theme Park:
I used ASCII characters to draw fences since it looked okay on my terminal. Many text editors and web browsers, however, do show ASCII characters with halfwidth glyphs, but show animals characters with fullwidth glyphs, as wide as two halfwidth glyphs. As this messed up the display, I created a second mockup using fullwidth characters:
I intend to start coding on at
, , and stop at . Before that, I wanted to write up a short roadmap of how I imagine the game that I plan to create.
I want Zoo Tycoon Roguelike to be a game where the player character is a hybrid between zoo keeper and zoo director, who is creating and maintaining a zoo: The player has to build compounds, care for the animals and make sure visitors like the place.
Like in the mockups, I want animals to be represented by Unicode characters.
Berlin Interpretation assessment
In general, I intend to follow the Berlin Interpretation with Zoo Tycoon Roguelike. The following table provides an assessment of the different roguelike value factors contained in the Berlin Interpretation regarding Zoo Tycoon Roguelike:
|Random environment generation||I do not see a huge venue for random environment generation in Zoo Tycoon Roguelike. Different terrain could provide a home for different creatures – long grass, short grass and water could easily constrain which creatures you could have in your zoo. Vegetation, like trees and cacti, could serve as nutrition source or just please animals in the vincinity.|
|Permadeath||This one looks easy: You die either when your money runs out or when an animal mauls you; in this game it will be a capital crime to be poor.|
|Turn-based||Zoo Tycoon Roguelike will be turn-based. I feel undecided if animals should have different speeds. Most likely I will just alternate player and NPC turns, so that every turn by a player is followed by a turn in which every NPC has a chance to move and vice versa.|
|Grid-based||The world of Zoo Tycoon Roguelike will be represented by a grid. I want the game interface to fit into a standard-sized terminal of 80 columns and 25 lines. I plan to have a non-scrolling map and a scrolling status window providing game commentary at the side.|
|Non-modal||Movement, building and pushing or pulling NPCs will occur in the same mode. I have no clear idea how to acquire new animals without a (modal) buy menu though.|
|Complexity||Zoo Tycoon Roguelike will have quite some animals – at least mice (🐁), chipmunks (🐿), rabbits (🐇), snakes (🐍) and elephants (🐘). Maybe it will also include a lone penguin (🐧) marching in the wrong direction, heading towards certain death. Animals will interact with each other, with vegetation and with visitors; snakes could eat mice, for example.|
|Resource management||Vegetation will provide food for animals when consumed, but grow back only slowly. Money will provide means to create infrastructure and might buy food for animals or the player character.|
|Hack'n'slash||Animals might fight each other, visitors and even you. When running out of food, you may have to kill and eat rare endangered animals.|
|Exploration and discovery||Nope.|
|Single player character||Yes.|
|Monsters are similar to players||Monsters, players and visitors will have wants and needs. For example, apes could be amused by seeing other apes behind bars and visitors could want to see at least three different animals before leaving. Also everyone will be hungry all the time.|
|Tactical challenge||Find out what visitors want and feed them tactical ice cream (🍨).|
|ASCII display||Haha, no.|
|Numbers||Character attributes will not be shown directly, but can be inferred from the running commentary that is provided in the status window.|
I started programming Zoo Tycoon Roguelike at approximately . As a starting point I used the source code of my game demo Unicode Tournament: I removed deadly and teleport tiles, replaced critters with animals and visitors and rearranged the widgets. I then drew a map with a text editor; like Unicode Tournament, Zoo Tycoon Roguelike loads the map from a plain text file. I plan to save to a plain text file as well.
There does not exist much of a game right now: Currently the player character (☺) can walk around and bump into NPCs, who are then pushed into the direction the player wanted to move, if they can move there. It seems that I have implemented convervation of momentum by accident: When several NPCs stand in line, bumping the first one only pushes back the last one, similar to a Newton's cradle.
The current state of the game can be downloaded using Git with git clone http://daten.dieweltistgarnichtso.net/src/zoo-tycoon-roguelike.git/.
I added the ability for the player to build barriers by pressing the meta key along with one of the arrow keys: If the targeted tile is empty, the player can build a wooden fence (┼), which can be upgraded to a chain link fence (╳) and a concrete wall (█). I plan to have building cost money, with more expensive barriers holding in stronger animals – an elephant could trample down a chain link fence with ease.
For implementing movement I started with the simplest possible NPC, the bus (🚌): For every move the player makes, the bus moves left, unless a bus stop (🚏) is in the same column. I quickly realized that this meant that the bus would wait at the bus stop forever. However, as the bus stop is a movable map object, the player character can just bump into the bus stop to let the bus continue on its way.
As it can be seen in the screenshots, the text in the status window is not always lined up. Apparently the widget library I am using – Urwid – misunderestimates the width of a line as one character too short for every Emoji character in the line.
According to Ian Ward, Urwid developer, Urwid tries to do the right thing here by using a lookup table with character widths, but interacts badly with the terminal emulator –
some of your interesting unicode characters are in a range that urwid thinks is width 2, but your terminal is rendering them width 1.
As I see a fixed grid as desirable for Zoo Tycoon Roguelike, I fixed the rendering bug by deleting Urwids str_util.so; Urwid then falls back to the Python version of the library, which Zoo Tycoon Roguelike monkey-patches at runtime to assume all characters have width 1 using
urwid.old_str_util.get_width = lambda x: 1.
I am refactoring the movement system; currently the map moves NPCs around, but I want them to move by themselves. As a preliminary step I added a
tick() method to NPC objects. This method is called every round for every NPC; currently, it only outputs text to the status window.
As soon as NPCs can move by themselves, I want to implement a rock-paper-scissors type relation between mice (🐁), snakes (🐍) and elephants (🐘): Mice fear snakes, snakes fear elephants and elephants fear mice. Movement abilities could compliment this, with mice being able to tunnel under walls and elephants being able to tear wooden and chain link fences down.
I spent the first few hours of the second day of the 7DRL challenge implementing movement. Most NPCs currently have a ten percent chance to move into a random direction. Buses still move to the left every turn and stop at the bus stop, but start moving again as soon as the next bus comes. To enhance realism, a collision with a bus is deadly.
Having implemented NPC movement, I chose to work on fleeing and preying behaviour. Both fleeing and preying behaviour are activated in the
tick() method of animals: Each turn, an animals first flees if necessary, then moves randomly, then hunts if possible. This may lead to interesting emergent behaviour; not only did I see a snake hunting a rabbit until it was run over by a bus – the bus movement was triggered by the rabbit bumping into the bus stop while fleeing.
I thought about giving NPCs weight or strength to prevent a rabbit damaging a bus stop – but for the time being, I just find it too funny. I will probably hardcode elephants being able to damage fences, though.
Animal reproduction in Zoo Tycoon Roguelike is entirely asexual: When two animals of the same species stand next to each other, each one has a chance to spawn an animal of its own species on an adjacent empty tile. Currently, mice have a chance of 20% to reproduce, while rabbits have a chance of 10%. To ensure reproduction, fencing in animals may be necessary.
Any food chain starts with a producer species; for Zoo Tycoon Roguelike, I chose grass to fill that role. To represent the growth states of grass visually, I use the aegean numerals one to eight (𐄇, 𐄈, 𐄉, 𐄊, 𐄋, 𐄌, 𐄍, 𐄎). Grass can grow and spread to an empty adjacent tile; after a bit of experimentation, I found a transition table that produced good-looking results:
|State||Next state||Chance of growing||Chance of spreading|
Grass can be trampled by elephants – whenever an elephant moves onto a tile, its terrain is replaced by a space ( ). Grass can also be eaten by rabbits whenever they do not move, reducing the corresponding aegean numeral by one. Currently, eating grass does not increase satiation, but I want to implement that.
During testing, I noticed animals reproducing faster than grass when in crowded conditions. To slow the animal reproduction rate for that case, I modified the reproduction method: Reproduction now can only occur when only one other animal is near.
Until now, I had implemented hunting prey, but did not implement eating prey; this led to predators moving towards their prey even when standing right next to it and pushing it farther away. I implemented eating, so predators can eat prey now. Like with grass, eating prey currently does not increase satiation – predators are always hungry.
Satiation and starving
Animals in Zoo Tycoon Roguelike start with 100 points of satiation. Moving costs a point of satiation, fleeing costs a point on top of that. Eating grass gives 4 points of satiation, eating animal prey gives 50 points. Predators are only motivated to hunt if satiation is below 75 points; reproduction now only occurs when satiation is over 50 points, with the act itself costing 10 points.
At 0 points of satiation an animal dies and is replaced by an animal carcass that takes 25 rounds to fully decompose. I plan the animal carcass to be of nutritional value, in case an animal is hunted to death.
This simple mechanic results in almost all of the animals in the game living a very short life, since I have not implemented any food sources for most of them. The two exceptions are rabbits, who feed on grass – and snakes, who feed on rabbits.
When a friend of mine built a wall on the street while playtesting Zoo Tycoon Roguelike, the bus just stopped. For added fun, I chose to implement explosions.
A friend of mine was unable to get his terminal to recognize the meta key; as a workaround, players can now build barriers by pressing the ctrl key along with one of the arrow keys. Elephants can eat grass now – three times as fast as rabbits do, if possible. Barriers can now be built on all traversable terrain, not just spaces.
On this day, I did not do any programming for Zoo Tycoon Roguelike as I had a date. We ate interesting sandwiches, drank delicious hot chocolate, drank acceptable wine, ate tasty pizza, cuddled and had mediocre sex. In the morning I showed her Hyper Rogue, which quickly replaced Candy Crush Saga as her time-waster of choice. I caught her checking out other roguelikes on her phone later.
From time to time, truck drivers will abandon their exotic pets at the roadside, bound by a leash to a delineator. In the world of Zoo Tycoon Roguelike, this is how a zoo gets new animals. Note that animals on a leash will not move, so they will not interfere with traffic. They will, however, die of starvation after a while.
Players can pull NPCs by pressing the ctrl key along with one of the arrow keys; this moves both the player and the NPC standing beside the player on the opposite of the chosen direction into the chosen direction if it can move.
Pulling makes it possible to move abandoned animals to safety. I originally made the leash break as soon as the player character pulled it; unfortunately, this made the corresponding animal move normally, hence hard to control. I therefore chose to make the leash move the animal beside it whenever it was moved.
I quite like the minigame that rescuing abandoned animals has become. The sense of latent urgency that the impending starvation of the animals creates reminds me of the subtle horror in Cataclysm: Dark Days Ahead – where a zombie bite can set off a race against the clock to find antibiotics.
Visitors are another type of animal that Zoo Tycoon Roguelike has to offer; they come in two flavors, adult (👨, 👩) and child (👦, 👧). Both adult and child visitors prey on french fries (🍟), soft ice cream (🍦) and donuts (🍩); adult visitors also drink beer (🍺) while child visitors eat candy (🍬). Adults only want to eat when their satiation is below 50 points; children always want to eat.
Each turn, a bus at a bus stop has a ten percent chance to create a visitor. Since visitors are not afraid of anything they get run over by buses frequently. A friend suggested I make them afraid of buses – but then how could they leave the premises?
I plan to give visitors a list of animals they want to see and a preferred direction that can be manipulated using player-built signposts. And yes, I am certainly aware of the video game cruelty potential the latter offers.
Over the course of the fifth day of the 7DRL challenge both bus and truck drivers have learned how to drive on the right side of the road. If driving in the wrong lane, both have a 20 percent chance to switch to the right lane when encountering a median strip (▔).
Field of view
Animals can now check if another NPCs of a specific type is near them. Their
see() method checks every tile with a taxicab distance of one, two or three from the source tile for an NPCs matching the given character argument and returns
True if it occurs. Currently, this method is only used for zoo visitors, which have a list of animals they want to see: When a visitor sees an animal from the list, it triggers a message in the status window.
Visitors can have a preferred direction that they move into randomly with a chance of ⅝ (62.5 percent); they have a chance of ⅛ (12.5 percent) each to move into a non-preferred direction. The preferred direction can be manipulated using signposts (🠴, 🠵, 🠶, 🠷); a visitor that sees a signpost (see previous section) changes its preferred direction accordingly. Signposts can be moved by the player and NPCs.
I am undecided yet whether the player should be able to build signposts in a way similar to barriers or have a fixed supply of movable signposts. The former would make gameplay faster, but necessitate additional key combinations; the latter would make gameplay slower, but could also make it more fun – imagine moving a signpost through a crowd of visitors who suddenly all change direction.
I rewrote the error message regarding the rendering bug as several playtesters thought it too vague and some even found it scary to delete a file. The message now reads: Zoo Tycoon Roguelike will have rendering bugs with your current configuration. To fix this, delete the file “str_util.so”, usually located in the folder “/usr/lib/python2.7/dist-packages/urwid/“. Deleting “str_util.so” is safe; Urwid will fallback to a compatible but slower implementation.