Saturday 10 July 2010

Strategy pattern applied

  
Yesterday I started thinking about how to improve the behaviour of one of the enemies on our Master's final project game, Once Upon a Night. At some point, I found myself thinking how the enemy might have to choose among a variety of available attacks once the main character enters the attack range for more than one attack types (obviously, if there is only one kind of attack it may launch, there is no problem). The easiest way would be to stick with a common selection policy (for instance "pick the first one", or "pick randomly"), but it wouldn't be very flexible. Then, almost immediately, one of the GoF patterns sprung to my mind. Of course, I mean the Strategy Pattern. According to their book, the pattern's intent is to define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

To make the concept clearer, I'll show you a simple implementation that I sketched last night applied to the attack selection policy for enemies. It should be correct (save for missing includes, which I've omitted) aside from a few typos.

First, some macros and typedefs...

// Attack selection strategies using the same-name design pattern.

// Let's say we have an enemy currently chasing the player.
// At some point,their distance gets close enough for
// the enemy to launch one or several possible attacks.
// If more than one attack is available, which one would it select?

// This code shows how several selection choices may be
// available at once by using the well-known strategy pattern.

#define SAFEDELETE(x) if (x) {delete x; x=NULL;}
#define SAFEDELETEARRAY(x) if (x) {delete[] x; x=NULL;}

// Struct containing a hypothetic attack type data
struct TAttackData
{
std::string name;
int damage;
int attackRange;
int cooldown;
int energy;
};

// A collection of available attacks, indexed by their name
typedef std::map<std::string, TAttackData*> TAttackCollection;

// Functor-like struct used to fetch the vector of values of a map
struct getValue
{
template <typename T>
typename T::second_type operator()(T keyValuePair) const
{
return keyValuePair.second;
}
};

// Return the vector of attacks from an attacks map.
std::vector<TAttackData*> getValues(const TAttackCollection&

 availableAttacks)
{
//BEWARE! This is inefficient, it'll copy the vector to return it.
//Passing the vector as a parameter might be a better option

std::vector<TAttackData*> attacksVector;
std::transform(availableAttacks.begin(),availableAttacks.end(),
std::back_inserter(attacksVector), getValue());
return attacksVector;
}


And now, let's define our base strategy class, and a couple of concrete implementations.

// Base strategy class.
class AttackSelectionStrategy
{
public:
virtual TAttackData* selectAttack(const TAttackCollection&
availableAttacks)=0;
};

// Concrete strategy: an enemy using this strategy will always choose
// the highest-damage
class HighestDamageStrategy: public AttackSelectionStrategy
{
public:
bool compareHighestDamage(TAttackData* one, TAttackData* other)
{
return one->cooldown>other->cooldown;
}
virtual TAttackData* selectAttack(const TAttackCollection&
     availableAttacks)

{
if (!availableAttacks.empty())
{
std::vector<TAttackData*> attacks = getValues(availableAttacks);
std::sort(attacks.begin(),attacks.end(),
  compareHighestDamage);
return attacks[0];
}
return NULL;
}
};


// Another concrete strategy: this time, an enemy using it
// will choose the available attack that has a lowest cooldown,
// so it may attack again as quickly as possible.
class LowestCooldownStrategy: public AttackSelectionStrategy
{
public:
bool compareCooldown(TAttackData* one, TAttackData* other)
{
return one->cooldown<other->cooldown;
}
virtual TAttackData* selectAttack(const TAttackCollection&
    availableAttacks)

{
if (!availableAttacks.empty())
{
std::vector<TAttackData*> attacks = getValues(availableAttacks);
std::sort(attacks.begin(),attacks.end(),compareCooldown);
return attacks[0];
}
return NULL;
}
};




Next is some sample client code using strategies:


void AnEnemy::selectAvailableAttack()
{
AttackSelectionStrategy* myStrategy = new HighestDamageStrategy();
setCurrentAttack(myStrategy->selectAttack(mAvailableAttacks));
SAFEDELETE(myStrategy);
}


