Main

June 12, 2006

My New Mobile and J2ME

About a month ago I bought myself a Motorola V3i from Exeltek. Nice price, quick delivery. Only issue is that their website seems to have some issues with Safari; I placed the order, (using bank transfer) and transferred the money - but got no verification. I phoned them up the next day to make sure it all worked and I was told that they have my money but not my order. No problems, no problems... they took my order over the phone and the phone was delivered the next day. No worries mate.

I gotta say, it's pretty spiffy. I haven't made much use of the iTunes support however, but I keep planning to. I'm going to encode a 3gp video (an episode of South Park) tonight and see how that plays on the phone.

The most use I'm getting out of the phone (aside from sending and receiving phone calls that is) is the Java capability. Sure, I'm playing a few games, (not the ones that come with the phone; they're stupid) but mostly, I'm making one. A while back, Chris told me about a programming competition, a kind of 'write a game in a month' type thing. I mused with the idea of rushing Fishink out the door but decided against it. I came up with something else though, described it all to Chris, got pretty excited about and proceeded to do nothing about it. Until now, that is!

I have finally brought the idea to life and implemented it on my phone. The whole process is really quite interesting; particularly considering that my phone is really not that speedy (in comparison to, say, the K750) which means that it benefits from optimisation. Carrying out beneficial optimisation, that is, optimisation that results in a higher frame rate is really enjoyable. Keeping the game cross-compatible is harder than you'd think as each phone seems to have its own quirks. At the moment I know that it works on the Sony Ericsson K750, the Nokia 6280 and the Motorola V3i. It's something I intend to market but I still figuring out how to do that.

April 02, 2006

Catastrophic System Meltdown

This afternoon my subversion server underwent what can only be described as a catastrophic system meltdown: 95% of the hard drive simply got wiped. It would seem to have been caused by a virus that triggers on April 1st. Serves me right for keeping something important on a machine running Windows. Quite amusing that it happened to occur on revision 667. That's right, the neighbour of the beast.

I had a go at recovering the repository using FreeUndelete, (pretty awesome tool, being free 'n all) though that seemed to have a little bit of trouble... svnadmin verify would bail out every 20 or so revisions with a unique and fancical error message each of which roughly equated to, "you is screwed." But wait! I had my repository back-up... made in November. Still, no matter, perhaps I can give the recovery a helping hand by plonking down all revisions up to 576. Turns out that was just wishful thinking; revision 647 was total garbage.

*Sigh*

Still, it's not a total loss, I merged the head of the repository into the November 7th version of the repository so now it just has this huge gap... nothing to really complain about there.

Oh and path finding works now. I'll upload some binaries soon.

March 27, 2006

Where It's At

Things are going well in the land of Mage. Absolutely all game logic is now in Lua. That is to say, C++ is Mage, and Lua is Fishink. Quite a nice way to look at it, I'd say. As keen as I am to put up a new version, I'm gonna hold back until I've finished up with pathfinding. I'm commiting to the method described on this site after my A* performance turned out to be quite terrible. This new method uses a collection of convex polygons with shared edges to define the boundary. I avoided this idea for quite a while due to the fact that it's a tad bit trickier for a designer to set up a collection of convex polygons than it is to create a black & white boundary image. But then... the end justifies the means - this is a very fast algorithm that should work very well on, say, a Pocket PC when compared to something heavyweight like A*. It shouldn't take me too much longer, though I'm not going to set a date. Just keep your eyes peeled.

So what's on my TODO list? Well, it gets longer everytime I think about it. This is what it currently looks like (in no particular order):

  • Pathfinding
  • Conversation trees
  • Sound
  • Scrolling scenes
  • Text - Make it coloured and fix that niggly chopped off pixel problem
  • Feedback when the mouse hovers over an Item

My current top priority item is pathfinding, obviously. After that I would have to say it's the Item feedback. It's one of those stupidly trivial problems that keeps getting pushed back because there are so many more trickier things to think about. After pathfinding I'll tackle it... promise.

March 22, 2006

Lua uninitialized variable access and nil

This is something I posted on the Lua mailing list that I felt like reposting here...

Some Lua behaviour that has bothered me since I started using it was:

"It is not an error to access a non-initialized variable; you just get the special value nil as the result"
http://www.lua.org/pil/1.2.html

Sometimes, (in my case, ALL the time) this is not desirable behaviour.

For example, I was trying to figure out a sensible way to expose an enum in C to Lua. For example,

enum Action
{
  Action_Stand
  Action_Walk,
  Action_Run,
};

So, I figured I'd make a table called Action and add a key for each (integer) value in the enum. Problem is, if I do this in my script:

some_action       = Action.Stand
some_other_action = Action.Dance

Then some_action will be set to an integer and some_other_action will be set to a nil... silently. Obviously, I'll notice this error when I attempt to actually use some_other_action, but it would be nice if Lua would bail out with a warning straight away.

Well here's the solution.

Create a seperate table with its __index metamethod set to print a "no such key" error message. I called this table "Object". Now, set this table as the metatable of any enum tables. I found this useful everywhere; "Object" is effectively my top-level base class.

And here it is implemented in C++:

extern "C"
{
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}

#include <string>
#include <iostream>

using namespace std;

//----------------------------------------------------------
void newTable(lua_State* state, const string& table)
{
  lua_newtable(state);
  lua_setglobal(state, table.c_str());
}

//----------------------------------------------------------
void setTableInt(lua_State*    state,
                 const string& table,
                 const string& key,
                 int           integer)
{
  lua_getglobal(state, table.c_str());
  lua_pushstring(state, key.c_str());
  lua_pushnumber(state, integer);
  lua_settable(state, -3);
  lua_pop(state, 1);
}

//----------------------------------------------------------
void setTableCFunction(lua_State*    state,
                       const string& table,
                       const string& key,
                       lua_CFunction function)
{
  lua_getglobal(state, table.c_str());
  lua_pushstring(state, key.c_str());
  lua_pushcfunction(state, function);
  lua_settable(state, -3);
  lua_pop(state, 1);
}

//----------------------------------------------------------
void setMetaTable(lua_State*    state,
                  const string& table,
                  const string& metatable)
{
  lua_getglobal(state, table.c_str());
  lua_getglobal(state, metatable.c_str());
  lua_setmetatable(state, -2);
  lua_pop(state, 1);
}

//----------------------------------------------------------
int index(lua_State* state)
{
  string key(luaL_checkstring(state, 2));

  string error = "No such key \"" + key + "\"";
  luaL_error(state, error.c_str());
}

//----------------------------------------------------------
enum Action
{
  Action_Stand,
  Action_Walk,
  Action_Run
};

//----------------------------------------------------------
int main(int argc, char** argv)
{
  const char* script = argv[1];
  lua_State*  state  = lua_open();

  luaL_openlibs(state);

  newTable(state, "Object");
  setTableCFunction(state, "Object", "__index", index);

  newTable(state, "Action");
  setMetaTable(state, "Action", "Object");
  setTableInt(state, "Action", "Stand", Action_Stand);
  setTableInt(state, "Action", "Walk",  Action_Walk);
  setTableInt(state, "Action", "Run",   Action_Run);

  if (luaL_loadfile(state, script) == 0)
  {
      int errors = lua_pcall(state, 0, LUA_MULTRET, 0);

      if (errors)
      {
          cerr << lua_tostring(state, -1) << endl;
          return -1;
      }
  }

  lua_close(state);

  return 0;
}
When I type to execute the line:
a = Action.JumpAroundLikeACrazyPerson
I get the error:
script.lua:1: No such key "JumpAroundLikeACrazyPerson"

Enjoy. In my opinion, this is a lot more useful than simply failing silently.

March 21, 2006

Progress Report

Last night I managed to transfer all my configuration Lua. This meant I was able to svn rm fishink.config - A particularly joyous moment.

That's not to say that all configuration happens in Lua now, though it's very close. Certain things, like determining which Inventory to display on the screen, and which Actor is controlled with the mouse is still hard-coded in the mainline. If I get a chance, I'll fix this tonight.

More soon...

March 15, 2006

Lua and the Registry

So I've got this class; The ActorModel and this class has an inventoryItem accessor/mutator that takes/returns an InventoryItem& (would you believe). Both of these classes have Lua counterparts, that is, there is a Table that wraps up an ActorModel and another that wraps up an InventoryItem. The trick to these tables is that they contain a "ptr" key that contain a pointer to the relevant C++ object. Functions on these tables operate on the pointer contained there.

It is therefore possible to do things like this:

some_actor_model:setInventoryItem(some_inventory_item);

When setInventoryItem is called, the object on the bottom of the stack is the some_actor_model and the object on top of that is some_inventory_item. It is straightforward then, to derive the C++ object by casting the contents of the "ptr" key to the relevant type. Hence, it is possible to move from the Lua wrapper of an object to the C++ object itself. But how about the other way around?

That is, it's easy to call the mutator, but what about the accessor? The accessor would need to be able to somehow derive the Lua table from the object. My first instinct was simply to let each C++ object hold a pointer to their counterpart Lua table - if only it were possible. The solution: the Lua registry.

The registry is a Table in Lua that is acessible only to C. The thing that makes it really neat is the luaL_ref function. This function "pops a value from the stack, stores it into the registry with a fresh integer key, and returns that key. We call this key a reference." This means, when you create a table in Lua, you can add it to the registry, hold onto the key that LuaL_ref gives you, and use that key later to retrieve the table! I found that the neatest way to implement this was to put a registryKey accessor/mutator on classes that have Lua wrappers.

Have a nice day.

March 10, 2006

WaitUntil/Yielding

Well, I've been racking my brain (as well as the brains of my work colleagues) for a couple of days now in an effort to come up with a solution to my sleep/yield problem. See my previous post for more information. My idea of:

"make the waitFor function register a callback with isIdle, process the main loop continuously itself and unregister with isIdle when it receives the callback..."

Was utter nonsense, here's why: If another callback was triggered while a Lua function was processing the main loop and that function needed to waitFor an event, then we'd have to recurse. If the waitFor in the recursed function took longer than the original function, then the original function would be blocked. Badness ensues. I only gave this option a little more thought before scrapping it entirely.

So I start looking for information in the Lua mailing list archives and soon found all this stuff on co-operative multitasking. As it turns out, Lua nowadays has built-in support for coroutines. This means that I can do something like:

lua_State* new_thread = lua_newthread (main_thread);

Which is, well, fantastic! The thing about cooperative multitasking though is that it isn't preemptive, it is necessary that the threads actually yield at some point. So how does this work in Mage?

Well, first of all, there's a new MessageColleague; the ScriptHandler. This is capable of responding to two Signals; Signal_Run and Signal_Yield. The parameter to Signal_Run is the function name and the parameter to Signal_Yield is the thread ID. Now then, in order to run a function, the ScriptHandler creates a new thread, pushes the function onto that thread's stack, and resumes it, (lua_resume). If that function yields, (by using a YieldUntil function) then the ScriptHandler will stash the thread in a map so that it can be resumed later. So the question is, "how does it get resumed?"

Before lua_yield-ing, each YieldUntil function first of all establishes a message link. That is, it links a Signal to a Slot. The Signal being what we are waiting to happen and the Slot being Signal_Yield on the ScriptHandler. Neat huh?

I might try and clarify this information at a later date, it does require a bit of previous knowledge of the innards of Mage, but hopefully it's enlightening.

I really need to get a new binary up on the net some time soon, though I probably won't do that until I've got all the game logic out into Lua... not long to go.

March 08, 2006

Lua Process and Hurdles

Ok, well things are going very well. I tidied up my sandbox last night and checked everything in. I was able to go around blowing classes away that are now managed by Lua. The coolest little change I made last night was to add this to the script:

function some_callback()
    dennis:queueSpeech("Wow, it works!")
end

Admittedly, the registration of the callback happened in C++, but it would be very easy to make the registration scriptable. Now for the hurdle. I'll try my best to explain this clearly...

The pipeline of operations is this:

  1. Main loop updates all objects
  2. Signals are emitted
  3. Any Slots/Callbacks do their processing

That obviously occurs over and over, until the user exits. An example of a signal might be that the lightswitch was turned on. Assuming that this event was slotted to a script called some_callback, that callback needs to return before we can get back to the main loop. Therefore, it doesn't seem to be easy to implement a waitFor(x) type function. For example, I can't figure out how to do this:

function some_callback()
    dennis:queueSpeech("Looks like a lightswitch")
    waitFor(dennis:isIdle)
    bob:walkTo(dennis:x() - 10, dennis:y())
    waitFor(bob:isIdle)
    bob:queueSpeech("I agree")
end

Problem is, the script isn't running in a seperate thread. I would certainly prefer that it stay that way, but I'm not sure exactly how to achieve this. One idea, is that I make the waitFor function register a callback with isIdle, process the main loop continuously itself and unregister with isIdle when it receives the callback... somehow.

It's all a bit messy and it's certainly something I'm going to need to address.

March 07, 2006

Lua is good

Y'know, I quite like Lua. It's not the same reaction I got when I started to learn/discover Ruby, that was something else. Learning Lua feels more like learning OpenGL or assembly even; the joy is in the low-level API. When I say "learning Lua" I mean learning how to interface it from C. This morning I looked up the reference manual to see how I might call a function defined in Lua from C. My immediate reaction was, "Gee, that's easy."

The integration with Mage is really coming along well; I'm already using Lua to load in my Image and Animations. In fact, it's a heck of a lot quicker than my previous method. Allow me a minute to explain that method:

Previously, I had this sort of recursive typeless-type, similar to Qt's QVariant or Boost's any. I had functions that took in one of these 'Containers', validated that it contained the relevant keys, (e.g. in the case of Image, it would look for filename and transparency key) and produced an object. These objects would then go into a library. The function that created Animations from containers would then need the Image library in order to locate an Image referred to by name. Just as an the function responsible for creating ActorViews needed the Animation library. This process soon became very slow, it was O(n) every time an object needed to be retrieved from the library.

Now, in my Lua script, I can make a call like this:

img  = Image.new("walrus.png")
anim = Animation.new()
anim:insertFrame(img)

Both img and anim are tables containing a "ptr" key. This key contains a pointer to the C++ object on the heap. Meaning that adding an Image to an Animation is a O(1), just dereference the pointer! I know I shouldn't be emphasizing the speed benefit as this is really about up-front configuration, but I must say, this new approach is much quicker. It is also much less error-prone; in the old method, it was possible to mistype the name of an object and end up with not being able to locate something in a library. With this new method, it looks like I might be able to get rid of the library's altogether, but small steps, small steps.

Another thing - the reason I'm looking into call lua functions from C, is for my message-passing mechanism. See here for more information. Real soon now, I'm going to make some modifications to the Messenger so that a signal can be slotted to a Lua function. This really simplifies the underlying engine code, no need to set/unset flags, pass parameters etc. I'm eager to see how it turns out.

I've been very incoherent here, mostly because I don't have a coherent point, suffice to say that Lua has been an interesting learning experience and I'm slowly becoming more confident with its abilities.

March 02, 2006

Lua and C++

Last night I decided to finally try out Lua and it was fun.

Specifically, I wanted to experiment with how I might expose a C++ class to a Lua script - it really wasn't that tricky.

Here are the details...

First, let's start with an academic nothing class that we want to make available to our script:

class Person
{
  public:
    Person()
        :
        m_age(0)
    {
    }

    int getAge() const
    {
        return m_age;
    }

    void setAge(int age)
    {
        m_age = age;
    }

  private:
    int m_age;
};

Next, the mainline:

extern "C"
{
    #include "lua.h"
    #include "lualib.h"
    #include "lauxlib.h"
}

#include <cassert>
#include <iostream>

using namespace std;

// lua callbacks
int newPerson(lua_State* state);
int deletePerson(lua_State* state);
int getAge(lua_State* state);
int setAge(lua_State* state);

int main(int argc, char** argv)
{
    const char* script = argv[1];
    lua_State*  state  = lua_open();

    // load all the standard libraries
    luaL_openlibs(state);

    // register functions
    lua_register(state, "new_person",    newPerson);
    lua_register(state, "delete_person", deletePerson);
    lua_register(state, "get_age",       getAge);
    lua_register(state, "set_age",       setAge);

    if (luaL_loadfile(state, script) == 0) // all is well
    {
        int errors = lua_pcall(state, 0, LUA_MULTRET, 0);

        if (errors)
        {
            cerr << lua_tostring(state, -1) << endl;
        }
    }

    lua_close(state);
    
    return 0;
}

As is fairly obvious, the name of the Lua script is meant to be passed in on the command-line. Notice the stubs? The intention is to provide interface to Lua to allow for the dynamic allocation and deallocation of a Person as well as to get/set the Person's age.

Now to fill out those stubs...

int newPerson(lua_State* state)
{
    assert(lua_gettop(state) == 0);

    lua_pushlightuserdata(state, new Person);
    return 1;
}

int deletePerson(lua_State* state)
{
    assert(lua_gettop(state) == 1);

    Person* person = 
        static_cast<Person*>(lua_touserdata(state, 1));

    delete person;
    
    return 0;
}

int getAge(lua_State* state)
{
    assert(lua_gettop(state) == 1);

    Person* person = 
        static_cast<Person*>(lua_touserdata(state, 1));

    lua_pushnumber(state, person->getAge());
    return 1;
}

int setAge(lua_State* state)
{
    assert(lua_gettop(state) == 2);
    
    Person* person = 
        static_cast<Person*>(lua_touserdata(state, 1));

    int age = lua_tonumber(state, 2);

    person->setAge(age);
    
    return 0;
}

The assertion on the first line of each function is on the number of arguments passed in. Not enormously useful, but I'm guessing it'll end up advantageous in the long-run when I'm tearing out my hair screaming at my computer.

Something a bit unfortunate with these callbacks is that if the parameter passed in (from the script) is not a Person, you're only indication will be a seg-fault. To achieve this in a relatively type-safe way, you would need a base-class common to all user data that is exposed to Lua. It would then be possible to assert lua_isuserdata, static_cast to the base-class and then dynamic_cast to the expected type. I haven't actually tried this, though.

So all that's left at this point is the script!

michael = new_person()
marcus  = new_person()

io.write("michael is ", get_age(michael), " years old\n")
io.write("marcus is ", get_age(marcus), " years old\n")

set_age(michael, 37)
set_age(marcus,  36)

io.write("michael is ", get_age(michael), " years old\n")
io.write("marcus is ", get_age(marcus), " years old\n")

delete_person(michael)
delete_person(marcus)

And there you have it!

I'm confident that some of my visitors are quite Lua-savy and as such would have some much better suggestions on how this can be done. I'm reasonably comfortable with the mechanics of it all, but I haven't a clue as to best-practices or anything like that - particularly when it comes to slotting it in to an existing C++ code base, like say, an adventure game engine :) Any advice would be appreciated.

January 28, 2006

Mage?

Now that I've been back at work for a couple weeks, Mage has been in my thoughts. It won't be long now before I'll be back into it. My first task will be to roll out the path-finding experiment - The A* path finding algorithm really does not appear to be a workable solution. With A*, Dennis walks around the scene as if her were drunk; scaling the walls trying desperately not to fall over.

I'm definately not going to delete any of the work, (I use subversion after all), and the refactoring I did to allow for interchangable path-finding algorithms will certainly come in handy. So yes, Happy Australia again. Good evening.

December 05, 2005

Path finding works!

Sounds exciting huh? Well it's pretty exciting... except that there are still a few issues.

First of all, I ended up integrating the BGL's astar search into MAGE, which was reasonably painless. A couple of things I'm less than ecstatic about, but hey. Suffice to say, when I click somewhere on the screen, Dennis will walk there - unless the place I clicked was outside of the boundary. Which sucks. The reason this happens is because the path finder (BoundaryNavigator) can't solve a path, and so Dennis doesn't move. Compare this to the "just walk until you hit a boundary" technique and you can see how this is hardly intuitive. For example, when the player clicks somewhere on the screen, that location will be compared with all scene objects. If no object is at that location, Dennis will just walk there. Otherwise, he'll walk to the foot of the object. Typically, the foot of each object is not a walkable region. This means, in the current build of Mage, you can't walk to objects by clicking on them - hence why I haven't uploaded it yet.

I think I know how to deal with this problem, and I intend to do some work on it tonight. A new binary is coming very soon.

December 01, 2005

More path finding

Path finding is coming along very nicely. I'm out of the prototyping stage and I've begun integrating the code into the game. I've written a function that takes a Boundary (and range at which to sample) and produces what's best described as an 'edge list'. An edge list is essentially a list of std::pair; it defines which vertices are connected to which other vertices. The 'int' denotes the index of the vertex in the vertex list. Doesn't feel very OO... but I'll withhold my judgement for the moment. This edge list is used to produce what the BGL describes as an adjacency_list.

Something that bothers me is that each vertex must have a 'weight' property in order for the astar algorithm to work. Given that each weight is simply 1, this feels wasteful. I considered writing a function, (ConstantWeight) that, you guessed it, always returned a 1, but Boost started whinging at me, so I'll put that off for now.

So, given that I can now generate an adjacency_list from a Boundary, I can start tested out the algorithm on some Scene boundaries. I first of all tested it on the academic example of the U shaped path - getting the algorithm to path find from the top-left to the top-right. Seeing that work, (by plotting the results in Excel) was very rewarding.

All that's really left is to integrate the path finder into the Director/Actor. Apologies if none of what I just said made sense.

November 28, 2005

A* Search using the Boost Graph Library

Lately, I've been playing with the Boost Graph Library, specifically the A* search algorithm. It didn't require very much effort to get something working, albiet that working meant finding its way from the top-left corner to the bottom-right corner of a square. At first, I was a little put off that it doesn't support implicit graphs, (graph's that expand on demand) but after a bit of thinking, I realised that I didn't really care for this behaviour anyway; if a search is going to happen every time the player clicks the mouse, its best keeping the whole graph in memory anyway.

I'm going to continue hacking prototyping until I become comfortable with the territory, see how difficult (and costly) its going to be to hook into the existing Boundary class I'm using at the moment. Maybe I should take a moment to explain...

Currently, an ActorModel is allocated a Boundary. A Boundary has a public method:

bool isInside(Vector2DF position);
Everytime the ActorModel tries to take a step, it will ask the Boundary if the place that it is about to step 'isInside()' and if it is, it will take that step. If not, it will become idle. The trick, as far as I can tell, is to sample the boundary at given intervals to build a boost::adjacency_list. This will only need to be done once for each scene. When the ActorModel is asked to walk somewhere, a suitable path will be found (if possible), boundary-checking will be disabled, (in case the sampling was too coarse) and the ActorModel will be directed to destination... almost. Just before reaching the final node, boundary-checking will be turned back on, to ensure that the ActorModel doesn't come to rest outside of the boundary.

Sounds good in theory at least :) Can't be too hard.

