VAGUE: Verily Another Game-engine by an Ultima Enthusiast

I am a terrible person, you know.

Some months ago, Darren “Time Machine Dragon” Janeczek — whom most of you will probably know from the xu4 project — alerted me to another little pet project of his, which he had tentatively named VAGUE. You can see the (somewhat arbitrary) expansion of that acronym in the title of this post. Here’s how Darren described it:

I decided to start working on a multi-platform (desktop and mobile) game engine with sufficient capabilities to recreate Ultimas 1 thru to at least 6. And of course do a few of its own unique things that I want to see in my original games.

I decided that I would start by implementing Ultima 1.

Ultima 1 is very much an action RPG that can be picked up and played casually. Go into dungeons, slay monsters, collect gold and hit points, rescue the princess, launch a space shuttle, rent a starfighter, shoot down alien craft, crash and burn upon re-entry because you can’t afford the space station docking fee, enjoy free resurrection, then rob the weapon and food store so you can buy hitpoints from the king and hop aboard a time machine to prevent the evil wizard from crafting the evil gem that has motivated you to quest back through time after him. All good wholesome stuff. I played through the classic recently on DOSBOX. It was pretty fun!

Naturally, he posted a video of VAGUE running Ultima 1:

[youtube http://www.youtube.com/watch?v=VXUqh4WOwSs&w=480&h=360]

Music by Noppz.

Darren continued his analysis of Ultima 1 and VAGUE thusly:

  • Lots of random U1 monsters moving around, at various speeds per tile.
  • No ‘pause’ for turn-based action (ie: instant pass)
  • Cheesy 3D billboard effect for solid landmarks and creatures.

When I’m at a satisfactory point in development, I’ll have something that I can use to make all sorts of interesting games that fall in line with what makes an Ultima. Until then however, this is just a dinky little map wanderer program implemented with OpenGL designed to be completely portable between iOS, Android, PC, Mac, etc.

Even so, Dragons and Dragonettes, there’s a measure of promise there. Not a month goes by in which I don’t see someone on Twitter pleading for EA to release this or that Ultima game for one mobile OS or another. The possibility of creating a dedicated engine which could run many of the Ultima games and easily publish to a variety of desktop and mobile platforms is a tantalizing thought indeed.

I spoke with Time Machine Dragon briefly by email today, and he reported that he hasn’t actually had much time to work on VAGUE since he first told me about it. Switching jobs and buying a house do, admittedly, exert such pressures on a person. Hopefully he will find time in the near future to pick up where he left off!

I’ll put up a project entry for it in the next day or so, but for now I wanted to actually get the news out about it…because it’s been too damn long already.

15 Responses

  1. Geoff says:

    This is exciting. Playing Ultima3 on the bus? Sweet!

  2. Dungy says:

    But if I play at home, I can play in my underwear. It seems like I can’t do that on the bus.

    • WtF Dragon says:

      Yes you can, on those pantsless riding days that sometimes happen in big cities.

      Just Google it. It’s odd, and oddly hilarious. You’d fit right in!

  3. Sanctimonia says:

    Get with FEARYOURSELF as he’s doing the same thing and already has much done. Could collaborate on parsing and interpretation of datasets, compromise on rendering engine, and work together on future feature implementations. Or work together but with two separate projects.

  4. Sanctimonia says:

    Shit, forgot this:

    http://eightvirtues.com/music/Chrono%20Trigger,%20SNES.spc

    The original background song for this clip.

  5. Time Machine Dragon says:

    Sanct: I agree. The focus of the code now is just rendering a game state. There are no significant rules or game objects — it’s all abstract.

  6. fearyourself says:

    Sanctimonia: I also agree, I think it’s very interesting to start with Ultima I instead of Ultima V as I did (the reason I did this is because to disable features already implemented is easier than adding concepts that didn’t exist first).

    However, I saw some rendering elements and things that shouldn’t be difficult to integrate into Backtoroots. Others such as real-time movement might be more tricky but not impossible.

    If you’re interested Time Machine Dragon, we could see how to share code, decoding data files, or even just merge the projects into a single bigger project system.

    Tell me what you think since our goals are relatively the same,
    Jc

  7. Mike O. says:

    Looks somewhat like the 3D implementation of EUO. Video link attached.
    http://www.youtube.com/watch?v=KDUvufZui9I

  8. Sanctimonia says:

    The 3D EUO engine looks great, but why did they not make a smoothly moving camera to show the graphics off? Everything accomplished by the 3D rendering is lost for the lack of attention to this.

    Here’s an abbreviated code snipped that might help:

    ‘ Move the camera position closer to the current (player) position.

    ‘ General declarations.
    Dim Distance As Single ‘ Distance of camera from player in tiles (used for zoom calculation).

    ‘ Calculate camera distance.
    Camera.DistanceX = Abs(Camera.WorldX – Client.Player[Client.Number].WorldX_Current)
    Camera.DistanceY = Abs(Camera.WorldY – Client.Player[Client.Number].WorldY_Current)

    ‘ Calculate camera velocity.
    If Camera.WorldX > Client.Player[Client.Number].WorldX_Current Then Camera.VelocityX = (Camera.VelocityX – Camera.Acceleration) * Camera.DistanceX / 4
    If Camera.WorldX Client.Player[Client.Number].WorldY_Current Then Camera.VelocityY = (Camera.VelocityY – Camera.Acceleration) * Camera.DistanceY / 4
    If Camera.WorldY Camera.VelocityMax Then Camera.VelocityX = Camera.VelocityMax
    If Camera.VelocityX Camera.VelocityMax Then Camera.VelocityY = Camera.VelocityMax
    If Camera.VelocityY Zoom.Target Then Zoom.Velocity = (Zoom.Velocity – Zoom.Acceleration) * Zoom.Distance
    If Zoom.Current Zoom.TerminalVelocity Then Zoom.Velocity = Zoom.TerminalVelocity
    If Zoom.Velocity Zoom.Minimum Then Zoom.Current = Zoom.Minimum
    If Zoom.Current < Zoom.Maximum Then Zoom.Current = Zoom.Maximum

    ' Update camera world position.
    Camera.WorldX = Camera.WorldX + Camera.VelocityX
    Camera.WorldY = Camera.WorldY + Camera.VelocityY

    I know it's really bad the way it calculates the camera's distance from the player (moves faster diagonally, for example), but it works pretty well and is visually impressive. The variables in this example are singles, and the underscores aren't events but just bad naming convention. I also set VelocityMax to less than one (like 0.9) so more than one row of tiles wouldn't be drawn per frame if the camera moved too fast chasing the target/player.

  9. Sanctimonia says:

    This line isn’t used by the code, I just noticed:

    Dim Distance As Single

    But it could be assigned a proper distance calculation like Sqr((x2 – x1) ^ 2 + (y2 – y1) ^ 2) and become useful.

  10. fearyourself says:

    I think it’s because they simply center the view with the main character and it isn’t a constant movement system such as the one we see from VAGUE. Being such a tile based system, they maybe wanted to keep that kind of view.

    In the end, they could add it but perhaps it isn’t what they are looking for.

    Jc

  11. Time Machine Dragon says:

    I think EUO were going for the more ‘purist’ approach.
    Looks cool nonetheless. I love how that u4 VGA ends up being used for so many new Ultima-related projects. (Even the ultra top secret ones 😉 )
    Props to Joshua Steele.

    As for integration, it all comes down to how you represent your world and the entity actions on that word.

    In VAGUE:
    The camera is fixated on the ‘avatar’, though it can be fixated on any tile.

    Pardon my inconsistent API-filled grammar, but here’s how it all fits together:
    Things exist on Tiles.
    Tiles are collected together on Facets (think of Facets of classic Ultima “chunks”).
    Facets may be linked to other Facets in potentially interesting ways (not implemented yet since Ultima doesn’t require this).
    Things may have an offset from the center of that tile, which at the very least can be visualized.
    Things can have Actions committed to them.
    Actions have durations.
    Actions may affect the state of the associated Thing atStart of the Action and/or atEnd of the action.
    Throughout the duration an Action, properties of the Thing may be affected by a FunctionOfTime where the time(0) is “start” and time(duration) is “end”.
    The various FunctionOfTime effects will be mostly for animation of effects, and are currently responsible for displaying the Things between the “start” and “end” of their movement Actions.
    So if I remember correctly, a typical MovementAction consists of a startCell (tile), endCell, duration/speed, and a FunctionOfTime that sets that Thing’s x/y offsets appropriately based on the gameclock time.
    Gameclock time moves forward with rendertime, except when there is a pause due to ‘wait for action’ lockups on UserControllable Things. In the demo there are no ‘wait for action’ lockups because I’ve hard-coded the avatar to automatically invokes a ‘pass’ action of 1 duration if his BehaviorController has no movement actions enabled.

    So in short, implementing a turned-based tile game is possible with this engine. More dynamic approaches to turn-taking are also possible. It is very tile-based however, and will probably remain that way. I’m hoping to implement hex cells for fun strategic battle stuffs.

    Since you have a lot of your engine implemented, you’d probably only potentially want to use this for an alternate world, object, and effects renderer.

    In that case, VAGUE would only care about the following interactions:

    How can I display your terrain tiles?
    How can I display your objects?
    Here’s an interface you can implement to help me represent the tiles in your world — and here’s a simple tile viewer that accepts texture definitions in PNG format.
    I’m going to request Actions from your registered Things at regular intervals based on when the duration has run out on your previously given action, and I will be rendering these actions in between and I’ll give you a hook-in function so you can change properties on your Thing as game time flows through the Action.
    If one of your objects is waiting user control, I can put all actions on pause until a decision is made. Same goes for if you have a complex AI.

    So I’ve tried to make things as abstract as possible. My measure of success will be the amount of joy you can derive in wrapping the VAGUE engine around parts of your engine. I still need to iron out a lot of details, and open stuff up. A lot of it takes advantage of the simplicity of the U1 world with a few lazy assumptions. This project would benefit from this sort of collaboration.

    Anyway, I gotta run. I’m open to further discussion, and eventually collaboration once I’ve blown enough dust off of the old code.

    D.

  12. fearyourself says:

    I’ll inline my comments:

    >> The camera is fixated on the ‘avatar’, though it can be fixated on any tile.

    Yes it is the same. I call it the “Group” but the idea is the same. Basically, depending on the borders of the map and the size of it, the start tile to draw is decided. The camera doesn’t really move it’s what you draw that changes.

    >> Pardon my inconsistent API-filled grammar, but here’s how it all fits together:

    No worries.

    >> Things exist on Tiles.

    Tiles are called Cell in my engine and they contain basically three level of “things”:

    – AnimatedObjects which are on top
    – Corpses which are dead AnimatedObjects
    – Objects

    >> Tiles are collected together on Facets (think of Facets of classic Ultima “chunks”).

    The tiles for me are simply collected in a 2D matrix which is a Map. However, since you can have multiple levels in towns or dungeons, a MapHandler contains multiple Maps.

    >> Things may have an offset from the center of that tile, which at the very least can be visualized.

    Each Object gets a call to render. If it did contain an offset, it will change the position it gets with its inner offset. For the moment, I don’t have offsets since I haven’t seen the use of it.

    >> Things can have Actions committed to them.
    >> Actions have durations.
    >> Actions may affect the state of the associated Thing atStart of the Action and/or atEnd of the action.
    >> Throughout the duration an Action, properties of the Thing may be affected by a FunctionOfTime where the time(0) is “start” and time(duration) is “end”.

    I don’t have any implementation of handling actions to objects for the moment.

    >> The various FunctionOfTime effects will be mostly for animation of effects, and are currently responsible for displaying the Things between the “start” and “end” of their movement Actions.

    Objects have their inner properties and a Sprite which handles the rendering. Therefore, an object basically just passes the rendering call to its sprite. The Sprite contains the information related to animation between frames. It handles it internally and the Object is not concerned with this except with passing the update information to give the sprite the information of time passing.

    >> So if I remember correctly, a typical MovementAction consists of a startCell (tile), endCell, duration/speed, and a FunctionOfTime that sets that Thing’s x/y offsets appropriately based on the gameclock time.

    Since I’m turn based and didn’t try anything else, you have a time clock that resets at each user input. If there is no user input, you pass that turn.

    At each end of the user’s turn, the rest of the world gets a turn and the system updates the movement for the different animated objects (NPCs and monsters) of the current maps being considered.

    # Gameclock time moves forward with rendertime, except when there is a pause due to ‘wait for action’ lockups on UserControllable Things. In the demo there are no ‘wait for action’ lockups because I’ve hard-coded the avatar to automatically invokes a ‘pass’ action of 1 duration if his BehaviorController has no movement actions enabled.

    Yes, I do the same kind of thing.

    >> So in short, implementing a turned-based tile game is possible with this engine. More dynamic approaches to turn-taking are also possible. It is very tile-based however, and will probably remain that way. I’m hoping to implement hex cells for fun strategic battle stuffs.

    Yes, I can see how that makes sense too.

    >> Since you have a lot of your engine implemented, you’d probably only potentially want to use this for an alternate world, object, and effects renderer.

    Most likely. Were we to integrate both systems, probably the rendering would be integrated and then see if we want to make it less tile based.

    >> In that case, VAGUE would only care about the following interactions:
    >> How can I display your terrain tiles?

    At each frame of the engine, each cell/tile says: “draw me at this screen position”. We could change this into: “draw me at this world position” and VAGUE decides where that is.

    >> How can I display your objects?

    When a cell is rendered, it requests its objects to be rendered and provides the same position information.

    >> So I’ve tried to make things as abstract as possible. My measure of success will be the amount of joy you can derive in wrapping the VAGUE engine around parts of your engine. I still need to iron out a lot of details, and open stuff up. A lot of it takes advantage of the simplicity of the U1 world with a few lazy assumptions. This project would benefit from this sort of collaboration.

    That is why I’ve integrated both U4 AND U5 at the same time. It keeps the engine generic to not over specialize.

    >> Anyway, I gotta run. I’m open to further discussion, and eventually collaboration once I’ve blown enough dust off of the old code.

    Most likely we should see how we could work together. Either by merging the two projects or creating hooks that make both work together as an option, etc.

    Jc

  13. Time Machine Dragon says:

    Hello.
    I’ve blown some dust off the code, and plan to work on it a bit further. It appears it wasn’t as developed as my description suggested, so I’ve been working on that.
    Anyway, I’ll try to send you a pm.