However, this is quite rigid, which defeats the purpose of the pattern. I then thought of a way to select specific strategies. Two different alternatives came to my mind, in both cases using an enumerated type as a discriminant.

//Strategy selector enumerated type
enum TStrategyPolicy
{
HIGHEST_DAMAGE,
RANDOM,
FIRST,
LOWEST_COOLDOWN,
LOWEST_ENERGY,
WEIGHTED
//..etc
};



// Now, to implement the strategy selector I have thought of two
// different alternatives:
// I could use a factory function that had a switch statement
// on a TStrategyPolicy value, instancing one
// or the other strategy on demand.
// The second possibility consists on defining a
// map <TStrategyPolicy, AttackSelectionStrategy*>
// and initializing the map at the beginning.
// When the time comes to select a strategy,
// the selector function/class would just access the map.
// While simpler, it has a bit of overhead since an
// instance of all strategies has to be created regardless of if
// it is used or not. However, if
// a getStrategy() method is used frequently, it may actually turn
// out being more efficient, since
// every strategy will only be instanced once.

//OPTION 1: FACTORY FUNCTION
AttackSelectionStrategy* createStrategy(TStrategyPolicy selector)
{
// Ensure that this function's client frees the
// dynamic memory, or memory leaks are bound to appear.
switch(selector)
{
     case HIGHEST_DAMAGE: return new HighestDamageStrategy();
     case LOWEST_COOLDOWN: return new LowestCooldownStrategy();
     //...remaining cases
       default: return NULL;
}
}

//OPTION 2: USE A MAP OF STRATEGIES AND RETRIEVE AN INSTANCE WHENEVER //YOU WANT

typedef std::map<TStrategyPolicy,AttackSelectionStrategy*> TStrategyCollection;

class StrategySelector
{
private:
TStrategyCollection mStrategies;
public:

// The initialization is hardcoded, which would require to
// recompile 
any time a new strategy was added
// (this will also happen using 
a factory function), but without
// any reflection-like device that'd

// allow us to dynamically load on runtime a particular subclass

// (I'll have to research more on RTTI or some libraries)
// there's little else to do.
// If I'm mistaken, which is really likely, I'm open to
// corrections :)
void initStrategies()
{
cleanupStrategies();
mStrategies[HIGHEST_DAMAGE]= new HighestDamageStrategy();
mStrategies[LOWEST_COOLDOWN]= new LowestCooldownStrategy();
//...
}

// Free memory
void cleanupStrategies()
{
if (!mStrategies.empty())
{
for (TStrategyCollection::iterator it=mStrategies.begin();
     it!=mStrategies.end();++it)
{
     SAFEDELETE(it->second);
}
mStrategies.clear();
}
}

// Retrieve a given strategy.
AttackSelectionStrategy* getStrategy(TStrategyPolicy index)
{
if (!mStrategies.empty() &&
mStrategies.find(index)!=mStrategies.end())
{
return mStrategies[index];
}
return NULL;
}
};


Any of these two alternatives would allow for some interesting results. For instance, you might script behaviours for enemies, such as 'Aggressive', 'Defensive', 'Ranged', etc, and the attack selection policy might be a behaviour-dependent parameter.

The client method I presented before would be rewritten to this (of course, myStrategy can be refactored to an AnEnemy class member, which would require at least a setter method allowing changes on the strategy selection algorithm to apply):


//Using option 1

void AnEnemy::selectAvailableAttack(TStrategyPolicy strategyId)
{
AttackSelectionStrategy* myStrategy = createStrategy(strategyId);
if (myStrategy)
{
setCurrentAttack(myStrategy->selectAttack(mAvailableAttacks));
SAFEDELETE(myStrategy);
}
// else throw exception, or do something to notify the strategyId
// wasn't valid
}