November 25, 2005

Automated the Pocket PC build

So I've modified the refresh_project_jamfile script I was referring to in my previous post so that it keeps the vcproj up to date. Feels good to have things automated.

I did a little bit of profiling, which was quite interesting. Turns out SDL_FillRect() is quite slow. As seeing as I was clearing canvas's unnecessarily, it was a major cause for slow down. Removing these redundant calls gave me something like a 200% performance improvement - but the Pocket PC build is still dang slow. Chris reminded me that the SDL.dll he gave me was compiled in debug mode, so I'm going to recompile that... I'm excepting great things, but we'll see.

I'm looking for some feedback from the Boost peeps to see if there's a way I can use lexical_cast on an architecture that doesn't (properly) support exceptions so I'll see how that goes. I may just have to duplicate the innards of the function. Bah.

I'm going to start on the text speed dialog box; it'll just be a bar in the top left corner or something like that - haven't thought too much about it yet. It's another one of those, "seems simple at first" type problems, though I'm not excepting it to be too difficult. When this is done, I'll upload a new binary.

November 24, 2005

More news on the Pocket PC front

So I got the latest MAGE working on the Pocket PC last night. What a huge pain. I'm really going to need to start thinking about profiling this thing; moves... so... slowly! Oh well.

My first major problem was the number of exceptions being thrown during initialisation. This process took a long, long time. After actually thinking for a moment, it occured to me that the offending piece of code must have been this:

    try
    {
        return lexical_cast<int>(lhs) < lexical_cast<int>(rhs);
    }
    catch (bad_lexical_cast&)
    {
        return lhs < rhs;
    }

