map.cpp

Go to the documentation of this file.
00001 
00002 //            Copyright (C) 2004-2007 by The Allacrost Project
00003 //                         All Rights Reserved
00004 //
00005 // This code is licensed under the GNU GPL version 2. It is free software
00006 // and you may modify it and/or redistribute it under the terms of this license.
00007 // See http://www.gnu.org/copyleft/gpl.html for details.
00009 
00016 #include "utils.h"
00017 #include "map.h"
00018 #include "map_objects.h"
00019 #include "map_sprites.h"
00020 #include "map_dialogue.h"
00021 #include "map_zones.h"
00022 #include "audio.h"
00023 #include "video.h"
00024 #include "global.h"
00025 #include "script.h"
00026 #include "input.h"
00027 #include "system.h"
00028 #include "battle.h"
00029 #include "menu.h"
00030 
00031 using namespace std;
00032 using namespace hoa_map::private_map;
00033 using namespace hoa_utils;
00034 using namespace hoa_audio;
00035 using namespace hoa_video;
00036 using namespace hoa_mode_manager;
00037 using namespace hoa_input;
00038 using namespace hoa_system;
00039 using namespace hoa_input;
00040 using namespace hoa_global;
00041 using namespace hoa_script;
00042 using namespace hoa_battle;
00043 using namespace hoa_menu;
00044 
00045 namespace hoa_map {
00046 
00047 bool MAP_DEBUG = false;
00048 // Initialize static class variables
00049 MapMode *MapMode::_current_map = NULL;
00050 MapMode *MapMode::_loading_map = NULL;
00051 bool MapMode::_show_dialogue_icons = true;
00052 
00053 // ****************************************************************************
00054 // ************************** MapMode Class Functions *************************
00055 // ****************************************************************************
00056 // ***************************** GENERAL FUNCTIONS ****************************
00057 // ****************************************************************************
00058 
00059 MapMode::MapMode(string filename) :
00060   _map_filename(filename)
00061 {
00062   if (MAP_DEBUG)
00063     cout << "MAP: MapMode constructor invoked" << endl;
00064   _loading_map = this;
00065 
00066   mode_type = MODE_MANAGER_MAP_MODE;
00067   _map_state = EXPLORE;
00068   _lastID = 1000;
00069 
00070   _virtual_focus = new VirtualSprite();
00071   _virtual_focus->SetXPosition(0, 0.0f);
00072   _virtual_focus->SetYPosition(0, 0.0f);
00073   _virtual_focus->movement_speed = NORMAL_SPEED;
00074   _virtual_focus->SetNoCollision(true);
00075   _virtual_focus->SetVisible(false);
00076 
00077   _dialogue_manager = new DialogueManager();
00078 
00079   _intro_timer.Initialize(7000, 0, this);
00080 
00081   // TODO: Load the map data in a seperate thread
00082   _Load();
00083 
00084   // TEMP: Load dialogue icon
00085   if (private_map::new_dialogue_icon.GetNumFrames() == 0) {
00086     std::vector<StillImage> frames;
00087     VideoManager->LoadMultiImageFromElementsSize(frames, "img/misc/dialogue_icon.png", 32, 32);
00088 
00089     for( size_t i = 0; i < frames.size(); ++i ) {
00090       private_map::new_dialogue_icon.AddFrame(frames[i], 100);
00091     }
00092 
00093     private_map::new_dialogue_icon.SetDimensions(2, 2);
00094     private_map::new_dialogue_icon.Load();
00095   }
00096 }
00097 
00098 
00099 
00100 MapMode::~MapMode() {
00101   if (MAP_DEBUG) cout << "MAP: MapMode destructor invoked" << endl;
00102 
00103   for (uint32 i = 0; i < _music.size(); i++) {
00104     _music[i].FreeMusic();
00105   }
00106 
00107   for (uint32 i = 0; i < _sounds.size(); i++) {
00108     _sounds[i].FreeSound();
00109   }
00110 
00111   // Delete all of the tile images
00112   for (uint32 i = 0; i < _tile_images.size(); i++) {
00113     delete(_tile_images[i]);
00114   }
00115 
00116   // Delete all of the map objects
00117   for (uint32 i = 0; i < _ground_objects.size(); i++) {
00118     delete(_ground_objects[i]);
00119   }
00120 
00121   for (uint32 i = 0; i < _pass_objects.size(); i++) {
00122     delete(_pass_objects[i]);
00123   }
00124   for (uint32 i = 0; i < _sky_objects.size(); i++) {
00125     delete(_sky_objects[i]);
00126   }
00127   delete(_virtual_focus);
00128 
00129   delete(_dialogue_manager);
00130 
00131   _map_script.CloseFile();
00132 }
00133 
00134 
00135 // Resets appropriate class members.
00136 void MapMode::Reset() {
00137   // Reset active video engine properties
00138   VideoManager->SetCoordSys(0.0f, SCREEN_COLS, SCREEN_ROWS, 0.0f);
00139   VideoManager->SetDrawFlags(VIDEO_X_CENTER, VIDEO_Y_BOTTOM, 0);
00140 
00141   if (!VideoManager->SetFont("map"))
00142       cerr << "MAP ERROR: Failed to set the map font" << endl;
00143 
00144   // Let all map objects know that this is the current map
00145   MapMode::_current_map = this;
00146 
00147   // TEMP: This will need to be scripted later
00148   if (_music.size() > 0 && _music[0].IsPlaying() == false) {
00149     _music[0].PlayMusic();
00150   }
00151 
00152   _intro_timer.Run();
00153 }
00154 
00155 
00156 // Loads the map from a Lua file.
00157 void MapMode::_Load() {
00158   // ---------- (1) Open map script file and read in basic map properties and tile definitions
00159   if (_map_script.OpenFile(_map_filename) == false) {
00160     return;
00161   }
00162 
00163   _map_name = MakeUnicodeString(_map_script.ReadString("map_name"));
00164   _location_graphic.SetFilename("img/menus/locations/" + _map_script.ReadString("location_filename"));
00165   if (_location_graphic.Load() == false) {
00166     cerr << "MAP ERROR: failed to load location graphic image: " << _location_graphic.GetFilename() << endl;
00167   }
00168 
00169   _num_tile_rows = _map_script.ReadInt("num_tile_rows");
00170   _num_tile_cols = _map_script.ReadInt("num_tile_cols");
00171   _num_grid_rows = _num_tile_rows * 2;
00172   _num_grid_cols = _num_tile_cols * 2;
00173 
00174   // Do some checking to make sure tables are of the proper size
00175   // NOTE: we only check that the number of rows are correct, but not the number of columns
00176   // NOTE: the "+ 1" is due to a bug in ReadGetTableSize that is not yet resolved
00177   if (_map_script.GetTableSize("map_grid") + 1 != _num_grid_rows) {
00178     cerr << "MAP ERROR: In MapMode::_Load(), the map_grid table had an incorrect number of rows" << endl;
00179     return;
00180   }
00181   if (_map_script.GetTableSize("lower_layer") + 1 != _num_tile_rows) {
00182     cerr << "MAP ERROR: In MapMode::_Load(), the lower_layer table had an incorrect number of rows" << endl;
00183     return;
00184   }
00185   if (_map_script.GetTableSize("middle_layer") + 1 != _num_tile_rows) {
00186     cerr << "MAP ERROR: In MapMode::_Load(), the middle_layer table had an incorrect number of rows" << endl;
00187     return;
00188   }
00189   if (_map_script.GetTableSize("upper_layer") + 1 != _num_tile_rows) {
00190     cerr << "MAP ERROR: In MapMode::_Load(), the upper_layer table had an incorrect number of rows" << endl;
00191     return;
00192   }
00193 
00194   // ---------- (2) Initialize all of the tile and grid mappings
00195   _LoadTiles();
00196 
00197   // ---------- (3) Load map sounds and music
00198   vector<string> sound_filenames;
00199   _map_script.ReadStringVector("sound_filenames", sound_filenames);
00200 
00201   for (uint32 i = 0; i < sound_filenames.size(); i++) {
00202     SoundDescriptor new_sound;
00203     if (new_sound.LoadSound(sound_filenames[i]) == true) {
00204       _sounds.push_back(new_sound);
00205     }
00206     else {
00207       cerr << "MAP ERROR: failed to load map sound: " << sound_filenames[i] << endl;
00208       return;
00209     }
00210   }
00211 
00212   vector<string> music_filenames;
00213   _map_script.ReadStringVector("music_filenames", music_filenames);
00214   for (uint32 i = 0; i < music_filenames.size(); i++) {
00215     MusicDescriptor new_music;
00216     if (new_music.LoadMusic(music_filenames[i]) == true) {
00217       _music.push_back(new_music);
00218     }
00219     else {
00220       cerr << "MAP ERROR: failed to load map music: " << music_filenames[i] << endl;
00221       return;
00222     }
00223   }
00224 
00225   // ---------- (4) Construct all enemies that may appear on this map
00226   vector<int32> enemy_ids;
00227   _map_script.ReadIntVector("enemy_ids", enemy_ids);
00228   for (uint32 i = 0; i < enemy_ids.size(); i++) {
00229     _enemies.push_back(GlobalEnemy(enemy_ids[i]));
00230   }
00231 
00232   // ---------- (5) Call the map script's load function, which will
00233   ScriptCallFunction<void>(_map_script.GetLuaState(), "Load", this);
00234   _update_function = _map_script.ReadFunctionPointer("Update");
00235 } // void MapMode::_Load()
00236 
00237 
00238 
00239 void MapMode::_LoadTiles() {
00240   // Contains all of the tileset filenames used (string does not contain path information or file extensions)
00241   vector<string> tileset_filenames;
00242   // A container to temporarily retain all tile images loaded for each tileset. Each inner vector contains 256 StillImages
00243   vector<vector<StillImage> > tileset_images;
00244   // Used to determine whether each tile is used by the map or not. An entry of -1 indicates that particular tile is not used
00245   vector<int32> tile_references;
00246   // Temporarily holds all animated tile images. The map key is the value of the tile index, before translation
00247   map<uint32, AnimatedImage> tile_animations;
00248 
00249   // ---------- (1) Construct the map grid (contains map traveriblity information)
00250 
00251   _map_script.OpenTable("map_grid");
00252   for (uint16 r = 0; r < _num_grid_rows; r++) {
00253     _map_grid.push_back(vector<uint32>());
00254     _map_script.ReadUIntVector(r, _map_grid.back());
00255   }
00256   _map_script.CloseTable();
00257   // ---------- (2) Load in the map tileset images and initialize all map tiles
00258 
00259   _map_script.ReadStringVector("tileset_filenames", tileset_filenames);
00260 
00261   // Note: each tileset image is 512x512 pixels, yielding 256 32x32 pixel tiles each
00262   for (uint32 i = 0; i < tileset_filenames.size(); i++) {
00263     // Construct the image filename from the tileset filename and create a new vector to use in the LoadMultiImage call
00264     string image_filename = "img/tilesets/" + tileset_filenames[i] + ".png";
00265     tileset_images.push_back(vector<StillImage>(TILES_PER_TILESET));
00266 
00267     for (uint32 j = 0; j < TILES_PER_TILESET; j++) {
00268       tileset_images[i][j].SetDimensions(2.0f, 2.0f);
00269     }
00270 
00271     if (VideoManager->LoadMultiImageFromNumberElements(tileset_images[i], image_filename, 16, 16) == false) {
00272       cerr << "MAP ERROR: MapMode::_LoadTiles() failed to load tileset image:" << image_filename << endl;
00273       return;
00274     }
00275   }
00276   // ---------- (3) Read in the map tile indeces from all three tile layers
00277 
00278   // First create the properly sized 2D grid of map tiles, then read the tile indeces from the map file
00279   for (uint32 r = 0; r < _num_tile_rows; r++) {
00280     _tile_grid.push_back(vector<MapTile>(_num_tile_cols));
00281   }
00282 
00283   vector<int32> table_row; // Used to temporarily store a row of integer table data
00284 
00285   // Read the lower_layer
00286   _map_script.OpenTable("lower_layer");
00287   for (uint32 r = 0; r < _num_tile_rows; r++) {
00288     table_row.clear();
00289     _map_script.ReadIntVector(r, table_row);
00290     for (uint32 c = 0; c < _num_tile_cols; c++) {
00291       _tile_grid[r][c].lower_layer = table_row[c];
00292     }
00293   }
00294   _map_script.CloseTable();
00295 
00296   // Read the middle_layer
00297   _map_script.OpenTable("middle_layer");
00298   for (uint32 r = 0; r < _num_tile_rows; r++) {
00299     table_row.clear();
00300     _map_script.ReadIntVector(r, table_row);
00301     for (uint32 c = 0; c < _num_tile_cols; c++) {
00302       _tile_grid[r][c].middle_layer = table_row[c];
00303     }
00304   }
00305   _map_script.CloseTable();
00306 
00307   // Read the upper_layer
00308   _map_script.OpenTable("upper_layer");
00309   for (uint32 r = 0; r < _num_tile_rows; r++) {
00310     table_row.clear();
00311     _map_script.ReadIntVector(r, table_row);
00312     for (uint32 c = 0; c < _num_tile_cols; c++) {
00313       _tile_grid[r][c].upper_layer = table_row[c];
00314     }
00315   }
00316   _map_script.CloseTable();
00317 
00318   // ---------- (4) Determine which tiles in each tileset are referenced in this map
00319 
00320   // Set size to be equal to the total number of tiles and initialize all entries to -1 (unreferenced)
00321   tile_references.assign(tileset_filenames.size() * TILES_PER_TILESET, -1);
00322 
00323   for (uint32 r = 0; r < _num_tile_rows; r++) {
00324     for (uint32 c = 0; c < _num_tile_cols; c++) {
00325       if (_tile_grid[r][c].lower_layer >= 0)
00326         tile_references[_tile_grid[r][c].lower_layer] = 0;
00327       if (_tile_grid[r][c].middle_layer >= 0)
00328         tile_references[_tile_grid[r][c].middle_layer] = 0;
00329       if (_tile_grid[r][c].upper_layer >= 0)
00330         tile_references[_tile_grid[r][c].upper_layer] = 0;
00331     }
00332   }
00333 
00334   // Here, we have to convert the original tile indeces defined in the map file into a new form. The original index
00335   // indicates the tileset where the tile is used and its location in that tileset. We need to convert those indecs
00336   // so that they serve as an index to the MapMode::_tile_images vector, where the tile images will soon be stored.
00337 
00338   // Keeps track of the next translated index number to assign
00339   uint32 next_index = 0;
00340 
00341   for (uint32 i = 0; i < tile_references.size(); i++) {
00342     if (tile_references[i] >= 0) {
00343       tile_references[i] = next_index;
00344       next_index++;
00345     }
00346   }
00347 
00348   // Now, go back and re-assign all lower, middle, and upper tile layer indeces with the translated indeces
00349   for (uint32 r = 0; r < _num_tile_rows; r++) {
00350     for (uint32 c = 0; c < _num_tile_cols; c++) {
00351       if (_tile_grid[r][c].lower_layer >= 0)
00352         _tile_grid[r][c].lower_layer = tile_references[_tile_grid[r][c].lower_layer];
00353       if (_tile_grid[r][c].middle_layer >= 0)
00354         _tile_grid[r][c].middle_layer = tile_references[_tile_grid[r][c].middle_layer];
00355       if (_tile_grid[r][c].upper_layer >= 0)
00356         _tile_grid[r][c].upper_layer = tile_references[_tile_grid[r][c].upper_layer];
00357     }
00358   }
00359 
00360   // ---------- (5) Parse all of the tileset definition files and create any animated tile images that are used
00361 
00362   ReadScriptDescriptor tileset_script; // Used to access the tileset definition file
00363   vector<uint32> animation_info;   // Temporarily retains the animation data (tile frame indeces and display times)
00364 
00365   for (uint32 i = 0; i < tileset_filenames.size(); i++) {
00366     if (tileset_script.OpenFile("dat/tilesets/" + tileset_filenames[i] + ".lua") == false) {
00367       cerr << "MAP ERROR: In MapMode::_LoadTiles(), the map failed to load because it could not open a tileset definition file: "
00368         << tileset_script.GetFilename() << endl;
00369       return;
00370     }
00371 
00372     tileset_script.OpenTable("animated_tiles");
00373     for (uint32 j = 1; j <= tileset_script.GetTableSize(); j++) {
00374       animation_info.clear();
00375       tileset_script.ReadUIntVector(j, animation_info);
00376 
00377       // The index of the first frame in the animation. (i * TILES_PER_TILESET) factors in which tileset the frame comes from
00378       uint32 first_frame_index = animation_info[0] + (i * TILES_PER_TILESET);
00379 
00380       // Check if this animation is referenced in the map by looking at the first tile frame index. If it is not, continue on to the next animation
00381       if (tile_references[first_frame_index] == -1) {
00382         continue;
00383       }
00384 
00385       AnimatedImage new_animation;
00386       new_animation.SetDimensions(2.0f, 2.0f);
00387 
00388       // Each pair of entries in the animation info indicate the tile frame index (k) and the time (k+1)
00389       for (uint32 k = 0; k < animation_info.size(); k += 2) {
00390         new_animation.AddFrame(tileset_images[i][animation_info[k]], animation_info[k+1]);
00391       }
00392 
00393       tile_animations.insert(make_pair(first_frame_index, new_animation));
00394     }
00395     tileset_script.CloseTable();
00396     tileset_script.CloseFile();
00397   } // for (uint32 i = 0; i < tileset_filenames.size(); i++)
00398 
00399   // ---------- (6) Add all referenced tiles to the _tile_images vector, in the proper order
00400 
00401   for (uint32 i = 0; i < tileset_images.size(); i++) {
00402     for (uint32 j = 0; j < TILES_PER_TILESET; j++) {
00403       uint32 reference = (i * TILES_PER_TILESET) + j;
00404 
00405       if (tile_references[reference] >= 0) {
00406         // Add the tile as a StillImage
00407         if (tile_animations.find(reference) == tile_animations.end()) {
00408           _tile_images.push_back(new StillImage(tileset_images[i][j]));
00409         }
00410 
00411         // Add the tile as an AnimatedImage
00412         else {
00413           AnimatedImage* new_animated_tile = new AnimatedImage(tile_animations[reference]);
00414           _tile_images.push_back(new_animated_tile);
00415           _animated_tile_images.push_back(new_animated_tile);
00416         }
00417       }
00418     }
00419   }
00420 
00421   // Remove all tileset images. Any tiles which were not added to _tile_images will no longer exist in memory
00422   tileset_images.clear();
00423 } // void MapMode::_LoadTiles()
00424 
00425 // ****************************************************************************
00426 // **************************** UPDATE FUNCTIONS ******************************
00427 // ****************************************************************************
00428 
00429 // Updates the game state when in map mode. Called from the main game loop.
00430 void MapMode::Update() {
00431   _time_elapsed = SystemManager->GetUpdateTime();
00432 
00433   // ---------- (1) Call the map's update script function
00434   ScriptCallFunction<void>(_update_function);
00435 
00436   // ---------- (2) Process user input
00437   switch (_map_state) {
00438     case EXPLORE:
00439       _HandleInputExplore();
00440       break;
00441     case DIALOGUE:
00442       _dialogue_manager->Update();
00443       break;
00444     default:
00445       _HandleInputExplore();
00446       break;
00447   }
00448 
00449   // ---------- (3) Update all animated tile images
00450   for (uint32 i = 0; i < _animated_tile_images.size(); i++) {
00451     _animated_tile_images[i]->Update();
00452   }
00453 
00454   // ---------- (4) Update all objects on the map
00455   for( uint32 i = 0; i < _zones.size(); i++ ) {
00456     _zones[i]->Update();
00457   }
00458 
00459   for (uint32 i = 0; i < _ground_objects.size(); i++) {
00460     _ground_objects[i]->Update();
00461   }
00462   for (uint32 i = 0; i < _pass_objects.size(); i++) {
00463     _pass_objects[i]->Update();
00464   }
00465   for (uint32 i = 0; i < _sky_objects.size(); i++) {
00466     _sky_objects[i]->Update();
00467   }
00468 
00469   // ---------- (5) Sort the objects so they are in the correct draw order ********
00470   std::sort( _ground_objects.begin(), _ground_objects.end(), MapObject_Ptr_Less() );
00471 } // void MapMode::Update()
00472 
00473 
00474 // Updates the game status when MapMode is in the 'explore' state
00475 void MapMode::_HandleInputExplore() {
00476   // Do the fade to battle mode
00477   // Doing this first should prevent user input
00478 //  if (_fade_to_battle_mode) {
00479 //    // Only start battle mode once the fade is done.
00480 //    if (!VideoManager->IsFading()) {
00481 //      // Clear fade instantly
00482 //      VideoManager->FadeScreen(Color::clear, 0.0f);
00483 //      _fade_to_battle_mode = false;
00484 //      BattleMode *BM = new BattleMode();
00485 //      ModeManager->Push(BM);
00486 //    }
00487 //    return;
00488 //  }
00489 
00490   // Go to menu mode if the user requested it
00491   if (InputManager->MenuPress()) {
00492     MenuMode *MM = new MenuMode(_map_name, _location_graphic.GetFilename());
00493     ModeManager->Push(MM);
00494     return;
00495   }
00496 
00497   // Toggle running versus walking
00498 //  if (InputManager->CancelPress()) {
00499 //    if (speed_double) {
00500 //      _focused_object->step_speed /= 2;
00501 //      speed_double = false;
00502 //    }
00503 //    else {
00504 //      _focused_object->step_speed *= 2;
00505 //      speed_double = true;
00506 //    }
00507 //  }
00508 
00509   if (InputManager->ConfirmPress()) {
00510     MapObject* obj = _FindNearestObject(_camera);
00511     if (obj && (obj->GetType() == VIRTUAL_TYPE || obj->GetType() == SPRITE_TYPE)) {
00512       VirtualSprite *sp = reinterpret_cast<VirtualSprite*>(obj);
00513 
00514       if (sp->HasDialogue()) {
00515         sp->SaveState();
00516         _camera->moving = false;
00517 
00518         sp->moving = false;
00519         sp->current_action = -1;
00520         sp->SetDirection(VirtualSprite::CalculateOppositeDirection(_camera->GetDirection()));
00521         _dialogue_manager->SetCurrentDialogue(sp->GetCurrentDialogue());
00522         sp->NextDialogue();
00523         _map_state = DIALOGUE;
00524         return;
00525       }
00526     }
00527   }
00528 
00529   // Detect and handle movement input from the user
00530   if (InputManager->UpState() || InputManager->DownState() || InputManager->LeftState() || InputManager->RightState()) {
00531     _camera->moving = true;
00532   }
00533   else {
00534     _camera->moving = false;
00535   }
00536 
00537   // Determine the direction of movement. Priority of movement is given to: up, down, left, right.
00538   // In the case of diagonal movement, the direction that the sprite should face also needs to be
00539   // deduced.
00540   if (_camera->moving == true) {
00541     if (InputManager->UpState()) {
00542       if (InputManager->LeftState()) {
00543         _camera->SetDirection(NORTHWEST);
00544       }
00545       else if (InputManager->RightState()) {
00546         _camera->SetDirection(NORTHEAST);
00547       }
00548       else {
00549         _camera->SetDirection(NORTH);
00550       }
00551     }
00552     else if (InputManager->DownState()) {
00553       if (InputManager->LeftState()) {
00554         _camera->SetDirection(SOUTHWEST);
00555       }
00556       else if (InputManager->RightState()) {
00557         _camera->SetDirection(SOUTHEAST);
00558       }
00559       else {
00560         _camera->SetDirection(SOUTH);
00561       }
00562     }
00563     else if (InputManager->LeftState()) {
00564       _camera->SetDirection(WEST);
00565     }
00566     else if (InputManager->RightState()) {
00567       _camera->SetDirection(EAST);
00568     }
00569   } // if (_camera->moving == true)
00570 } // void MapMode::_HandleInputExplore()
00571 
00572 
00573 
00574 MapObject* MapMode::_FindNearestObject(const VirtualSprite* sprite) {
00575   // The edges of the collision rectangle to check
00576   float top, bottom, left, right;
00577 
00578   // ---------- (1): Using the sprite's direction, determine the area to check for other objects
00579   if (sprite->direction & FACING_NORTH) {
00580     bottom = sprite->ComputeYLocation() - sprite->coll_height;
00581     top = bottom - 3.0f;
00582     left = sprite->ComputeXLocation() - sprite->coll_half_width;
00583     right = sprite->ComputeXLocation() + sprite->coll_half_width;
00584   }
00585   else if (sprite->direction & FACING_SOUTH) {
00586     top = sprite->ComputeYLocation();
00587     bottom = top + 3.0f;
00588     left = sprite->ComputeXLocation() - sprite->coll_half_width;
00589     right = sprite->ComputeXLocation() + sprite->coll_half_width;
00590   }
00591   else if (sprite->direction & FACING_WEST) {
00592     right = sprite->ComputeXLocation() - sprite->coll_half_width;
00593     left = right - 3.0f;
00594     bottom = sprite->ComputeYLocation();
00595     top = bottom - sprite->coll_height;
00596   }
00597   else if (sprite->direction & FACING_EAST) {
00598     left = sprite->ComputeXLocation() + sprite->coll_half_width;
00599     right = left + 3.0f;
00600     bottom = sprite->ComputeYLocation();
00601     top = bottom - sprite->coll_height;
00602   }
00603   else {
00604     if (MAP_DEBUG)
00605       cerr << "MAP ERROR: sprite was set to invalid direction in MapMode::_FindNearestObject()" << endl;
00606     return NULL;
00607   }
00608 
00609   // A vector to contain objects which are valid for the sprite to interact with
00610   vector<MapObject*> valid_objects;
00611   // A pointer to the object which has been found to be the closest to the sprite within valid_objs
00612   MapObject* closest = NULL;
00613 
00614   // ---------- (2): Go through all objects and determine which (if any) are valid
00615   for (map<uint16, MapObject*>::iterator i = _all_objects.begin(); i != _all_objects.end(); i++) {
00616     MapObject* obj = i->second;
00617     if( obj == sprite ) //A sprite can't target itself
00618       continue;
00619 
00620     // Objects in different contexts can not interact with one another
00621     if (obj->context & sprite->context == 0) // Since objects can span multiple context, we check that no contexts are equal
00622       continue;
00623 
00624     // Compute the full position coordinates for the object under study
00625     float other_x_location = obj->ComputeXLocation();
00626     float other_y_location = obj->ComputeYLocation();
00627 
00628     // Verify that the bounding boxes overlap on the horizontal axis
00629     if (!(other_x_location - obj->coll_half_width > right
00630       || other_x_location + obj->coll_half_width < left)) {
00631       // Verify that the bounding boxes overlap on the vertical axis
00632       if (!(other_y_location - obj->coll_height > bottom
00633         || other_y_location < top )) {
00634         // Boxes overlap on both axes, it is a valid interaction
00635         valid_objects.push_back(obj);
00636       }
00637     }
00638   } // for (map<MapObject*>::iterator i = _all_objects.begin(); i != _all_objects.end(); i++)
00639 
00640   // If there are one or less objects that are valid, then we are done here.
00641   if (valid_objects.empty()) {
00642     return NULL;
00643   }
00644   else if (valid_objects.size() == 1) {
00645     return valid_objects[0];
00646   }
00647 
00648   // ---------- (3): Figure out which of the valid objects is the closest to the sprite
00649   // NOTE: For simplicity, we simply find which object has the location coordinates which are
00650   // closest to the sprite's coordinates using the Manhattan distance.
00651 
00652   // Used to hold the full position coordinates of the sprite
00653   float source_x = sprite->ComputeXLocation();
00654   float source_y = sprite->ComputeYLocation();
00655 
00656   closest = valid_objects[0];
00657   float min_distance = fabs(source_x - closest->ComputeXLocation())
00658     + fabs(source_y - closest->ComputeYLocation());
00659 
00660   // Determine which object's position is closest to the sprite
00661   for (uint32 i = 1; i < valid_objects.size(); i++) {
00662     float dist = fabs(source_x - valid_objects[i]->ComputeXLocation())
00663       + fabs(source_y - valid_objects[i]->ComputeYLocation());
00664     if (dist < min_distance) {
00665       closest = valid_objects[i];
00666       min_distance = dist;
00667     }
00668   }
00669   return closest;
00670 } // MapObject* MapMode::_FindNearestObject(VirtualSprite* sprite)
00671 
00672 
00673 
00674 bool MapMode::_DetectCollision(VirtualSprite* sprite) {
00675   // NOTE: Whether the argument pointer is valid is not checked here, since the object pointer
00676   // itself presumably called this function.
00677 
00678   // The single X,Y floating point coordinates of the sprite
00679   float x_location = sprite->ComputeXLocation();
00680   float y_location = sprite->ComputeYLocation();
00681 
00682   // The coordinates corresponding to the four sides of the sprite's collision rectangle (cr)
00683   float cr_left = x_location - sprite->coll_half_width;
00684   float cr_right = x_location + sprite->coll_half_width;
00685   float cr_top = y_location - sprite->coll_height;
00686   // The bottom of the sprite's collision rectangle is its y_location
00687 
00688   // ---------- (1): Check if the sprite's position has gone out of bounds
00689 
00690   if (cr_left < 0.0f || cr_top < 0.0f || cr_right >= static_cast<float>(_num_grid_cols) ||
00691     y_location >= static_cast<float>(_num_grid_rows)) {
00692     return true;
00693   }
00694 
00695   // Do not do tile or object based collision detection for this sprite if it has this member set
00696   if (sprite->no_collision == true) {
00697     return false;
00698   }
00699 
00700   // A pointer to the layer of objects to do the collision detection with
00701   vector<MapObject*>* objects;
00702 
00703   if (sprite->sky_object == false) { // Do tile collision detection for ground objects only
00704 
00705     // ---------- (2): Determine if the sprite's collision rectangle overlaps any unwalkable tiles
00706 
00707     // NOTE: Because the sprite's collision rectangle was determined to be within the map bounds,
00708     // the map grid tile indeces referenced in this loop are all valid entries.
00709     for (uint32 r = static_cast<uint32>(cr_top); r <= static_cast<uint32>(y_location); r++) {
00710       for (uint32 c = static_cast<uint32>(cr_left); c <= static_cast<uint32>(cr_right); c++) {
00711         if (_map_grid[r][c] & sprite->context > 0) { // Then this overlapping tile is unwalkable
00712           return true;
00713         }
00714       }
00715     }
00716     objects = &_ground_objects;
00717   }
00718   else {
00719     objects = &_sky_objects;
00720   }
00721 
00722   // ---------- (3): Determine if two object's collision rectangles overlap
00723 
00724   for (uint32 i = 0; i < objects->size(); i++) {
00725     // Only verify this object if it is not the same object as the sprite
00726     if ((*objects)[i]->object_id != sprite->object_id
00727       && !(*objects)[i]->no_collision
00728       && (*objects)[i]->context & sprite->context > 0 )
00729     {
00730       // Compute the full position coordinates of the other object
00731       float other_x_location = (*objects)[i]->ComputeXLocation();
00732       float other_y_location = (*objects)[i]->ComputeYLocation();;
00733 
00734       // Verify that the bounding boxes overlap on the horizontal axis
00735       if (!(other_x_location - (*objects)[i]->coll_half_width > cr_right
00736         || other_x_location + (*objects)[i]->coll_half_width < cr_left)) {
00737         // Verify that the bounding boxes overlap on the vertical axis
00738         if (!(other_y_location - (*objects)[i]->coll_height > y_location || other_y_location < cr_top )) {
00739           // Boxes overlap on both axis, there is a colision
00740           if (sprite->GetType() == ENEMY_TYPE && (*objects)[i] == _camera) {
00741             EnemySprite *enemy = reinterpret_cast<EnemySprite*>(sprite);
00742             if (enemy->IsHostile()) {
00743               enemy->ChangeStateDead();
00744               BattleMode *BM = new BattleMode();
00745               BM->AddMusic(enemy->GetBattleMusicTheme());
00746               ModeManager->Push(BM);
00747               const vector<uint32>& enemy_party = enemy->RetrieveRandomParty();
00748               for (uint32 i = 0; i < enemy_party.size(); i++) {
00749                 BM->AddEnemy(enemy_party[i]);
00750               }
00751               return false;
00752             }
00753           }
00754 
00755           if ((*objects)[i]->GetType() == ENEMY_TYPE && sprite == _camera) {
00756             EnemySprite *enemy = reinterpret_cast<EnemySprite*>((*objects)[i]);
00757             if (enemy->IsHostile()) {
00758               enemy->ChangeStateDead();
00759               BattleMode *BM = new BattleMode();
00760               BM->AddMusic(enemy->GetBattleMusicTheme());
00761               ModeManager->Push(BM);
00762               const vector<uint32>& enemy_party = enemy->RetrieveRandomParty();
00763               for (uint32 i = 0; i < enemy_party.size(); i++) {
00764                 BM->AddEnemy(enemy_party[i]);
00765               }
00766               return false;
00767             }
00768           }
00769 
00770           return true;
00771         }
00772       }
00773 
00774     }
00775   }
00776 
00777   // No collision was detected
00778   return false;
00779 } // bool MapMode::_DetectCollision(VirtualSprite* sprite)
00780 
00781 
00782 
00783 void MapMode::_FindPath(const VirtualSprite* sprite, std::vector<PathNode>& path, const PathNode& dest) {
00784   // NOTE: Refer to the implementation of the A* algorithm to understand what all these lists and scores are
00785   std::vector<PathNode> open_list;
00786   std::vector<PathNode> closed_list;
00787 
00788   // The starting node of this path discovery
00789   PathNode source_node(static_cast<int16>(sprite->y_position), static_cast<int16>(sprite->x_position));
00790 
00791   // The current "best node"
00792   PathNode best_node;
00793   // Used to hold the eight adjacent nodes
00794   PathNode nodes[8];
00795 
00796   // Temporary delta variables used in calculation of a node's heuristic (h score)
00797   uint32 x_delta, y_delta;
00798   // The number of grid elements that the sprite's collision rectange spreads outward and upward
00799   int16 x_span, y_span;
00800   // The number to add to a node's g_score, depending on whether it is a lateral or diagonal movement
00801   int16 g_add;
00802 
00803   path.clear();
00804   x_span = static_cast<int16>(sprite->coll_half_width);
00805   y_span = static_cast<int16>(sprite->coll_height);
00806 
00807   // Check that the source node is not the same as the destination node
00808   if (source_node == dest) {
00809     if (MAP_DEBUG)
00810       cerr << "MAP ERROR: source node is same as destination in MapMode::_FindPath()" << endl;
00811     return;
00812   }
00813 
00814   // Check that the destination is valid for the sprite to move to
00815   if ((dest.col - x_span < 0) || (dest.row - y_span < 0) ||
00816     (dest.col + x_span >= (_num_grid_cols)) || (dest.row >= (_num_grid_rows))) {
00817     if (MAP_DEBUG)
00818       cerr << "MAP ERROR: sprite can not move to destination node on path because it exceeds map boundaries" << endl;
00819     return;
00820   }
00821   for (int16 r = dest.row - y_span; r < dest.row; r++) {
00822     for (int16 c = dest.col - x_span; c < dest.col + x_span; c++) {
00823       if (_map_grid[r][c] & sprite->context > 0) {
00824         if (MAP_DEBUG)
00825           cerr << "MAP ERROR: sprite can not move to destination node on path because one or more grid tiles are unwalkable" << endl;
00826         return;
00827       }
00828     }
00829   }
00830 
00831   open_list.push_back(source_node);
00832 
00833   while (!open_list.empty()) {
00834 //    sort(open_list.begin(), open_list.end(), PathNode::NodePred());
00835     sort(open_list.begin(), open_list.end());
00836     best_node = open_list.back();
00837     open_list.pop_back();
00838     closed_list.push_back(best_node);
00839 
00840     // Check if destination has been reached, and break out of the loop if so
00841     if (best_node == dest) {
00842       break;
00843     }
00844 
00845     // Setup the coordinates of the 8 adjacent nodes to the best node
00846     nodes[0].row = closed_list.back().row - 1; nodes[0].col = closed_list.back().col;
00847     nodes[1].row = closed_list.back().row + 1; nodes[1].col = closed_list.back().col;
00848     nodes[2].row = closed_list.back().row;     nodes[2].col = closed_list.back().col - 1;
00849     nodes[3].row = closed_list.back().row;     nodes[3].col = closed_list.back().col + 1;
00850     nodes[4].row = closed_list.back().row - 1; nodes[4].col = closed_list.back().col - 1;
00851     nodes[5].row = closed_list.back().row - 1; nodes[5].col = closed_list.back().col + 1;
00852     nodes[6].row = closed_list.back().row + 1; nodes[6].col = closed_list.back().col - 1;
00853     nodes[7].row = closed_list.back().row + 1; nodes[7].col = closed_list.back().col + 1;
00854 
00855     // Check the eight adjacent nodes
00856     for (uint8 i = 0; i < 8; ++i) {
00857       // ---------- (A): Check that the sprite's collision rectangle will be within the map boundaries
00858       if ((nodes[i].col - x_span < 0) || (nodes[i].row - y_span < 0) ||
00859         (nodes[i].col + x_span >= _num_grid_cols) || (nodes[i].row >= _num_grid_rows)) {
00860         continue;
00861       }
00862 
00863       // ---------- (B): Check that all grid nodes that the sprite's collision rectangle will overlap are walkable
00864       bool continue_loop = true;
00865       for (int16 r = nodes[i].row - y_span; r < nodes[i].row && continue_loop; r++) {
00866         for (int16 c = nodes[i].col - x_span; c < nodes[i].col + x_span; c++) {
00867           if (_map_grid[r][c] & sprite->context > 0) {
00868             continue_loop = false;
00869             break;
00870           }
00871         }
00872       }
00873       if (continue_loop == false) { // This node is invalid
00874         continue;
00875       }
00876 
00877       // ---------- (C): Check if the Node is already in the closed list
00878       if (find(closed_list.begin(), closed_list.end(), nodes[i]) != closed_list.end()) {
00879         continue;
00880       }
00881 
00882       // ---------- (D): If this point has been reached, the node is valid for the sprite to move to
00883 
00884       // If this is a lateral adjacent node, g_score is +10, otherwise diagonal adjacent node is +14
00885       if (i < 4)
00886         g_add = 10;
00887       else
00888         g_add = 14;
00889 
00890       // Set the node's parent and calculate its g_score
00891       nodes[i].parent_row = best_node.row;
00892       nodes[i].parent_col = best_node.col;
00893       nodes[i].g_score = best_node.g_score + g_add;
00894 
00895       // ---------- (E): Check to see if the node is already on the open list and update it if necessary
00896       vector<PathNode>::iterator iter = find(open_list.begin(), open_list.end(), nodes[i]);
00897       if (iter != open_list.end()) {
00898         // If its G is higher, it means that the path we are on is better, so switch the parent
00899         if (iter->g_score > nodes[i].g_score) {
00900           iter->g_score = nodes[i].g_score;
00901           iter->f_score = nodes[i].g_score + iter->h_score;
00902           iter->parent_row = nodes[i].parent_row;
00903           iter->parent_col = nodes[i].parent_col;
00904         }
00905       }
00906       // ---------- (F): Add the new node to the open list
00907       else {
00908         // Calculate the H and F score of the new node (the heuristic used is diagonal)
00909         x_delta = abs(dest.col - nodes[i].col);
00910         y_delta = abs(dest.row - nodes[i].row);
00911         if (x_delta > y_delta)
00912           nodes[i].h_score = 14 * y_delta + 10 * (x_delta - y_delta);
00913         else
00914           nodes[i].h_score = 14 * x_delta + 10 * (y_delta - x_delta);
00915 
00916         nodes[i].f_score = nodes[i].g_score + nodes[i].h_score;
00917         open_list.push_back(nodes[i]);
00918       }
00919     } // for (uint8 i = 0; i < 8; ++i)
00920   } // while (!open_list.empty())
00921 
00922   if (open_list.empty()) {
00923     if (MAP_DEBUG)
00924       cerr << "MAP ERROR: could not find path to destination" << endl;
00925     path.push_back( source_node );
00926     return;
00927   }
00928 
00929   // Add the destination node to the vector, retain its parent, and remove it from the closed list
00930   path.push_back(closed_list.back());
00931   int16 parent_row = closed_list.back().parent_row;
00932   int16 parent_col = closed_list.back().parent_col;
00933   //PathNode* parent = closed_list.back().parent;
00934   closed_list.pop_back();
00935 
00936   // Go backwards through the closed list to construct the path
00937   for (vector<PathNode>::iterator iter = closed_list.end() - 1; iter != closed_list.begin(); --iter) {
00938     if ( iter->col == parent_col && iter->row == parent_row ) { // Find the parent of the node, add it to the path, and then set a new parent node
00939       path.push_back(*iter);
00940       parent_col = iter->parent_col;
00941       parent_row = iter->parent_row;
00942     }
00943   }
00944   std::reverse( path.begin(), path.end() );
00945 } // void MapMode::_FindPath(const VirtualSprite* sprite, std::vector<PathNode>& path, const PathNode& dest)
00946 
00947 // ****************************************************************************
00948 // **************************** DRAW FUNCTIONS ********************************
00949 // ****************************************************************************
00950 
00951 #define __MAP_CHANGE_1__
00952 #define __MAP_CHANGE_2__
00953 
00954 
00955 // Determines things like our starting tiles
00956 void MapMode::_CalculateDrawInfo() {
00957   // TRYING TO GET RID OF PROBLEMS OF DUPLICATED LINES IN MAP
00958   // THIS CODE IS TEMPORAL AND NOT COMPLETELY WORKING
00959 
00960 #ifdef __MAP_CHANGE_1__
00961   static float x (_draw_info.tile_x_start);
00962   static float y (_draw_info.tile_y_start);
00963 
00964 //  if (VideoManager->GetWidth() == 1024 && VideoManager->GetHeight() == 768)
00965   {
00966     _draw_info.tile_x_start = x;
00967     _draw_info.tile_y_start = y;
00968   }
00969 #endif
00970 
00971   // ---------- (1) Set the default starting draw positions for the tiles (top left tile)
00972 
00973   // The camera's position is in terms of the 16x16 grid, which needs to be converted into 32x32 coordinates.
00974   float camera_x = _camera->ComputeXLocation();
00975   float camera_y = _camera->ComputeYLocation();
00976 
00977   // Determine the draw coordinates of the top left corner using the camera's current position
00978   _draw_info.tile_x_start = 1.0f - _camera->x_offset;
00979   if (IsOddNumber(_camera->x_position))
00980     _draw_info.tile_x_start -= 1.0f;
00981 
00982   _draw_info.tile_y_start = 2.0f - _camera->y_offset;
00983   if (IsOddNumber(_camera->y_position))
00984     _draw_info.tile_y_start -= 1.0f;
00985 
00986   // By default the map draws 32 + 1 columns and 24 + 1 rows of tiles, the maximum that can fit on the screen.
00987   _draw_info.num_draw_cols = TILE_COLS + 1;
00988   _draw_info.num_draw_rows = TILE_ROWS + 1;
00989 
00990   // The default starting tile row and column is relative to the map camera's current position.
00991   _draw_info.starting_col = (_camera->x_position / 2) - HALF_TILE_COLS;
00992   _draw_info.starting_row = (_camera->y_position / 2) - HALF_TILE_ROWS;
00993 
00994   // ---------- (2) Determine the coordinates for the screen edges on the map grid
00995 
00996   _draw_info.top_edge    = camera_y - HALF_SCREEN_ROWS;
00997   _draw_info.bottom_edge = camera_y + HALF_SCREEN_ROWS;
00998   _draw_info.left_edge   = camera_x - HALF_SCREEN_COLS;
00999   _draw_info.right_edge  = camera_x + HALF_SCREEN_COLS;
01000 
01001 
01002 
01003   // ---------- (3) Check for special conditions that modify the drawing state
01004 
01005   // Usually the map centers on the camera's position, but when the camera becomes close to
01006   // the edges of the map, we need to modify the drawing properties of the frame.
01007 
01008   // Camera exceeds the left boundary of the map
01009   if (_draw_info.starting_col < 0) {
01010     _draw_info.starting_col = 0;
01011     _draw_info.tile_x_start = 1.0f;
01012     _draw_info.left_edge = 0.0f;
01013     _draw_info.right_edge = SCREEN_COLS;
01014   }
01015   // Camera exceeds the right boundary of the map
01016   else if (_draw_info.starting_col + TILE_COLS >= _num_tile_cols) {
01017     _draw_info.starting_col = static_cast<int16>(_num_tile_cols - TILE_COLS);
01018     _draw_info.tile_x_start = 1.0f;
01019     _draw_info.right_edge = static_cast<float>(_num_grid_cols);
01020     _draw_info.left_edge = _draw_info.right_edge - SCREEN_COLS;
01021   }
01022 
01023   // Camera exceeds the top boundary of the map
01024   if (_draw_info.starting_row < 0) {
01025     _draw_info.starting_row = 0;
01026     _draw_info.tile_y_start = 2.0f;
01027     _draw_info.top_edge = 0.0f;
01028     _draw_info.bottom_edge = SCREEN_ROWS;
01029   }
01030   // Camera exceeds the bottom boundary of the map
01031   else if (_draw_info.starting_row + TILE_ROWS >= _num_tile_rows) {
01032     _draw_info.starting_row = static_cast<int16>(_num_tile_rows - TILE_ROWS);
01033     _draw_info.tile_y_start = 2.0f;
01034     _draw_info.bottom_edge = static_cast<float>(_num_grid_rows);
01035     _draw_info.top_edge = _draw_info.bottom_edge - SCREEN_ROWS;
01036   }
01037 
01038   // Check for the conditions where the tile images align perfectly with the screen and one less row or column of tiles is drawn
01039   if (IsFloatInRange(_draw_info.tile_x_start, 0.999f, 1.001f)) { // Is the value approximately equal to 1.0f?
01040     _draw_info.num_draw_cols--;
01041   }
01042   if (IsFloatInRange(_draw_info.tile_y_start, 1.999f, 2.001f)) { // Is the value approximately equal to 2.0f?
01043     _draw_info.num_draw_rows--;
01044   }
01045 
01046   // TRYING TO GET RID OF PROBLEMS OF DUPLICATED LINES IN MAP
01047   // THIS CODE IS TEMPORAL AND NOT COMPLETELY WORKING
01048 #ifdef __MAP_CHANGE_1__
01049   double y_resolution;
01050   double x_resolution;
01051 
01052   float x2 (_draw_info.tile_x_start);
01053   float y2 (_draw_info.tile_y_start);
01054 
01055 //  if (VideoManager->GetWidth() == 1024 && VideoManager->GetHeight() == 768)
01056   {
01057     VideoManager->GetPixelSize(x_resolution, y_resolution);
01058     x_resolution = abs(x_resolution);
01059     y_resolution = abs(y_resolution);
01060 
01061     _draw_info.tile_x_start = FloorToFloatMultiple (_draw_info.tile_x_start, x_resolution);
01062     _draw_info.tile_y_start = FloorToFloatMultiple (_draw_info.tile_y_start, y_resolution);
01063 
01064     if (x2 - _draw_info.tile_x_start > x_resolution*0.5f)
01065       _draw_info.tile_x_start += x_resolution;
01066     if (y2 - _draw_info.tile_y_start > y_resolution*0.5f)
01067       _draw_info.tile_y_start += y_resolution;
01068   }
01069 #endif
01070 
01071 #if defined(__MAP_CHANGE_1__) && defined(__MAP_CHANGE_2__)
01072 //  if (VideoManager->GetWidth() == 1024 && VideoManager->GetHeight() == 768)
01073   {
01074     _draw_info.left_edge = FloorToFloatMultiple (_draw_info.left_edge, x_resolution);
01075     _draw_info.top_edge = FloorToFloatMultiple (_draw_info.top_edge, y_resolution);
01076 
01077     if (camera_x - HALF_SCREEN_COLS - _draw_info.left_edge > x_resolution*0.5f)
01078       _draw_info.left_edge += x_resolution;
01079     if (camera_y - HALF_SCREEN_ROWS - _draw_info.top_edge > y_resolution*0.5f)
01080       _draw_info.top_edge += y_resolution;
01081 
01082     _draw_info.right_edge = _draw_info.left_edge + 2*SCREEN_COLS;
01083     _draw_info.bottom_edge = _draw_info.top_edge + 2*SCREEN_ROWS;
01084   }
01085 #endif
01086 
01087 
01088 
01089   // Comment this out to print out debugging info about each map frame that is drawn
01090 //  printf("--- MAP DRAW INFO ---\n");
01091 //  printf("Starting row, col: [%d, %d]\n", _draw_info.starting_row, _draw_info.starting_col);
01092 //  printf("# draw rows, cols: [%d, %d]\n", _draw_info.num_draw_rows, _draw_info.num_draw_cols);
01093 //  printf("Camera position:   [%f, %f]\n", camera_x, camera_y);
01094 //  printf("Tile draw start:   [%f, %f]\n", _draw_info.tile_x_start, _draw_info.tile_y_start);
01095 //  printf("Edges (T,D,L,R):   [%f, %f, %f, %f]\n", _draw_info.top_edge, _draw_info.bottom_edge, _draw_info.left_edge, _draw_info.right_edge);
01096 } // void MapMode::_CalculateDrawInfo()
01097 
01098 
01099 // Public draw function called by the main game loop
01100 void MapMode::Draw() {
01101   _CalculateDrawInfo();
01102 
01103   // ---------- (1) Call Lua to determine if any lighting, etc. needs to be done before drawing
01104   // TODO
01105 
01106   // ---------- (2) Draw the lower tile layer
01107   VideoManager->SetDrawFlags(VIDEO_NO_BLEND, 0);
01108   VideoManager->Move(_draw_info.tile_x_start, _draw_info.tile_y_start);
01109   for (uint32 r = static_cast<uint32>(_draw_info.starting_row);
01110       r < static_cast<uint32>(_draw_info.starting_row + _draw_info.num_draw_rows); r++) {
01111     for (uint32 c = static_cast<uint32>(_draw_info.starting_col);
01112         c < static_cast<uint32>(_draw_info.starting_col + _draw_info.num_draw_cols); c++) {
01113       if (_tile_grid[r][c].lower_layer >= 0) { // Draw a tile image if it exists at this location
01114         _tile_images[_tile_grid[r][c].lower_layer]->Draw();
01115       }
01116       VideoManager->MoveRelative(2.0f, 0.0f);
01117     }
01118     VideoManager->MoveRelative(-static_cast<float>(_draw_info.num_draw_cols * 2), 2.0f);
01119   }
01120 
01121   // ---------- (2) Draw the middle tile layer
01122   VideoManager->SetDrawFlags(VIDEO_BLEND, 0);
01123   VideoManager->Move(_draw_info.tile_x_start, _draw_info.tile_y_start);
01124   for (uint32 r = static_cast<uint32>(_draw_info.starting_row);
01125       r < static_cast<uint32>(_draw_info.starting_row + _draw_info.num_draw_rows); r++) {
01126 
01127     for (uint32 c = static_cast<uint32>(_draw_info.starting_col);
01128         c < static_cast<uint32>(_draw_info.starting_col + _draw_info.num_draw_cols); c++) {
01129       if (_tile_grid[r][c].middle_layer >= 0) { // Draw a tile image if it exists at this location
01130         _tile_images[_tile_grid[r][c].middle_layer]->Draw();
01131       }
01132       VideoManager->MoveRelative(2.0f, 0.0f);
01133     }
01134 
01135     VideoManager->MoveRelative(static_cast<float>(_draw_info.num_draw_cols * -2), 2.0f);
01136   }
01137 
01138   // ---------- (3) Draw the ground object layer (first pass)
01139   for (uint32 i = 0; i < _ground_objects.size(); i++) {
01140     if (_ground_objects[i]->draw_on_second_pass == false) {
01141       _ground_objects[i]->Draw();
01142     }
01143   }
01144 
01145   // ---------- (4) Draw the pass object layer
01146   for (uint32 i = 0; i < _pass_objects.size(); i++) {
01147     _pass_objects[i]->Draw();
01148   }
01149 
01150   // ---------- (5) Draw the ground object layer (second pass)
01151   for (uint32 i = 0; i < _ground_objects.size(); i++) {
01152     if (_ground_objects[i]->draw_on_second_pass == true) {
01153       _ground_objects[i]->Draw();
01154     }
01155   }
01156 
01157   // ---------- (6) Draw the upper tile layer
01158   VideoManager->Move(_draw_info.tile_x_start, _draw_info.tile_y_start);
01159   for (uint32 r = static_cast<uint32>(_draw_info.starting_row);
01160       r < static_cast<uint32>(_draw_info.starting_row + _draw_info.num_draw_rows); r++) {
01161     for (uint32 c = static_cast<uint32>(_draw_info.starting_col);
01162         c < static_cast<uint32>(_draw_info.starting_col + _draw_info.num_draw_cols); c++) {
01163       if (_tile_grid[r][c].upper_layer >= 0) { // Draw a tile image if it exists at this location
01164         _tile_images[_tile_grid[r][c].upper_layer]->Draw();
01165       }
01166       VideoManager->MoveRelative(2.0f, 0.0f);
01167     }
01168     VideoManager->MoveRelative(-static_cast<float>(_draw_info.num_draw_cols * 2), 2.0f);
01169   }
01170 
01171   // ---------- (7) Draw the sky object layer
01172   for (uint32 i = 0; i < _sky_objects.size(); i++) {
01173     _sky_objects[i]->Draw();
01174   }
01175 
01176   // ---------- (8) Call Lua to determine if any lighting, etc. needs to be done after drawing
01177   // TODO
01178 
01179   // ---------- (9) Draw the dialogue display if a dialogue is active
01180   if (_map_state == DIALOGUE) {
01181     _dialogue_manager->Draw();
01182   }
01183 
01184   if (_intro_timer.IsFinished() == false) {
01185     uint32 time = _intro_timer.GetTimeExpired();
01186     Color blend(1.0f, 1.0f, 1.0f, 1.0f);
01187     if (time < 2000) { // Fade in
01188       blend.SetAlpha((static_cast<float>(time) / 2000.0f));
01189     }
01190     else if (time > 5000) { // Fade out
01191       blend.SetAlpha(1.0f - static_cast<float>(time - 5000) / 2000.0f);
01192     }
01193     VideoManager->PushState();
01194     VideoManager->SetCoordSys(0.0f, 1024.0f, 768.0f, 0.0f);
01195     VideoManager->SetDrawFlags(VIDEO_X_CENTER, VIDEO_Y_CENTER, 0);
01196     VideoManager->Move(512.0f, 100.0f);
01197     VideoManager->DrawImage(_location_graphic, blend);
01198     VideoManager->MoveRelative(0.0f, -80.0f);
01199     VideoManager->SetTextColor(blend);
01200     VideoManager->DrawText(_map_name);
01201     VideoManager->PopState();
01202   }
01203 } // void MapMode::_Draw()
01204 
01205 
01206 
01207 uint16 MapMode::_GetGeneratedObjectID() {
01208   return ++_lastID;
01209 }
01210 
01211 // ****************************************************************************
01212 // ************************* LUA BINDING FUNCTIONS ****************************
01213 // ****************************************************************************
01214 
01215 void MapMode::_AddGroundObject(private_map::MapObject *obj) {
01216   _ground_objects.push_back(obj);
01217   _all_objects.insert(make_pair(obj->object_id, obj));
01218 }
01219 
01220 
01221 
01222 void MapMode::_AddPassObject(private_map::MapObject *obj) {
01223   _pass_objects.push_back(obj);
01224   _all_objects.insert(make_pair(obj->object_id, obj));
01225 }
01226 
01227 
01228 
01229 void MapMode::_AddSkyObject(private_map::MapObject *obj) {
01230   _sky_objects.push_back(obj);
01231   _all_objects.insert(make_pair(obj->object_id, obj));
01232 }
01233 
01234 void MapMode::_AddZone(private_map::MapZone *zone) {
01235   _zones.push_back(zone);
01236 }
01237 
01238 } // namespace hoa_map

Generated on Fri Jul 6 23:11:17 2007 for Hero of Allacrost by  doxygen 1.5.1