// Using option 2: assume StrategySelector is a Singleton
// (http://en.wikipedia.org/wiki/Singleton_pattern).
void AnEnemy::selectAvailableAttack(TStrategyPolicy strategyId)
{
AttackSelectionStrategy* myStrategy =
StrategySelector::getInstance()->getStrategy(strategyId);
if (myStrategy)
{
setCurrentAttack(myStrategy->selectAttack(availableAttacks));
myStrategy=NULL;

// Don't delete the strategy here: that'll be handled by
// the StrategySelector when it invokes its cleanup method
}
// else throw exception, or do something to notify the strategyId
// wasn't valid
}


Now, we can define as many strategies as we want, and the code for the class AnEnemy won't have to be changed to do that. We may provide the strategy selection policy externally through the value of an int that would be cast to a TStrategyPolicy.

In fact, using LUA and luabind, which allows exposing C++ enums to LUA, we wouldn't even need to care about casting between enums and ints.

Unfortunately, due to tight time constraints, we've been trimming the variety of attacks that enemies can launch on our game, so this code will never see the light beyond this modest blog post.


LARGELY UNRELATED RANT: I've been a happy user of the Opera browser for close to 8 years now. However, after the 10.60 release some Google services, such as Google Calendar, Gmail or Google Docs, are screwed up in varying degrees of severity. My biggest annoyance is at the moment Docs. Besides being close to unusable when using their new version, I've been crashing every time it auto-saves, or when I manually save my work. Restarting the browser and logging back in every two minutes is a real pain in the a#se, so I've ended up switching to Firefox so that I could finish this post without fear of having to restart again.

People in Opera Software, PLEASE, can you fix that???

Thursday 8 July 2010

My first game design challenges

A couple of months or so ago I decided to stop lurking, and then I began submitting my own entries for Game Career Guide’s Game Design Challenges. In case you don’t know, Game Career Guide is one of Gamasutra’s sister sites, specifically oriented to students. It features some interesting articles on game development by prominent people in the industry, and it also holds a game design competition every few weeks. For these challenges, that are quite useful as a way to exercise one’s skills at designing and, mainly, communicating your idea as concisely as you can, they suggest a topic from which to devise a game, and then anyone may submit their own design in 500 words or less, including a maximum of three images. The most relevant ones are listed on the site. When I first learned about it, I instantly got interested and thought that I would take part on it as soon as I came up with a half decent idea. Inspiration, though, is a bit reluctant to assist me half of the time, so I have only participated three times so far. I got an honorable mention and a second place (the results for the third one haven’t been posted yet), so I guess I can’t complain. However, I’m still aiming for the first place. From now on, I’ll devote a whole post to future challenges, which I’ll update when the results are out...or maybe I should create a specific page to list the challenges, whatever. For today’s post, however, I was planning to share my first two entries.

My first time: Romance (No pun intended)

On the challenge’s wording they dealt with the romancing genre (for instance, the Tokimeki Memorial series), which is quite popular in Japan. Attempts to carry over those titles to Europe and the United States have kind of failed though. Our ‘mission’ was to design a game with romance as its main theme that could be more appealing to occidental mindsets.

To provide a bit of context, as the game will be heavily story-driven, I had the main idea while recalling 'Eternal Sunshine of the Spotless Mind', one of my favourite films ever.


The goal consists of gathering the pieces of a perplexing puzzle: the memories of your girlfriend/boyfriend and the relationship you had/have, which apparently you have completely forgotten. Solving the riddle doesn't mean you both get to live happily ever after: as you regain new memories and get closer to your goal, your decisions throughout the game and your interactions with other characters may significantly affect the outcome.

You won't be alone in your journey: Together with a partially controllable NPC who's going through the same, you'll have to cooperate to find out why your respective significant others seem to have been erased from your memories...if they ever existed.

At the beginning, you'll get to choose your gender and sexual orientation: they'll determine your partner's identity. Then you can pick a career (such as a scientist, a painter, a PR or a stripper) with benefits and disadvantages to your skills. There will also be some traits to choose which will set some background story-wise and grant you with further bonuses and handicaps. Your character's appearance will be customizable, for the eye candy.