This function will ensure that strings will be sorted numerically first, and alphabetically second. Very handy as a predicate for a std::map. I need this for my key/value config to ensure that an animation with more than 10 frames will be ordered correctly, that is "0,1,2,3" as opposed to "0,1,10,2,3."

Anyhoo, as it turns out, throwing exceptions on the Pocket PC is a Bad Idea. As I currently don't have any animations with more than 10 frames, I just ripped out the lexical_cast bit, and things started working... almost.

My next problem was that my SDL_Image.dll did not have PNG support compiled in! If only I had been using SDL_GetError I would have noticed the very obvious, an "unsupported file type" rather than a missing file. Thankfully, Chris had already compiled the necessary DLL, so I just plonked that onto the Pocket PC and hey-presto.

Glad that's sorted. Now it's just a matter of fine-tuning the vcproj, checking it into my subversion repository and modifying (and renaming) my refresh_project_jamfile script to ensure the vcproj is refreshed as well. No biggy.

In other news, I'm working on my first engine tutorial and the next game scene. Stay tuned.

November 22, 2005

My new toy and Visual Studio 8

Wacom Graphire 4x5As Chris is leaving for the US soon, he's getting rid of some of his stuff. I was lucky enough to score a Wacom Graphire (4x5). First impressions, it's pretty spiffy. It has 512 levels of pressure sensitivity so drawing with the brush (rather than pencil) in Photoshop really resembles painting. I'm still trying to determine how useful its going to be for pixel art, but I'm sure I'll soon figure that out. This would have to be the first product that was quicker to get working on Windows rather than on the Mac. Dang Mac drivers did that hideous thing of popping up a box telling me I have to restart my computer immediately. No opportunity to close things down properly. I've only seen this box once before and I was when I was trying out a crufty PS2 emulator. Never mind.

