Welcome back to another edition of Voxatron's development diary. The game is available in alpha form (with access to all future updates) here. There's also an updated development plan if you'd like a broad feature-centric summary, and a FAQ.
Recently Voxatron has been going through a kind of annealing process; many sub-projects jostling for position as it becomes clearer how they interact with each other. I've collected a large wishlist of engine features and gameplay ideas, and now the goal is to gradually boil the whole thing down into something that is technically possible and creatively in self-agreement. The temperature is getting a bit cooler now, and it's clearer what form features will take and which ones will get squeezed out.
So, here's a run-down of some of those sub-projects in roughly the order that they'll show up in future updates..
0.2.1 & Twisty Castle
This one is already done, if you missed it! The changes in 0.2.1 were designed to provide everything needed to make a basic exploratory adventure level. Some of the new features (collect-once items, use-once doors, checkpoints) are stop-gap solutions until nearer the end of the engine's development cycle (v0.4).
You might recall the sci-fi level that Anthony was working on in the last diary entry. This level turned out to be too ambitious in terms of working with unfinished engine features: persistent inventory items, scripting and custom monster design and sounds. So instead we decided to shelve it for now and go for a simpler short-term demo adventure. This way I don't need to rush temporary code in to get things working, and Anthony doesn't need mock-up parts of the level by making cardboard cutouts and manipulating them in a doll-like fashion.
Zoot is a map-based adventure with around 10 locations that you don't need to complete in order. It includes the first custom object (animations), along with new physics and a water base type.
In v0.2.*, there is only one type of definable object: the humble prop. Props are burnt into the map when they are activated but are otherwise static and not very interesting. The 5 new types of customisable objects I've made for 0.3.* updates are:
ANIMATION: floating multi-frame props that don't interact with the world
PICKUP: trinkets with definable scores and messages
DOOR: define open, close animations and collision size
MONSTER: define some stock behaviours with parameters
PLAYER: replaces the _char hack, and allows variable sized players
These objects share much of the same groundwork, so although I'll release them in separate updates, each one won't be so far apart. It's just a hop skip and a jump from collectable turnips to magnificent creatures!
It's now possible for objects to push and sit on each other, and for the player to pick up objects and throw them around. To test this, I added good old fashioned crates to improve Voxatron's OMM Crate Rating.
The existing monsters will remain roughly as they were, but it's now possible for tinymon to run around on your head, and will allow riding moving monsters/objects (good for moving platforms etc)
One requirement of customisable objects is the ability to edit multiple frames per object. In order to do this, I've created a unified resource tree. Instead of having the current set of 6 'banks', with each voxmap having a set of frames, objects are instead store in one big tree of any depth. The whole thing is like a kind of file system; banks become folders and objects are the files. This will still take a bit of work as it requires a nicer interface for browsing, but there are many advantages:
- easy to organise rooms into groups (e.g. a folder called "Forest", which contains "Castle").
- share branches of the tree on the bbs, rather than VOBs
- objects are indexed by a global_id, so possible to re-order, delete and move objects around the resource tree
- the tree can be used to store whole level files near the root (and so allow multiple open files)
- animations can be embedded inside objects and used to elegantly represent events (e.g. a door opening)
- use it to store other types of resources later on (music, sounds)
- can alias branches of the tree to external files for very large projects with shared components (e.g. my v1.0 world!)
Water is something I needed for the v1.0 world anyway, but after Anthony animated some great water using the new animation tools, I couldn't resist bumping the water base type forward so that I could make it more interactive. The above image is a scene from Zoot with hand-animated water crashing up against the rocks. With a base water type, you'll be able to float objects on top of it (or in the case of hostile rough water, bob around for a moment before dramatically disappearing below the surface).
There are two possible schemes for water: a 2d heightfield, where water covers the whole level and can only exist at one layer (see lava) -- or generalized water that can exist at multiple levels (and in separate pools). The second type is much more difficult, and I'm still exploring possible approaches with varying degrees of success:
Numerically unstable water
This comes under custom objects, but I know it's one of the more anticipated features, so I should give you a bit more detail about what the first version is looking like.
0.3 monsters won't have scripting (see below), so instead I've opted for a template system for doing basic monsters. This is probably a better approach in terms of usability, as you can get quite far without needing to learn the intricacies of scripting. Instead of typing in a bunch of text describing a basic monster's behaviour, you can do it by filling out a form (and drawing some frames of animation).
Each monster has a set of behaviours with parameters that can be adjusted with several sliders and checkboxes. For example, you might want to turn on jumping and then specify how frequently / high the monster jumps, and if it jumps out of the way of bullets, or at the player if they are close-by. In the current design, I've also allowed for some shooting attacks (although, this will become more flexible with scripting). You'll be able to draw the bullet animation, specify how many bullets and what kind of bullet formation each attack has, and the behaviour of the bullets (e.g. no gravity, seeking).
Special voxels: Some special voxels are already usable in 0.2.1, but need better tools for managing them (negative voxels that subtract sections from the world, indestructible voxels). Other types I've tried that look promising and will probably appear soon are deadly voxels (invisible voxels that hurt you e.g. to put on the tips of spikes) and crumbly voxels (cave in easily when shot or pushed)
Cellular automata: Voxels that have per-frame behaviours based on the state of their neighbours, for example sand that naturally settles into a cone-shaped heap. This was fun to try out, but ultimately not very useful for designing levels and slowed the engine down too much. It has been useful for providing insights into how to general water however (which I might write about later if it works out).
Scripting / Events
In the last diary entry, I mentioned an event system that I thought would be a powerful addition to scripting that I could add in 0.3. This turned out to be a mirage. As I added more functionality to the design to justify its existence, I found it converging on being a full text editor-driven scripting system. e.g. if you have a list of event conditions and actions, and you can shuffle them around and change chains of binary operators between them, it really starts to look like a text editor. It's better just to make a text editor!
Instead, I'll keep events as a minimal interface-level feature in such a way that it can optionally be mixed with scripting. This will also make it a more flexible replacement for the triggering system. This might not make much sense yet, but here's a simple example:
Say you want to open a door when the player collects an apple.
In the v0.2 scheme, you'd group the door and the apple, and then set the door to TRIGGER_PICKUP
With the new scheme, you can add an event to apple (PICKUP), and an action (ACTIVATE DOOR (and pick out the door)).
You can specify multiple events per object, so there is no limitation caused by only being able to add each object to a single group.
When mixed with scripting, the action can be replaced with a short script (that you type into a box) that can do more precise things if needed. For example, only open the door if all of the apples in the same group have been collected, or flip the state of the door (if it's already open, it will close and vice versa).
I've settled on Lua for scripting. It's a relatively easy language to learn, and a popular choice for other games. It also meets Voxatron's technical requirements -- tiny embedding, fast, can run without floating point math, and interacts nicely with C.
LEX500 Palette Test
This project isn't part of Voxatron per se, but is something I've wanted to do for a long time and has suddenly become extremely relevant.
LEX500 (working title) is a little program for making low-res 2d games (160x120, 16 colour). It has a built-in sprite, map and sound editor, and allows the user to write games in Lua (surprise). The programs can be shared on this BBS, along with replays and new levels.
The great thing about LEX500 is that it can be built almost entirely out of components from Voxatron. I haven't done much work with scripting for games, so it's a great chance to prototype ideas that will eventually become part of Voxatron, and hopefully avoid some bad design decisions.
Some other advantages of making LEX500: 1. It will be a nice way to introduce players to scripting in LUA 2. It will attract more coders/designers and retro game affectionados that might become part of the Voxatron community and 3. It will be extremely fun to see what kind of programs people come up with!
I'll get into this after the 0.3 series of updates are finished.
I did a bit more work on world persistence (e.g. shoot some dirt and it's still gone when you come back to that room or load your saved game). Keeping the state of rooms stored in memory is very tied up with custom objects and scripting, so it will probably become available in 0.4.
Persistence also requires quite fancy loading/saving, and complex backwardly compatible save files is not something I want to rush into early (bug-prone and heartbreaking to lose save game data).
The saving scheme is quite cute, I think. Every time you leave a room, the state of the room is appended to the current save game file. So it's very fast to save, but you end up with one long save game file that takes a bit longer to load (around a second for a long game). A nice by-product of this is you end up with an entire recording of the game and could conceivably rewind to any previous time (including moments mid-room if key-press sequences are also stored). I'm not sure how useful this will be but I think it's a nice possibility to have.
Future Game Mode
Voxatron was originally supposed to be only a Robotron homage using my voxel renderer (hence the name) because I thought my plans for a map editor & grand adventure would take too long. After quickly prototyping the arcade version (which is still basically the same as the current arcade mode), I encountered so much passionate interest in the game that I decided to go ahead with the adventure part anyway. Because the time it takes to make would pass anyway.
If you have a look at the updated development plan, you can see the project has roughly 4 parts that correspond with game modes:
0.1->0.4: Adventure Demos (+ engine & tools to support them)
0.5: Arcade Mode
0.6: Battle Mode (local multiplayer)
I'm not doing much work on 0.5->1.0 at the moment, but I keep coming back to the designs so that I know the engine will support what I need, and to keep the original vision of the game alive.
The current design for the 0.5 arcade mode is a wave-based thing (like Robotron and many shooters), but with procedurally generated waves. I've been experimenting with how to make this interesting and fair: the sequence of monster entry and terrain changes might be easier or harder on any given play-through, but the challenge is to identify that you've been dealt a good hand and have the composure to capitalize on it.
Many of these high-scoring opportunities comr about from combinations of temporary powerups, bonus multipliers and side-arm characters. If you have a side-arm bunnoid (robotic rabbit) and it seems to be working effectively with a triple shot modifier, you might be tempted in the midst of a thick wave to go for a duplicate and bonus multiplier combination lying in close proximity. I want these moments of brash glory-seeking, for the death of your vital bunnoid to feel truely tragic, and the out-gunned vain attempt at redemption equally sweet.
0.6 I haven't looked at much yet. But it will be a varied player vs. player arena thing driven by an assortment of weapons, pickups and objectives. Because 0.6 will come out after scripting, it will also be possible to design your own PvP games that might not even resemble Voxatron. Tennis, anyone?
1.0 comes with the main Adventure mode. Lately I've been working on new music for this, which I think is a great way to design and remember the feeling of pivotal scenes and locations in the game. The story follows 3 main characters: a girl, a robot (the robot) and a fox. Each character represents different styles of play (adventure, arcade, rpg/rogue-like), and so the music has roughly divided itself into 3 groups: incidental thematic music (like Jasper's Journeys, or the original Prince of Persia), thumping action music (a continuation of the style used in Voxatron trailers / arena rooms), and meandering background music that adapts to circumstance (for the fox's dungeon spelunking).
Voxatron's music and sound is generated on start-up with a little modular synth. I updated it for 0.2.1 to get some more sounds out of it: for the hellephant boss's trumpet and more instruments for the music.
At some stage it will be necessary to allow the player to design their own sounds to go with custom monsters and objects (and music!). I made a visual interface for this, but it's still way too cryptic for the average user. Later I'll add some sfxr-style 'wizards' for generating common groups of sounds easily from templates: thuds, grunts, pickups & explosions etc.
Synth definition for the large explosion sound
Bit-7 Physics (Failed Experiment)
The voxels in Voxatron are represented as 8-bit values, meaning there are 256 possible colours for each voxel. So far I only use around 64 of them and want to keep the palette quite small. So I always knew there would be a spare bit (bit-7) available should I need it for something.
I learnt, once again, that just because something is possible it doesn't mean you should do it! In this case, the possible thing was voxel-perfect physics and collisions. i.e. instead of defining a size for each object in the world, the engine just looks at what the object is made of and calculates the weight and collisions based on that.
This is where bit-7 came in. I tried adding a 'ghost' layer to the world that disappears at the end of each frame. Every object draws themselves into the ghost layer every frame, and that information is then used to calculate (down to the voxel) when monsters crash into each other, walls, land on each other, etc. This way collision code only needs to read one source of information -- the world map -- rather than consider the world and objects separately.
I won't go into detail here why this didn't work out. But briefly:
Slow: even just clearing the 7th bit of the 256x256x48 map at the end of each frame is pretty expensive (the world state is updated at 120fps)
Ambiguous: when there are overlapping monsters, it's difficult to determine if they're colliding with their own voxels or each other, and when to allow collision exceptions that allow objects to untangle from each other.
Bad feel: even when it functions "correctly", it just doesn't feel good. Even though it might seem like a beautiful unified system from a programmer's point of view, in practise it's more comfortable for a player to abstract objects as some simpler geometric shape. This is especially true when you introduce animation and turning -- if a walking animation puts voxels inside a wall, or prevents movement that the player would have otherwise expected, the results are counter-intuitive. Basically it requires the player to keep track of too much information.
[As a side note -- this is similar to the reason I don't like gangly characters in 2d platform/action games. It's difficult to ascertain quickly what the state of the world is. I like beany characters like mario, meat boy and the worms in liero.]
Too much work for the designer: even though this scheme requires the designer to define a size for each object, they still need to define which frame should be considered the active physical mask of an object for any given point in time. Sometimes this shouldn't be the one being displayed, or should be the combination of several frames (e.g. body + feet)
So I went back to bounding boxes, and everything was swell. Bounding boxes aren't such a bad thing visually in Voxatron because many characters and objects look best blocky anyway.
I made a flash version of the Voxatron engine using Adobe's experimental Alchemy compiler. I signed up to try out the beta of their commercial version which may generate faster code, but for now it seems to be reasonably playable. In the future this will be useful for sharing or previewing levels & replays, and maybe demos to attract more players.
Try it here
Shadow volume rendering
This will probably come out closer to 1.0 too, but I did some more experiments with varied lighting. One significant breakthrough I made was finding a nice way to generate 3d shadow volumes quickly, rather than 2d shadow maps. This will allow for effects like light emitted from a lantern that the player is carrying (well.. actually that's all I wanted it for). I'm storing the shadow state in Bit-7 (that I mentioned earlier -- it WAS useful!) and sampling that to get the soft shadows. This is great for cache performance, as organizing data to be efficiently accessible for a game like Voxatron is very important.
Because of making the flash version (and renderer changes), I was prompted to do a bit more optimisation. Running the game and software renderer in a virtual machine is kind of a crazy thing that I never imagined would be possible, but it does require everything to be humming along efficiently. Testing under flash was a good way to expose inefficiencies in the gameplay logic that earlier profiling didn't pick up, and I was able to more than double the average performance. If you play a long arcade mode game and then PLAYBACK->SKIP PLAYBACK at the end you can see the result of this: the entire game is re-simulated in a few seconds. This might prove to be useful when randomly seeking playbacks, or journaled level files that include player input.
The last major feature that I'm still not sure about, but am dearly holding onto, is online multiplayer. The current speed of the gameplay logic is a good sign in this department. There is probably too much going on in Voxatron to send data describing the whole world state, so there needs to be a fair amount of independent simulation going on. I tested a promising model with this in mind: by keeping two copies of the world state in memory:
state_1: the state of the world at the time when all players keypresses are known
state_2: the current local state of the world
.. so that only player keypress data needs to be sent across the network (along with initial world state and error-correcting patches). Each frame, the world is re-simulated from state_1 using incomplete player key data (complete for the local player) to produce state_2, which is what is displayed. A cut-down version of the gameplay logic can be used for this, which ignores things like bits of dirt flying around.
So network play is looking good so far, but I'm yet to see how it does under typical network conditions and with scripting. Eventually Voxatron will become a general game-maker like program, so it would be wonderful to be able to make networkable multi-player games without even caring how the networking is happening.
This blurry image is Voxatron running in glorious full resolution monochrome on a real-life, Help-me-Obi-Wan-Kanobi, volumetric display. More on this soon!
Pico Pico Cafe
Lexaloffle Games is now also Pico Pico Cafe, which means "Pixelated" or "low-fi" in Japanese. The idea behind Pico is to provide a public space people (including me) can go to work on creative things, to test out games on unsuspecting visitors, and drink coffee. Hopefully someday it will also be home to a volumetric cabinet of Voxatron, so that anyone can drop by and try out their levels in 3d. If you're visiting Tokyo or nearby, please do come by and say hi (or better yet, bring a laptop or notepad and make some stuff).
Next up is 0.3 with Zoot and support for animations & water. It should be out in 2-3 weeks if all goes well, so please check back here or sign up to the newsletter to be notified when it's available.
P#6572 2012-09-14 21:01
All those features sound amazing! I really look forward to see how these turn out! (specially the water!)
The ammount of work going behind this game is outstanding. I had no idea so many things were being planned.
Now I want a volumetric display :3
P#6573 2012-09-14 22:00
I especially like how you take into account all the little resources to be used in one way or another, but being careful to know when something is not gonna work, or is going to compromise some future feature, its playability, or feel of the game.
Yes, the water is really cool! I definitely would love to see that in the game, even if with limited physics. Or even just animated, if the physics prove to be too costly. There could be just a new "water voxel" in the pallette and players could animate it themselves :)
It would be awesome if Voxatron could have lots of voxels with different properties...
like the Powder Game but in 3D ! But that would probably melt the computer xD. Maybe some more years down the road that can be possible.
But it will have much cooler stuff like the animations, the enemies, the scripting... ^_^ I can easily picture this game getting ultra famous in the years to come, much more than minecraft or the like!
P#6574 2012-09-15 07:52
I won't be able to use scripting a lot at this moment if it gets released due to very very busy school studying (yet looking for a job soon or later).
P#6575 2012-09-15 13:19
That Powder Game is awesome. I tried a much simpler version a long time ago (not sure if it was the same author). I'm a little sad to let proper automata physics go (like the sand voxel type), but it will be replaced in part by more interesting water and lava instead. By modelling these things on a global scale instead of local voxel neighbourhoods, I can give them a more realistic feel -- water levels out and carries objects in the downwards current / lava can slowly creep down slopes like a magma river etc.
P#6577 2012-09-15 18:59
Besides, (just like it happened with the voxel-perfect collision detection) maybe having too realistic physics could end up being difficult to work with or be counter-intuitive. Those voxels may not behave always exactly like we expect them to.
Maybe you can try to add those physics to the LEX500, if you want. Since it's 2D, it may be less resource-intensive. Moreover, it would give a gameplay advantage over Voxatron, so it would not just be it's "younger brother". They would both have the same level of greatness, with just different features :)
P#6581 2012-09-16 08:27
P#6584 2012-09-16 18:17
Will it be possible to add a collision box to them ? Because if I draw a TV with a moving screen, I don't wan't my guy to go through it...
Also and idea if you wanted to make an animation that can be destroyed : the voxels of every frame would be linked with each other (manually or not. It might be tedious...). So if you destroy one in a frame, all its "partners" in the other will be too.
P#6632 2012-09-26 02:39
Exactly -- I'm in now way going for realism as long as it looks and feels good
The LEX500 won't come with any pre-made objects -- it's just for making programs from scratch quickly (with sprite + map drawing tools). But it's so low resolution it would be possible to implement such effects in the scripting language.
I'm glad it's already feeling new. The 0.3 updates will hopefully produce some levels that are not recognizable as voxatron! (e.g. D's 2d cut scenes).
The scheme I'm using hopfully solves both of these problems. For each animation, you can choose one of 3 draw modes:
1. draw each voxel no matter what
2. draw each voxel only if the target voxel is empty
3. draw each voxel only if the target voxel is not empty
So if you use 3, you can make a regular prop the shape of a tv, and then draw a thin 2d-ish animation onto the screen part of it. As the screen gets shot to bits, the 2d animation also starts to disappear where the holes are.
It's not useful for things which are physical and change shape -- that's a more difficult problem I'm still working on. e.g. an animation of an opening door that pushes the player as it opens.
P#6635 2012-09-26 17:33
I would see a solution, if the movement of the animation is only one voxel/frame :
- when the animation is trying to draw a voxel on the player's box, it checks the 26 neighbouring voxel surrounding that one in previous frame, to determine were the mouvement comes from.
- The player, is pushed in opposite direction. If more that one voxel are trying to be drawn in the player's box, the average movement is being used.
- If the player can not move (surrounded by animation / wall), then maybe it should be killed.
Also, have you seen that suggestion about non-viewer point reflexion ? ;-)
P#6640 2012-09-27 17:13
also, when you say barrels do you mean the exploding barrels? a character that moves but doesnt home in on the player? sorry just a little confused. also there are no monsters that stab....yet! But im gonna make some when the monster editor comes!
P#6673 2012-10-04 04:52
And By Stab I Mean Attack Also Yeah The Exploding Barrels Are Not Hostile To The Player They Are Just A Dangerous Obstacle To Me And I'm Making A Level "The Nightmare" Id Like To Make The Zombies Attack A Non Hostile Character And Turn It Into A Zombie Using Special Triggers And Also Id Like To Comment About The Destroyed Rooms That When You Leave And Come Back And It Will Still Be Destroyed Id Like For That To Be An Optional Thing Cause I Made A Level For My Sister And She Likes It When She Destroys Something And When She Leaves And Returns Its All Fixed Up.
P#6675 2012-10-04 19:15
Having different groups of monsters that are harmless to each other only within the same group is interesting. It would also work in with player/monster relationships and player/player in the case of team multiplayer later on. ok, let me think about that!
More complex things like a monster that becomes dangerous for some reason would have to wait for scripting. My general approach, when something looks tricky or not commonly used, is to throw it into the v0.4 scripting bucket (:
@Jauq -- for sure, it will be optional to save each room or reset it. Some styles of levels really require resetting, like puzzles that might become impossible otherwise.
P#6679 2012-10-05 16:45
For the same reason, it might make sense to have a big jump in features at 0.3, but I'll at least quietly post test versions of the monster editor etc. if it's taking too long.
@Jauq the 0.3 monster editor is not flexible enough to do those built-in monsters, but later in 0.4 they'd be possible with scripting.
P#6692 2012-10-09 18:58
P#6711 2012-10-12 17:20
The last thing I needed to finish to support animations was a resource-tree browser and related tools. This allows items to be organised as if they are files on a disk, where special compound objects (such as animations and later monsters) are treated as folders. e.g. a monster folder might contain some animation folders, a folder of sounds and a bullet definition folder.
Here's a test animation of a blade of grass blowing in the wind (a ping-pong frame sequence). You can see the 'file path' at the top: Objects->Plants->Grass. The Grass item is shown in orange because it is an animation rather than a regular folder. You can click on it to edit properties of the animation itself (speed, lifespan etc).
The Object folder looks like this. There are two objects tabs so that you can have two object folders open at once. Each folder has thumbnails of its contents.
There's a special folder called 'Internal' that houses built-in actors and items. Later I'll add standard sounds and music here too. They will become objects that can be placed inside rooms in order to control music using the standard triggers.
I had to rewrite a lot of code to get this working and ended up introducing a lot of new bugs. I'll spend the rest of the week working on stability & backwards compatibility for 0.2.2
The set of properties an animation can have look like this:
lifespan: number of world ticks before halting
frame_duration: how fast to flip through the frames
play_style: loop / ping-pong / play once and hold / play once and disappear
loop_frame: where to loop back to
draw_mode: draw_all / draw_on_solid / draw_on_empty
flags: scramble_start_frame, draw_in_screen_space, loop_in_room, kill_outside_room
P#6719 2012-10-16 18:16
@Jauq I can't change this easily but it's possible in the future. Check the "voxatron limits.." thread for more details.
P#6751 2012-10-23 20:11
After a few good nights sleep and sitting down to re-test each corner of the game and editor, I compiled a list of a more than 120 bugs and editor usability issues. Three weeks later, I'm down to around 25 /:
So, (120-25)/(3*5) = ~6.3 bugs/issues fixed a day, which puts 0.2.2 another week away. Ah, software. You so crazy.
P#6783 2012-11-11 18:33
P#6789 2012-11-13 15:48
P#6800 2012-11-22 00:57
But, all this technical, behind-closed-doors insight as almost as good to me as the game itself. ;) Game design is really interesting, but I'm not quite skilled enough to get into it myself. So, voyeurism like this is perfect.
Point is, though, it looks like you're developing a lot of really cool technology for Voxatron! I know this is getting so far ahead of where we are right now, but I'm also really looking forward to whatever you make next. :D
Do you think you'll ever make an update, or a version, or sequel of Voxatron that doesn't confine your area to a robotron-style square? Don't get me wrong. I don't think you should ditch the square idea. The robotron homage absolutely plays. It was one of my favorite atari games.
However, it doesn't need to ONLY be a robotron homage, as you mentioned while talking about how the game has grown so much. I think if you had a typical, zelda-style view, where the full screen was occupied by the field without black borders, it would drastically change the visual impact/impression people get when they look at the game.
I guess you might have to increase the size of the field a bit so it's not too cramped, and each additional step-up in resolution massively increases the total amount of on-screen voxels, but, hey, computers are powerful! They can handle it! Ah, well! Just consider it!
Know that you have fans and, even if we aren't always watching, we're out there believing in you, supporting you and hoping for your success. :)
P#6808 2012-12-04 12:05
P#6809 2012-12-04 15:06
Log in to post a comment