Your companion will start with some skills of her own. As you progress through the game and get to know her better, you'll be able to 'discover' her own traits (not necessarily the same set you were offered in the beginning) and further refine her skills.

The plot will advance by completing certain sub-goals: - Get some reaction from an NPC, through conversational trees or performing in-game actions. - Reach some particular location. - Cooperative missions. Say, your partner uses her persuasion skill to distract some guy while you sneak past and then use your amazing ability to find information to...find some information. - Mini-game solving, related to whatever you're doing. Oblivion is useful as a bad and a good example: While I found the persuasion wheel totally unimmersive, the lock picking mini-game was, in contrast, reasonably well done.

Solving a sub-goal will trigger some hint about your relationship (which will contribute to get you attached to him/her, lest you might end up always romancing a secondary or even more unimportant character) and may give some clues for the next mission.

If you end up romancing other people (you cheater!), you'll have to talk to them, give them gifts or help them out. Your choices during the game may also modify the approval of one potential lover (where that option makes sense: no clairvoyance!). I'm afraid I won't be spoiling much if I say beforehand your companion will be a love interest, but there'll be more, some of which you might not get to meet on a single playthrough.

Last, there will be a variety of optional areas where you can get some benefits: insight about missions or the game world, shops, secondary quests, workplaces, motels, etcetera.

I enjoyed a lot imagining how the story would unfold. My weak point was, however, that I lacked a bit of focus on the gameplay. As a result, it isn’t totally clear if the game will be more of an RPG, vastly focused on conversations and character development, than a sandbox.
This is something that I have tried to solve for the subsequent entries. I still like the idea very much, and I intend to further develop it as soon as I can think of a set of suitable mechanics.

The results of the challenge, as well as the entries on the following pages, are listed right below, so you can read what other people did. My entry, that you’ve already read, is on page 8. http://www.gamecareerguide.com/features/835/results_from_game_design_.php

Second entry, second place :D: Inappropriate title

The second challenge I participated in asked contestants to take the title of a game that has nothing to do with the game itself and make another one that is better suited to that title. Examples included were Vagrant Story or Guilty Gear.

This time I opted for a more casual approach. I was playing Braid at that time (amazing game, by the way), and I couldn’t see how braids had anything to do with a time-controlling platformer (aside from a really brief mention on the plot introductory texts for one level). I then remembered Ratatouille and suddenly everything made sense: what about a hairdresser louse?

Don’t tell me it isn’t cute

As Louse Sassoon, a hairdresser-wannabe louse (Ratatouille anyone?), your dream is to make your human host wear the best-looking braids in the neighbourhood. To do so, you'll get to tame a set of rebel hair locks, forming the links that will shape the braid(s). However, humans and even your fellow lice will be around, decided to crush your dreams.

At the beginning of the level you'll get explained the type of braid you must do, as well as the possible new features you may encounter in it.

Then the game will star with Louse swinging from one of the locks (There will be some wind, blowing with varying strengths depending on the level). From there, it can jump to another lock either on its own, or carrying around the lock Louse was previously hanging from. If the jump is done while carrying around a lock of hair, one of the "links" of the braid will be made. After that, Louse will keep making links by repeating this process until time runs out. You must decide carefully when to jump so Louse can reach the desired lock avoiding to fall down. In addition to jumping and swinging, Louse can also use some items that may help it defeat its enemies, get some power-ups or score additional points. All the levels have a set duration. The area of interest where Louse will be able to put its skills to use will remain fixed for some seconds, and then the braid will go up (think of Puzzle Bobble, but in reverse order). If no links were done, the braid's appearance will look messy and you'll get less points.

Once the time has run out, Louse will move on to the next level if it managed to achieve a minimum score. There will be more than one scoring levels to provide an additional challenge and reward your skill with some bonuses.