Some first impressions... the drawable surface of the tablet matches the screen, which is sensible. What is not sensible is that when I connect a second monitor, the horizontal sensitivity of the tablet is effectively doubled. Very annoying. I can't find any obvious option to correct this. I would much prefer to have to pick up the mouse in order to move the cursor to the second monitor.

Now then, onto Visual Studio 8. Why don't things just work the way they're supposed to? Don't get me wrong, so far it seems like a great product, but already I've noticed 2 or 3 things that I would classify as bugs. For example, the linker flags for a Pocket PC 2003 app do not include ccrtrtti.lib. I was getting a bunch of link errors about vftable. This page solved my problem, but you would really expect the IDE to say something to the effect of, "hey, you specified the /GR flag. You're probably gonna need RTTI." Humbug.

Another thing, in keeping withe MSVC way of building projects, all objects get compiled into one directory... not a problem. So why is it that when linking, it is trying to find them elsewhere? It was looking within the objects directory in a structure that matched my source tree. Grr.

To end on a positive note I will point out that I was quite happy to see an assert go off in the standard library when I tried to dereference a std::string::iterator that had progressed to std::end. This sort of thing is not on. On gcc, it just returned a 0, which, given the circumstances, was good enough.

That's enough cruft for now.

November 18, 2005

Integrating PocketPC into the build system

