Adonthell 0.4
|
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 }