Obstacles/Enemies:
  • Lice shampoo cloud. Be careful and avoid them at all costs, as these clouds may kill you.
  • Enemy lice. They despise Louse because they think it brings shame to the family. To defeat them, throw them some nits and make them fall.
  • Hairspray cloud. This ozone-layer-destroying cloud will also paralyse Louse for a few seconds, leaving it vulnerable against enemies, and making it lose some precious time.
  • Hair drier. Strong wind gusts will blow for a while, making swinging and jumping from lock to lock more complicated.
  • Others.
Items:
  • Hair gel: It stops a lock from swinging around due to the wind.
  • Nits: Keep them to fight the enemy lice.
  • Beads and ribbons: Use them to increase your score, as the braids Louse will make will look prettier <3
  • Blood bubble: It'll cover Louse, making it invulnerable for a few seconds.
  • Extra lives: Well, I bet all of us know these ones already, don't we?
  • End-of-level bonus: After finishing certain levels Louse will have a chance to make some cool hairstyle by combining the braids it has been making during the level. If successful, it'll earn a huge score bonus
A fellow programmer colleague from my Master’s final project, Aniol Alcaraz, ranked in third place. UPC seems to be hitting hard design-wise, doesn’t it? :)

Check the full list of winning entries here: http://www.gamecareerguide.com/features/855/results_from_game_design_.php

Third design: Michael Jackson

For the latest design challenge, our objective was to imagine a game centered about the late singer.

I’ve always thought that his videoclips were really original and elaborated -starting, of course, with Thriller, responsible for my irrational fear of zombies, so when I read about the challenge I thought that I could use that as an obvious theme. I was at a risk of ending up like on my first challenge, where I kind of left the essential gameplay aside, so I began plotting possible interesting mechanics.

Since leaving music and dance out of the picture is a no-no, I came up with a not-too-original rhythm game, borrowing lots from the Osu! Tatakae! Ouendan! and Elite Beat Agents games. To prevent my idea from being a total rip-off, I thought of an issue concerning these two games: The player can forget about the DS’s upper screen when playing. In fact, if she wants to achieve a nice score, she should forget about it, as it may be distracting. Storywise isn’t particularly meaningful either (except for the comic-book-like cutscenes that are played on the level’s play pauses), so iNiS might have done without the upper screen and nobody would have noticed the difference. I decided to solve that by adding an enemy to fight on the upper screen. Square’s The World Ends With You manages to do a two-screen combat system using both the stylus and the buttons that works reasonably well, and I thought it could be applied to my game, hence the 9 Michael Jackson’s evil impersonators he must defeat. (Oh, the number isn’t final...it could be 9, it could be 13,...)

Adding this ‘pay attention to both screens’ feature involves an additional complexity layer, which means the difficulty of the classic rhythm game on the lower screen must be decreased a bit so that the combined challenge is not unbearably difficult.

This is my original entry:
Michael Jackson vs the nine.
Nine die-hard fans who've taken their obsession way too far and now believe to have become him, have got rid of Michael's most famous video clips and replaced the originals with their own, utterly crappy versions. Michael will have to redo the videos performing the same moves that made him famous again while at the same time he defeats his evil impersonators to prevent his legend from being stained with shame.


Mechanics:
This is a rhythm game intended for the Nintendo DS. The main source of inspiration is Elite Beat Agents, but I’ve added a twist inspired on the battle system used in The World Ends with You to make the upper screen a bit more meaningful gameplay-wise than it was on EBA.



During a stage you’ll have to take care of two things:
Performing the dance moves as accurately as possible on the lower screen using the stylus. You’ll have to click and/or follow certain symbols at the right time to make Michael dance, and also increase the power meter (the better he performs, the more energy he’ll gain).
At the same time Michael dances, he’ll have to dodge, counter and attack the evil impersonator for the current stage (remember those fans have lost touch with reality and think the authentic Michael is actually an imitator himself). Michael’s fan will be displayed on the upper screen, and every now and then he’ll throw some spotlights, rocks, etc (dependant on the setting of the stage). The directional pad+L trigger (or ABXY buttons+ R trigger for left-handed people) will allow you to avoid the items, deflect them or attack your foe, pressing the buttons when appropriate. The damage you cause to him will be proportional to the “style meter”.