So now that Chris has proven that PocketPC compiling can work, I've started looking at how I can integrate it into the build system. Currently I use Boost Build System V2 and it works very well on the Mac, Windows and Linux, (For anyone who's interested, I put 3rd party libraries into a site-config.jam and have a different version for each platform). So next comes the challenge to include PocketPC...

Unfortunately, the latest milestone release of BB does not support Visual Studio 8 cross-compilation to embedded architectures. I did try following some instructions in the mailing list, but to no avail. So it seems, for the time being, that the best way forward is to write a script to maintain a vcproj file, or simply modify the one that I wrote to maintain my Jamfile. If you haven't used BB before, this probably doesn't make a heck of a lot of sense, suffice to say, It's unforunate that I can't yet simply say, using msvc : 8.0arm ;.

November 17, 2005

Improvements and bug fixes

So here's the round-up of recent work...

Due to popular demand I've made text speed adjustable. Just about everyone who's gotten back to me has complained that Dennis takes too long to blabber on about how useful tissues are and all that. The obvious fix was the make -/+ adjust the text speed. No visual feedback yet, so you don't actually know how slow/fast the text is... won't be long.

I've made some improvements to the Signal/Slot mechanism; it's now possible to say that a slot requires the absense of a flag. This makes things a heck of a lot simpler. For example, when you try to turn on the light once, Dennis says something to the effect of, "I think it's broken." This slot requires the presence of the have_not_used_switch flag. If you do it again, he'll say, "Trust me... it's broken." This second slot requires the presence of the have_used_switch. This felt wrong from day one. This configuration can now be done with one flag; used_switch. If it's not there, he says comment #1, if it is, he says comment #2. Not very interesting, huh? Well trust me, it makes it easier to script.

