• Main Page
  • Related Pages
  • Classes
  • Files
  • File List
  • File Members

mapview.cc

Go to the documentation of this file.
00001 /*
00002    $Id: mapview.cc,v 1.16 2008/04/22 17:35:03 ksterker Exp $
00003 
00004    Copyright (C) 1999/2000/2001    Alexandre Courbot
00005    Part of the Adonthell Project http://adonthell.linuxgames.com
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License.
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY.
00011 
00012    See the COPYING file for more details.
00013 */
00014 
00015 
00016 /**
00017  * @file   mapview.cc
00018  * @author Alexandre Courbot <alexandrecourbot@linuxgames.com>
00019  * 
00020  * @brief  Defines the mapview class.
00021  * 
00022  * 
00023  */
00024 
00025 
00026 #include "mapview.h"
00027 #include <set>
00028 
00029 mapview::mapview () : da () 
00030 {
00031     drawable::set_length (0);
00032     drawable::set_height (0); 
00033     d_length = d_height = currentsubmap_ = posx_ = posy_ = 0;
00034     m_map = NULL;
00035     offx_ = offy_ = 0;
00036 
00037     schedule_args = NULL; 
00038 }
00039 
00040 mapview::~mapview ()
00041 {
00042     detach_map ();
00043     Py_XDECREF (schedule_args); 
00044 }
00045 
00046 void mapview::attach_map (landmap * m)
00047 {
00048     m_map = m;
00049 
00050     set_pos (0, 0, 0);
00051 }
00052 
00053 void mapview::detach_map ()
00054 {
00055     if (!m_map) return;
00056     
00057     m_map = NULL;
00058 }
00059 
00060 s_int8 mapview::set_pos (u_int16 sm, u_int16 px, u_int16 py, s_int16 ox, s_int16 oy)
00061 {
00062     currentsubmap_ = sm;
00063     mapsquare_area * ms = m_map->submap[sm]; 
00064     
00065     s_int32 tpx = px * MAPSQUARE_SIZE + ox;
00066     s_int32 tpy = py * MAPSQUARE_SIZE + oy;
00067     
00068     if (tpx + length () > ms->area_length () * MAPSQUARE_SIZE)
00069         tpx = ms->area_length () * MAPSQUARE_SIZE - length (); 
00070     if (tpy + height () > ms->area_height () * MAPSQUARE_SIZE)
00071         tpy = ms->area_height () * MAPSQUARE_SIZE - height (); 
00072 
00073     if (tpx < 0) tpx = 0;
00074     if (tpy < 0) tpy = 0; 
00075     
00076     px = tpx / MAPSQUARE_SIZE;
00077     py = tpy / MAPSQUARE_SIZE;
00078 
00079     ox = tpx % MAPSQUARE_SIZE;
00080     oy = tpy % MAPSQUARE_SIZE;
00081     
00082     posx_ = px;
00083     posy_ = py;
00084     offx_ = ox;
00085     offy_ = oy;
00086     
00087     return 0;
00088 }
00089 
00090 s_int8 mapview::center_on (u_int16 sm, u_int16 px, u_int16 py, s_int16 ox, s_int16 oy)
00091 {
00092     s_int32 tpx = px * MAPSQUARE_SIZE + ox - ((length () - MAPSQUARE_SIZE) >> 1); 
00093     s_int32 tpy = py * MAPSQUARE_SIZE + oy - ((height () - MAPSQUARE_SIZE) >> 1); 
00094 
00095     if (tpx < 0) tpx = 0; 
00096     if (tpy < 0) tpy = 0; 
00097     
00098     s_int16 npx = tpx / MAPSQUARE_SIZE; 
00099     s_int16 npy = tpy / MAPSQUARE_SIZE;
00100     
00101     s_int16 nox = tpx % MAPSQUARE_SIZE;
00102     s_int16 noy = tpy % MAPSQUARE_SIZE;
00103 
00104     return set_pos (sm, npx, npy, nox, noy);     
00105 }
00106 
00107 void mapview::scroll_right ()
00108 {
00109     if (!can_scroll_right ())
00110         return;
00111     if (offx_ == MAPSQUARE_SIZE - 1)
00112     {
00113         offx_ = 0;
00114         posx_++;
00115     }
00116     else
00117         offx_++;
00118 }
00119 
00120 void mapview::scroll_left ()
00121 {
00122     if (!can_scroll_left ())
00123         return;
00124     if (offx_ == 0)
00125     {
00126         offx_ = MAPSQUARE_SIZE - 1;
00127         posx_--;
00128     }
00129     else
00130         offx_--;
00131 }
00132 
00133 void mapview::scroll_down ()
00134 {
00135     if (!can_scroll_down ())
00136         return;
00137     if (offy_ == MAPSQUARE_SIZE - 1)
00138     {
00139         offy_ = 0;
00140         posy_++;
00141     }
00142     else
00143         offy_++;
00144 }
00145 
00146 void mapview::scroll_up ()
00147 {
00148     if (!can_scroll_up ())
00149         return;
00150     if (offy_ == 0)
00151     {
00152         offy_ = MAPSQUARE_SIZE - 1;
00153         posy_--;
00154     }
00155     else
00156         offy_--;
00157 }
00158 
00159 void mapview::resize (u_int16 l, u_int16 h)
00160 {
00161     drawable::set_length (l);
00162     drawable::set_height (h); 
00163     d_length = (l / MAPSQUARE_SIZE) + (l % MAPSQUARE_SIZE != 0);
00164     d_height = (h / MAPSQUARE_SIZE) + (h % MAPSQUARE_SIZE != 0);
00165     da.resize (length (), height ());
00166 }
00167 
00168 s_int8 mapview::get_state (igzstream& file)
00169 { 
00170     u_int16 a, b, c, d, sm;
00171     string t;
00172     bool bo; 
00173     
00174     // Read the mapview's dimensions
00175     // Length and height
00176     a << file;
00177     b << file; 
00178     resize (a, b);
00179 
00180     // Currentsubmap
00181     sm << file;
00182     
00183     // Position on map
00184     a << file;
00185     b << file;
00186     c << file;
00187     d << file; 
00188     set_pos (sm, a, b, c, d);
00189 
00190     // Schedule state
00191     PyObject * args = NULL; 
00192     t << file;
00193     bo << file; 
00194     if (bo) args = python::get_tuple (file); 
00195     set_schedule (t, args);      
00196     Py_XDECREF (args); 
00197 
00198     return 0;
00199 }
00200 
00201 s_int8 mapview::put_state (ogzstream& file)
00202 {
00203     u_int16 b;
00204  
00205     // Write the mapview's dimensions
00206     b = length (); 
00207     b >> file;
00208     b = height (); 
00209     b >> file; 
00210     currentsubmap_ >> file; 
00211 
00212     // Position
00213     posx_ >> file;
00214     posy_ >> file;
00215     offx_ >> file;
00216     offy_ >> file; 
00217 
00218     // Write the mapview's schedule state
00219     schedule_file () >> file;
00220     if (schedule_args) 
00221     {
00222         true >> file; 
00223         python::put_tuple (schedule_args, file);
00224     }
00225     else false >> file; 
00226 
00227     return 0;
00228 }
00229 
00230 void mapview::set_schedule (string file, PyObject * args)
00231 {
00232     if (file == "") 
00233     {
00234         schedule.clear ();
00235         Py_XDECREF (schedule_args);
00236         schedule_args = NULL; 
00237     }
00238     else 
00239     {
00240         Py_XINCREF (args);
00241         schedule_args = args;
00242         
00243         u_int16 argssize = args == NULL ? 1 : PyTuple_Size (args) + 1; 
00244         PyObject * theargs;
00245         
00246         theargs = PyTuple_New (argssize);
00247         
00248         // We can pass_instance directly 'cause PyTuple_SetItem steals a
00249         // reference to the result of pass_instance.
00250         PyTuple_SetItem (theargs, 0, python::pass_instance (this, "mapview"));
00251         for (u_int16 i = 1; i < argssize; i++)
00252         {
00253             PyObject * intref = PyTuple_GetItem (args, i - 1);
00254             Py_INCREF (intref); 
00255             PyTuple_SetItem (theargs, i, intref); 
00256         }
00257         schedule.create_instance ("schedules.mapviews." + file, file, theargs);
00258         Py_DECREF (theargs); 
00259     }
00260     schedule_file_ = file; 
00261 }
00262 
00263 bool mapview::update ()
00264 {
00265     schedule.run ();
00266 
00267     return true; 
00268 }
00269 
00270 void mapview::draw (s_int16 x, s_int16 y, const drawing_area * da_opt,
00271                     surface *target) const
00272 {
00273     static u_int16 i, j;
00274     static u_int16 i0, j0, ie, je;
00275     static list <mapsquare_tile>::iterator it;
00276     static list <mapsquare_char>::iterator itc;
00277     static list <mapcharacter *>::iterator itb;
00278     static mapsquare_area *l;
00279     static u_int16 offx, offy; 
00280 
00281     static list <mapsquare_tile> critical_draw;
00282     static list <mapsquare_char> characters_draw;
00283     static list <mapcharacter *> bubbles_draw; 
00284     
00285     if (!m_map)
00286         return;
00287 
00288     static SDL_Rect trect; 
00289     static drawing_area tda;
00290      
00291     da.move (x, y);
00292     if (da_opt) da.assign_drawing_area (da_opt);
00293     
00294     trect = da.setup_rects ();
00295     tda = trect;
00296     
00297     l = m_map->submap[currentsubmap_];
00298     if (!l->area_length () || !l->area_height ())
00299         return;
00300 
00301     i0 = posx_;
00302     j0 = posy_;
00303     ie = i0 + d_length + (offx_ != 0) < l->area_length () ? i0 + d_length + (offx_ !=
00304                                                                     0) : l->area_length ();
00305     je = j0 + d_height + (offy_ != 0) < l->area_height () ? j0 + d_height + (offy_ !=
00306                                                                     0) : l->area_height ();
00307 
00308     offx = l->area_length () * MAPSQUARE_SIZE < length () ?
00309         (length () - l->area_length () * MAPSQUARE_SIZE) >> 1 : 0; 
00310 
00311     offy = l->area_height () * MAPSQUARE_SIZE < height () ?
00312         (height () - l->area_height () * MAPSQUARE_SIZE) >> 1 : 0; 
00313 
00314     x += offx;
00315     y += offy; 
00316     
00317     // 1st horizontal parse to check top overflows
00318     // Top-left corner
00319     for (it = l->area[i0][j0].tiles.begin ();
00320          it != l->area[i0][j0].tiles.end () && *(it->base_tile) < *it; it++)
00321         if (it->x > it->base_tile->x && it->y > it->base_tile->y)
00322             critical_draw.push_back (*(it->base_tile));
00323 
00324     for (itc = l->area[i0][j0].mapchars.begin ();
00325          itc != l->area[i0][j0].mapchars.end (); itc++)
00326         if (itc->x > itc->base_tile->x && itc->y > itc->base_tile->y)
00327             characters_draw.push_back (*itc);
00328     
00329     // Top line
00330     for (i = i0; i < ie && i < l->area_length (); i++)
00331     {
00332         for (it = l->area[i][j0].tiles.begin ();
00333              it != l->area[i][j0].tiles.end (); it++)
00334             if (it->x == it->base_tile->x && it->y > it->base_tile->y)
00335                 critical_draw.push_back (*(it->base_tile));
00336 
00337         for (itc = l->area[i][j0].mapchars.begin ();
00338              itc != l->area[i][j0].mapchars.end (); itc++)
00339             if (itc->x == itc->base_tile->x && itc->y > itc->base_tile->y)
00340                 characters_draw.push_back (*itc);
00341     }
00342 
00343     // Top right corner
00344     for (it = l->area[ie - 1][j0].tiles.begin ();
00345          it != l->area[ie - 1][j0].tiles.end (); it++)
00346         if (it->x < it->base_tile->x && it->y > it->base_tile->y)
00347             critical_draw.push_back (*(it->base_tile));
00348 
00349     for (itc = l->area[ie - 1][j0].mapchars.begin ();
00350          itc != l->area[ie - 1][j0].mapchars.end (); itc++)
00351         if (itc->x < itc->base_tile->x && itc->y > itc->base_tile->y)
00352             characters_draw.push_back (*itc);
00353 
00354     // Drawing characters and top overflowing gfx
00355     critical_draw.sort ();
00356     characters_draw.sort ();
00357 
00358     it = critical_draw.begin ();
00359     itc = characters_draw.begin ();
00360     while (itc != characters_draw.end () || it != critical_draw.end ())
00361     {
00362         if (itc != characters_draw.end ())
00363         {
00364             if (it != critical_draw.end ())
00365             {
00366                 if (it->base_tile->y <= itc->base_tile->y)
00367                 {
00368                     draw_tile (x, y, &tda, target, it);
00369                     it++;
00370                 }
00371                 else
00372                 {
00373                     draw_mapchar (x, y, &tda, target, itc);
00374                     if (itc->mchar->is_speaking ())
00375                             bubbles_draw.push_back (itc->mchar); 
00376                     itc++;
00377                 }
00378             }
00379             else
00380             {
00381                 draw_mapchar (x, y, &tda, target, itc); 
00382                 if (itc->mchar->is_speaking ()) 
00383                         bubbles_draw.push_back (itc->mchar); 
00384                 itc++;
00385             }
00386         }
00387         else
00388         {
00389             draw_tile (x, y, &tda, target, it);
00390             it++;
00391         }
00392     }
00393     critical_draw.clear ();
00394     characters_draw.clear ();
00395 
00396     // Now drawing objects without any top or bottom overflow
00397     for (j = j0; j < je; j++)
00398     {
00399         // Left overflow
00400         for (it = l->area[i0][j].tiles.begin ();
00401              it != l->area[i0][j].tiles.end () && *(it->base_tile) <= *it;
00402              it++)
00403             if (it->y == it->base_tile->y && it->x > it->base_tile->x)
00404                 draw_tile (x, y, &tda, target, it); 
00405 
00406         for (itc = l->area[i0][j].mapchars.begin ();
00407              itc != l->area[i0][j].mapchars.end (); itc++)
00408             if (itc->y == itc->base_tile->y && itc->x > itc->base_tile->x)
00409                 characters_draw.push_back (*itc);
00410 
00411         // Objects which base tile is visible on the map view
00412         for (i = i0; i < ie; i++)
00413         {
00414             for (it = l->area[i][j].base_begin;
00415                  it != l->area[i][j].tiles.end () && *(it->base_tile) < *it;
00416                  it++);
00417             for (; it != l->area[i][j].tiles.end () && *(it->base_tile) == *it;
00418                  it++)
00419                 draw_tile (x, y, &tda, target, it);
00420                 
00421             for (itc = l->area[i][j].mapchars.begin ();
00422                  itc != l->area[i][j].mapchars.end (); itc++)
00423                 if (*itc == *(itc->base_tile) &&
00424                     itc->x == itc->mchar->posx () &&
00425                     itc->y == itc->mchar->posy ())
00426                     characters_draw.push_back (*itc);
00427         }
00428         
00429         // Right overflow
00430         for (it = l->area[ie - 1][j].tiles.begin ();
00431              it != l->area[ie - 1][j].tiles.end (); it++)
00432             if (it->y == it->base_tile->y && it->x < it->base_tile->x)
00433                 draw_tile (x, y, &tda, target, it); 
00434 
00435         for (itc = l->area[ie - 1][j].mapchars.begin ();
00436              itc != l->area[ie - 1][j].mapchars.end (); itc++)
00437             if (itc->y == itc->base_tile->y && itc->x < itc->base_tile->x)
00438                 characters_draw.push_back (*itc);
00439 
00440         // Drawing characters
00441         for (itc = characters_draw.begin (); itc != characters_draw.end ();
00442              itc++)
00443           {
00444             draw_mapchar (x, y, &tda, target, itc);
00445             if (itc->mchar->is_speaking ()) 
00446                     bubbles_draw.push_back (itc->mchar); 
00447           }
00448         characters_draw.clear ();
00449     }
00450 
00451     // Last horizontal parse to check bottom overflows
00452     // Bottom left overflow
00453     if (!l->area[i0][je - 1].tiles.empty ())
00454         for (it = --l->area[i0][je - 1].tiles.end ();
00455              it->y < it->base_tile->y; it--)
00456         {
00457             if (it->x > it->base_tile->x && it->y < it->base_tile->y)
00458                 critical_draw.push_front (*(it->base_tile));
00459             if (it == l->area[i0][je - 1].tiles.begin ())
00460                 break;
00461         }
00462 
00463     for (itc = l->area[i0][je - 1].mapchars.begin ();
00464          itc != l->area[i0][je - 1].mapchars.end (); itc++)
00465         if (itc->x > itc->base_tile->x && itc->y < itc->base_tile->y)
00466             characters_draw.push_back (*itc);
00467 
00468     // Bottom line
00469     for (i = i0; i < ie && i < l->area_length (); i++)
00470     {
00471         if (!l->area[i][je - 1].tiles.empty ())
00472             for (it = --l->area[i][je - 1].tiles.end ();
00473                  it->y < it->base_tile->y; it--)
00474             {
00475                 if (it->x == it->base_tile->x && it->y < it->base_tile->y)
00476                     critical_draw.push_front (*(it->base_tile));
00477                 if (it == l->area[i][je - 1].tiles.begin ())
00478                     break;
00479             }
00480 
00481         for (itc = l->area[i][je - 1].mapchars.begin ();
00482              itc != l->area[i][je - 1].mapchars.end (); itc++)
00483         {
00484             if (itc->x == itc->base_tile->x && itc->y < itc->base_tile->y)
00485             {
00486                 characters_draw.push_back (*itc);
00487             }
00488         }
00489     }
00490 
00491     // Bottom right corner
00492     if (!l->area[ie - 1][je - 1].tiles.empty ())
00493         for (it = --l->area[ie - 1][je - 1].tiles.end ();
00494              it->y < it->base_tile->y; it--)
00495         {
00496             if (it->x < it->base_tile->x && it->y < it->base_tile->y)
00497                 critical_draw.push_front (*(it->base_tile));
00498             if (it == l->area[ie - 1][je - 1].tiles.begin ())
00499                 break;
00500         }
00501 
00502     for (itc = l->area[ie - 1][je - 1].mapchars.begin ();
00503          itc != l->area[ie - 1][je - 1].mapchars.end (); itc++)
00504         if (itc->x < itc->base_tile->x && itc->y < itc->base_tile->y)
00505             characters_draw.push_back (*itc);
00506 
00507 
00508     // Drawing characters and bottom overflowing gfx
00509     critical_draw.sort ();
00510     characters_draw.sort ();
00511 
00512     it = critical_draw.begin ();
00513     itc = characters_draw.begin ();
00514     while (itc != characters_draw.end () || it != critical_draw.end ())
00515     {
00516         if (itc != characters_draw.end ())
00517         {
00518             if (it != critical_draw.end ())
00519             {
00520                 if (it->base_tile->y <= itc->base_tile->y)
00521                 {
00522                     draw_tile (x, y, &tda, target, it);
00523                     it++;
00524                 }
00525                 else
00526                 {
00527                     draw_mapchar (x, y, &tda, target, itc); 
00528                     if (itc->mchar->is_speaking ())
00529                             bubbles_draw.push_back (itc->mchar); 
00530                     itc++;
00531                 }
00532             }
00533             else
00534             {
00535                 draw_mapchar (x, y, &tda, target, itc); 
00536                 if (itc->mchar->is_speaking ()) 
00537                         bubbles_draw.push_back (itc->mchar); 
00538                 itc++;
00539             }
00540         }
00541         else
00542         {
00543             draw_tile (x, y, &tda, target, it);
00544             it++;
00545         }
00546     }
00547 
00548     for (itb = bubbles_draw.begin (); itb != bubbles_draw.end (); itb++)
00549         draw_bubble (x, y, &tda, target, itb); 
00550  
00551     critical_draw.clear ();
00552     characters_draw.clear ();
00553     bubbles_draw.clear (); 
00554     
00555     if (da_opt) da.detach_drawing_area ();
00556 }
00557 
00558 
00559 
00560 // Private methods
00561 
00562 
00563 void mapview::draw_tile (s_int16 x, s_int16 y, const drawing_area * da_opt,
00564                          surface * target, list<mapsquare_tile>::iterator it) const
00565 { 
00566     it->mapobj->draw_from_base
00567         ((it->base_tile->x - posx_) * MAPSQUARE_SIZE - offx_ + x,
00568          (it->base_tile->y - posy_) * MAPSQUARE_SIZE - offy_ + y,
00569          da_opt, target);
00570 }
00571 
00572 void mapview::draw_mapchar (s_int16 x, s_int16 y, const drawing_area * da_opt,
00573                             surface * target, list<mapsquare_char>::iterator itc) const
00574 { 
00575     u_int16 xdraw =
00576         ((itc->mchar->posx () - posx_ - itc->mchar->base_x ()) * MAPSQUARE_SIZE)
00577         + itc->mchar->offx () - offx_ + x;
00578     
00579     u_int16 ydraw =
00580         ((itc->mchar->posy () - posy_ - itc->mchar->base_y ()) * MAPSQUARE_SIZE)
00581         + itc->mchar->offy () - offy_ + y;
00582     
00583     itc->mchar->draw (xdraw, ydraw, da_opt, target);
00584 }
00585 
00586 void mapview::draw_bubble (s_int16 x, s_int16 y, const drawing_area * da_opt,
00587                            surface * target, list<mapcharacter *>::iterator itc) const
00588 { 
00589     u_int16 xdraw =
00590         (((*itc)->posx () - posx_ - (*itc)->base_x ()) * MAPSQUARE_SIZE)
00591         + (*itc)->offx () - offx_ + x;
00592     
00593     u_int16 ydraw =
00594         (((*itc)->posy () - posy_ - (*itc)->base_y ()) * MAPSQUARE_SIZE)
00595         + (*itc)->offy () - offy_ + y;
00596     
00597     (*itc)->draw_bubble (xdraw, ydraw, da_opt, target);
00598 }

Generated on Mon Sep 12 2011 for Adonthell by  doxygen 1.7.1