As the focus is on rhythm, the attack and dance sequences will have to be balanced so that Michael’s attacks blend in nicely with the music. In addition, the dance moves part should be a bit easier than it is on EBA so that when incorporating the upper-screen-focused gameplay the combined challenge level does not get impossibly difficult.

The stage ends either when the whole video has finished, or when the player loses, which will happen when the style level goes below a minimum (either by repeatedly failing at dancing, or by getting hit by the crazy fan). There is a middle-ground situation: if by the end of the stage the style level is above the minimum threshold but the player hasn’t beaten the enemy, the score will be computed and the experience will accumulate to the total experience counter, but the stage will not be considered as cleared till the enemy has been defeated..

Last, the game is structured on several tiers of two or three stages of increasing difficulty. The player may choose between the available stages freely, but all of them will have to be cleared before advancing to the next tier.

The time limit to submit entries ended yesterday, and they’ll be posting the results next week.

If I happen to have a good idea from which to code a simple game on XNA, C++ plus [OpenGL|DirectX] or Pygame for learning purposes (What should I do? A scrolling shooter? A platformer? A tower defense? I’m open to any suggestions), my next post might deal with it; otherwise, I may have to recycle a couple of incomplete designs that I have in mind. For now, I’ll just spoil the titles: Psyche, and The Path is The Goal (this one is probably temporary, though).

Tuesday 6 July 2010

Wall Chaos (II) - Technical stuff (Run for your lives!!)

After the first post, focused on design issues, this second one will show the dirty implementation details behind the 2D version of Wall Chaos.

The language of choice was C++. Firstly, because that way I had the chance to reuse some code from the theory classes, and also because it's the language I feel most comfortable programming in excluding Python. 

If you remember, the assignment included a constraint that restricted the game to be isometric. Getting this done was probably the most challenging part, and I ended up mixing theory concepts learned in class with some ideas I got from Ernest Pazera's Isometric Game Programming with DirectX 7.0.

As you probably know, there are several subtypes of isometric maps. The most widely used ones are probably the staggered map(for example, the one used throughout the Civilization series) or the diamond map (The Age of Empires maps have this kind of layout). I was pretty sure from the beginning that I'd go with the second approach, as it seemed to fit better with the shape of the rooms.  Both types are pretty similar, but they differ in the way the map is traversed. 

This is how the x and y coordinates range in a diamond map:
This setup makes it a bit more difficult to blit a tile, since two consecutive cells aren't blitted in rows as in a typical rectangular 2d map. Besides, the cell sprites (which are rectangular) will overlap, so the traverse order matters.