And... I'm a few steps closer to moving the signal/slot hooks into config, so that'll be a big achievement. I'm quite looking forward to the day that I'll be able to seperate the Mage and Fishink downloads.

What else we got... I've made a slight fix to the Director class. Someone noticed that if you clicked on something while the Actor was talking, he wouldn't walk to it... (which is correct) ...but when he stopped talking, he would try to manipulate the 'something'. Which was wrong. That was an easy fix.

...Anything else? Don't think so. I really gotta make a start on the next scene. I'm getting sick of the bedroom and cave all the time.

November 11, 2005

More on message passing

Anyone who's downloaded the latest Mage/Fishink will see that Dennis is now saying things in response to events. For example: Turn on the light switch and he says, "Light goes on." and likewise, turn it off, and he says, "Light goes off." This is just another example of the Signal/Slot mechanism: When A occurs, B should occur.

It seemed about time that I started working more on the flexibility of Signal/Slot linkages. So first of all, I added two new Messenger methods:

signalSetFlag(Signal, Flag);
signalUnsetFlag(Signal, Flag);

These methods make it possible to link the occurance of a Signal to the setting of a flag. I then modifed Slot to introduce an (optional) required flag. Therefore, it's possible to do this:

Continue reading "More on message passing" »

November 08, 2005

The latest

As you can see from my postings, text has been the magic word lately. I had no idea how hard it would be! Reading in SCUMM character sets, that was the easy part!

Up front, without thinking about it to hard, it seemed easy enough to write a class that would allow me to start rendering text to the screen. For example:

TextWriter writer(font, canvas);
writer.writeText(
    "Hello Bernard, I've been expecting you...",
    actor.x(),
    actor.y() - actor.height());
Would write the text, Hello Bernard- above the actor. So now the issues...
  • What if the text was two or more lines?
  • How do I centre the text above the actors head?
  • What if the actor is at the edge of the screen? How do I stop the text from falling off the edge?
  • How do I adjust the colour of the text?

I've resolved all of the issues bar the one about colour. I'm still racking my brains about that one.

When I get the actor to respond to signals, (and not just have a fixed block of text above his head all the time) I'll post a new binary.

November 05, 2005

Endian-independent SCUMM fonts

Ssssweet. That went well...

windows_scumm.png

Sample text I've also made a start on putting text into the game, as you can see in the screenshot. Something that's beginning to get on my nerves, is the way that certain characters seem to have bites taken out of them! The lowercase L and the exclaimation mark, for example. It would seem that I'm doing a little bit wrong :) I've got a few ideas, but I'm going to have to investigate.