This is the blitting loop (there is an outer loop for further layers, as the tiles are stackable, but for brevity's sake I will omit it)

for (int y=0;y<SCENE_HEIGHT;y++)
{
for (int x=0;x<SCENE_WIDTH;x++)
{
TTile* tile = &(gameData.scene->map[y][x][z]);
//Read the tiles' sprite sheet to get the clip rectangle
tileRect=gameData.scene->getTileRect(tile);
int tileIndex=tile->index;
if (tileIndex!=NOTILE)
g_pSprite->Draw(textures[TILESET_INDEX],&tileRect,NULL,
&D3DXVECTOR3( float((x-y-1)*(TILE_WIDTH>>1)-baseX), float((x+y)*(TILE_HEIGHT>>1)-baseY-z*TILE_HEIGHT), 0.0f),
 inkColor); 
}
}

The x,y screen coordinates are computed as follows;
x_screen = ((x_map-y_map-1)*TILE_WIDTH/2)-baseX;
y_screen = ((x_map+y_map)*TILE_HEIGHT/2 - baseY-(z_map*TILE_HEIGHT);

baseX, baseY define the offset from the screen position (0,0). This ensures that the map is rendered at the right location (at the beginning of the game, it will typically start next to the top edge and horizontally centered).

Another issue was to retrieve the cell in the map from a set of screen coordinates. One of the main uses for this is to find out which cell the player has clicked on with the mouse. As Wall Chaos was basically controlled through the keyboard -save for the GUI menus-, I used this method to quickly convert between screen and cell coordinates instead.

The algorithm consists of two parts. This time I'll just describe it:

First, get the cell's rectangle (The diamond cell and its surroundings).
To do this, from the screen coordinates we'll first get the world coordinates, taking into account the scene's offset. This means that if the mouse click resolved to position (100,200), and there is a (400,64) scene offset, the world coordinates would be, respectively, (500,264).

Then, the tentative coarse (per-cell) and fine (per-pixel) coordinates are to be retrieved. This is done in the same way as with common 2D tiled maps:

coarse = (worldX/TILE_WIDTH, worldY/TILE_HEIGHT)
fine = (worldX%TILE_WIDTH, worldY%TILE_HEIGHT)

On those maps we'd probably end the whole process here. However, there are still some more steps involved in this case. Due to the scene's offset position, there is a chance than the fine coordinates are negative and we need to adjust them, adding the tile width or height to the modulo operation result.

Then, depending on the value of the coarse coordinates, we need to adjust the pre-final map coordinates. That's achieved like this:

int mapX=0,mapY=0; //Candidate map coordinates
while(coarseY<0)//Move north
{
mapX--;
mapY--;
coarseY++;
}
while(coarseY>0)//Move south
{
mapX++;
mapY++;
coarseY--;
}
while(coarseX<0)//Move west
{
mapX--;
mapY++;
coarseX++;
}
while(coarseX>0)//...and finally, east
{
mapX++;
mapY--;
coarseX--;
}


After iterating through these loops, the first part of the procedure ends. We have a pair of coordinates corresponding to a rectangular cell (x,y). However, depending on the fine coordinates, the actual diamond cell might be one of the 4 depicted adjacent cells.



The second part's objective is, therefore, to retrieve the actual cell. Taking advantage of the fact that  the ratio width:height of the tiles was 2:1 we can use the following property:

if(fineX<(TILE_WIDTH>>1))//32
{
//Left
if(fineY<(TILE_HEIGHT>>1))//16
{
//Up
if( (TILE_HEIGHT-fineX)>>1 > fineY ) { mapX-=1;}
}
else
{
//Down
if( (TILE_HEIGHT+fineX)>>1 < fineY ) {mapY+=1; }
}
}
else
{
fineX-=(TILE_WIDTH>>1);

//Right
if(fineY<(TILE_HEIGHT>>1))
{
//Up
if( (fineX>>1) > fineY ) mapY-=1;
}
else
{
//Down
if( (TILE_WIDTH-fineX)>>1 < fineY ) mapX+=1;
}
}

After this, mapX and mapY will hold the final map coordinates.

Last, this game featured music and sound. One of the assignment requirements asked us to implement an interface to abstract and encapsulate the concrete sound library used. This was relatively simple to do. I used the old API of FMOD, which seemed good enough for my purposes, and abstracted the three kinds of supported sounds (Streams, Sounds and Samples -midis, basically) into three subclasses of a base class CSoundItem. At the resource loading time, the layer parsed the filename and, depending on the extension (*.wav, *.mid, *.mp3,...), it instanced a particular subclass.
The sound layer had an STL map indexed by an ID string containing all the loaded sounds (the load was done on a per-game-state basis), and then the application just had to keep track of the IDs to play any sound of music track. 

I could dwelve a bit more on the game's architecture (For instance, for managing the game states I defined a couple of variables to keep the current and next state IDs and then a factory to resolve and instance the particular GameState subclass to switch to next. For Once Upon a Night, the Master's final project, I opted for using a stack-based game state machine instead, which turned out to be much more flexible), but I guess I've bored you enough already. If you feel like diving a bit more into the code, you may download the sources from here.