No new binaries yet... I need to put up a Mac package soon. Stay tuned!

November 03, 2005

Pulling in fonts from SCUMM...

Well that was reasonably easy...
scumm_font.png
Just need make sure that the code works on little-endian (I'm willing to bet that it won't) and the other small matter of actually using these letters to write words!

The agenda

So I was racking my brain about which to do next; path-finding or text. And after much deliberation, (with myself) the clear winner was text. By 'text' I mean, the ability for the actors to say things. You know... Monkey Island style. This is probably not going to be easy, fortunately I've already done some work reverse-engineering the Lucasarts character set. That wasn't as difficult as it might sound, thanks to this website can't say I'm too sure about the legality, however...

Going to have to dig out that old long abandoned code and get it working with the latest cut of Mage.

Continue reading "The agenda" »

October 31, 2005

Inventory Selection Feedback

Something I've noticed watching people try to pick up the game for the first time is that they don't know how the heck to interact with the inventory. Essentially, the rule that determines when an Inventory Item is in the Actor's hand, so to speak, and when he puts it back in his, um, pocket, isn't something that be picked up intuitively.

To this end, I've modified the engine so that when the Actor is carrying an Inventory Item, the brightness of that Item will 'pulse'. Seems sensible :)

Basically, what I was going for was some sort of feedback to say, 'hey, you've just selected the torch' as this was clearly getting people stuck. Nice and obvious now.

October 30, 2005

Manipulation Strategies

On my quest to move all game logic into the .config file, (and out of C++) I just migrated the ManipulationStrategy stuff into config.

So, what's a manipulation strategy. Well... the condition that must be satisfied before an Item may be manipulated is defined by a ManipulationStrategy. There are currently two types:

Continue reading "Manipulation Strategies" »

October 29, 2005

Message Passing

I wouldn't get too used to this flurry of activity; I'm making up for the many months of development that went undocumented :)

So message-passing...

Currently, when something interesting happens to an object, it emits a signal. For example, when the lampshade is manipulated it emits the signal, IsManipulated, with the parameter 'true'. Similarly, when the lampshade is manipulated again, it will emit the signal, IsManipulated with the parameter 'false'. Something that may recieve/emit signals is a MessageColleague.

Signals are received by the Messenger who forwards them to whoever has registered an interest. Interest is registered like so:

Continue reading "Message Passing" »

October 28, 2005

Switching Scenes...

cave Just a moment ago, it became possible to switch between scenes. Yes... this is a very good thing. Not only can it switch, but it can also switch back. Wow, how cool is that. Before I get too excited, there are a couple of slight issues that I'll need to address before moving on...

Continue reading "Switching Scenes..." »

What's this about then?

Testing, testing...

banner.png This is my first entry on the new Mage development log. Mage being an acronym for Matts Adventure Game Engine. Matt, would you believe, is me. And Mage, as its name would suggest, is my endevour to put together an adventure game engine.

Continue reading "What's this about then?" »