Adonthell  0.4
mapview.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 1999/2000/2001 Alexandre Courbot
3  Part of the Adonthell Project <http://adonthell.nongnu.org>
4 
5  Adonthell is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9 
10  Adonthell is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with Adonthell. If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 
20 /**
21  * @file mapview.cc
22  * @author Alexandre Courbot <alexandrecourbot@linuxgames.com>
23  *
24  * @brief Defines the mapview class.
25  *
26  *
27  */
28 
29 
30 #include "mapview.h"
31 #include <set>
32 
33 mapview::mapview () : da ()
34 {
37  d_length = d_height = currentsubmap_ = posx_ = posy_ = 0;
38  m_map = NULL;
39  offx_ = offy_ = 0;
40 
41  schedule_args = NULL;
42 }
43 
45 {
46  detach_map ();
47  Py_XDECREF (schedule_args);
48 }
49 
51 {
52  m_map = m;
53 
54  set_pos (0, 0, 0);
55 }
56 
58 {
59  if (!m_map) return;
60 
61  m_map = NULL;
62 }
63 
65 {
66  currentsubmap_ = sm;
67  mapsquare_area * ms = m_map->submap[sm];
68 
69  s_int32 tpx = px * MAPSQUARE_SIZE + ox;
70  s_int32 tpy = py * MAPSQUARE_SIZE + oy;
71 
72  if (tpx + length () > ms->area_length () * MAPSQUARE_SIZE)
73  tpx = ms->area_length () * MAPSQUARE_SIZE - length ();
74  if (tpy + height () > ms->area_height () * MAPSQUARE_SIZE)
75  tpy = ms->area_height () * MAPSQUARE_SIZE - height ();
76 
77  if (tpx < 0) tpx = 0;
78  if (tpy < 0) tpy = 0;
79 
80  px = tpx / MAPSQUARE_SIZE;
81  py = tpy / MAPSQUARE_SIZE;
82 
83  ox = tpx % MAPSQUARE_SIZE;
84  oy = tpy % MAPSQUARE_SIZE;
85 
86  posx_ = px;
87  posy_ = py;
88  offx_ = ox;
89  offy_ = oy;
90 
91  return 0;
92 }
93 
95 {
96  s_int32 tpx = px * MAPSQUARE_SIZE + ox - ((length () - MAPSQUARE_SIZE) >> 1);
97  s_int32 tpy = py * MAPSQUARE_SIZE + oy - ((height () - MAPSQUARE_SIZE) >> 1);
98 
99  if (tpx < 0) tpx = 0;
100  if (tpy < 0) tpy = 0;
101 
102  s_int16 npx = tpx / MAPSQUARE_SIZE;
103  s_int16 npy = tpy / MAPSQUARE_SIZE;
104 
105  s_int16 nox = tpx % MAPSQUARE_SIZE;
106  s_int16 noy = tpy % MAPSQUARE_SIZE;
107 
108  return set_pos (sm, npx, npy, nox, noy);
109 }
110 
112 {
113  if (!can_scroll_right ())
114  return;
115  if (offx_ == MAPSQUARE_SIZE - 1)
116  {
117  offx_ = 0;
118  posx_++;
119  }
120  else
121  offx_++;
122 }
123 
125 {
126  if (!can_scroll_left ())
127  return;
128  if (offx_ == 0)
129  {
130  offx_ = MAPSQUARE_SIZE - 1;
131  posx_--;
132  }
133  else
134  offx_--;
135 }
136 
138 {
139  if (!can_scroll_down ())
140  return;
141  if (offy_ == MAPSQUARE_SIZE - 1)
142  {
143  offy_ = 0;
144  posy_++;
145  }
146  else
147  offy_++;
148 }
149 
151 {
152  if (!can_scroll_up ())
153  return;
154  if (offy_ == 0)
155  {
156  offy_ = MAPSQUARE_SIZE - 1;
157  posy_--;
158  }
159  else
160  offy_--;
161 }
162 
164 {
167  d_length = (l / MAPSQUARE_SIZE) + (l % MAPSQUARE_SIZE != 0);
168  d_height = (h / MAPSQUARE_SIZE) + (h % MAPSQUARE_SIZE != 0);
169  da.resize (length (), height ());
170 }
171 
173 {
174  u_int16 a, b, c, d, sm;
175  string t;
176  bool bo;
177 
178  // Read the mapview's dimensions
179  // Length and height
180  a << file;
181  b << file;
182  resize (a, b);
183 
184  // Currentsubmap
185  sm << file;
186 
187  // Position on map
188  a << file;
189  b << file;
190  c << file;
191  d << file;
192  set_pos (sm, a, b, c, d);
193 
194  // Schedule state
195  PyObject * args = NULL;
196  t << file;
197  bo << file;
198  if (bo) args = python::get_tuple (file);
199  set_schedule (t, args);
200  Py_XDECREF (args);
201 
202  return 0;
203 }
204 
206 {
207  u_int16 b;
208 
209  // Write the mapview's dimensions
210  b = length ();
211  b >> file;
212  b = height ();
213  b >> file;
214  currentsubmap_ >> file;
215 
216  // Position
217  posx_ >> file;
218  posy_ >> file;
219  offx_ >> file;
220  offy_ >> file;
221 
222  // Write the mapview's schedule state
223  schedule_file () >> file;
224  if (schedule_args)
225  {
226  true >> file;
227  python::put_tuple (schedule_args, file);
228  }
229  else false >> file;
230 
231  return 0;
232 }
233 
234 void mapview::set_schedule (string file, PyObject * args)
235 {
236  if (file == "")
237  {
238  schedule.clear ();
239  Py_XDECREF (schedule_args);
240  schedule_args = NULL;
241  }
242  else
243  {
244  Py_XINCREF (args);
245  schedule_args = args;
246 
247  u_int16 argssize = args == NULL ? 1 : PyTuple_Size (args) + 1;
248  PyObject * theargs;
249 
250  theargs = PyTuple_New (argssize);
251 
252  // We can pass_instance directly 'cause PyTuple_SetItem steals a
253  // reference to the result of pass_instance.
254  PyTuple_SetItem (theargs, 0, python::pass_instance (this, "mapview"));
255  for (u_int16 i = 1; i < argssize; i++)
256  {
257  PyObject * intref = PyTuple_GetItem (args, i - 1);
258  Py_INCREF (intref);
259  PyTuple_SetItem (theargs, i, intref);
260  }
261  schedule.create_instance ("schedules.mapviews." + file, file, theargs);
262  Py_DECREF (theargs);
263  }
264  schedule_file_ = file;
265 }
266 
268 {
269  schedule.run ();
270 
271  return true;
272 }
273 
274 void mapview::draw (s_int16 x, s_int16 y, const drawing_area * da_opt,
275  surface *target) const
276 {
277  static u_int16 i, j;
278  static u_int16 i0, j0, ie, je;
279  static list <mapsquare_tile>::iterator it;
280  static list <mapsquare_char>::iterator itc;
281  static list <mapcharacter *>::iterator itb;
282  static mapsquare_area *l;
283  static u_int16 offx, offy;
284 
285  static list <mapsquare_tile> critical_draw;
286  static list <mapsquare_char> characters_draw;
287  static list <mapcharacter *> bubbles_draw;
288 
289  if (!m_map)
290  return;
291 
292  static SDL_Rect trect;
293  static drawing_area tda;
294 
295  da.move (x, y);
296  if (da_opt) da.assign_drawing_area (da_opt);
297 
298  trect = da.setup_rects ();
299  tda = trect;
300 
301  l = m_map->submap[currentsubmap_];
302  if (!l->area_length () || !l->area_height ())
303  return;
304 
305  i0 = posx_;
306  j0 = posy_;
307  ie = i0 + d_length + (offx_ != 0) < l->area_length () ? i0 + d_length + (offx_ !=
308  0) : l->area_length ();
309  je = j0 + d_height + (offy_ != 0) < l->area_height () ? j0 + d_height + (offy_ !=
310  0) : l->area_height ();
311 
312  offx = l->area_length () * MAPSQUARE_SIZE < length () ?
313  (length () - l->area_length () * MAPSQUARE_SIZE) >> 1 : 0;
314 
315  offy = l->area_height () * MAPSQUARE_SIZE < height () ?
316  (height () - l->area_height () * MAPSQUARE_SIZE) >> 1 : 0;
317 
318  x += offx;
319  y += offy;
320 
321  // 1st horizontal parse to check top overflows
322  // Top-left corner
323  for (it = l->area[i0][j0].tiles.begin ();
324  it != l->area[i0][j0].tiles.end () && *(it->base_tile) < *it; it++)
325  if (it->x > it->base_tile->x && it->y > it->base_tile->y)
326  critical_draw.push_back (*(it->base_tile));
327 
328  for (itc = l->area[i0][j0].mapchars.begin ();
329  itc != l->area[i0][j0].mapchars.end (); itc++)
330  if (itc->x > itc->base_tile->x && itc->y > itc->base_tile->y)
331  characters_draw.push_back (*itc);
332 
333  // Top line
334  for (i = i0; i < ie && i < l->area_length (); i++)
335  {
336  for (it = l->area[i][j0].tiles.begin ();
337  it != l->area[i][j0].tiles.end (); it++)
338  if (it->x == it->base_tile->x && it->y > it->base_tile->y)
339  critical_draw.push_back (*(it->base_tile));
340 
341  for (itc = l->area[i][j0].mapchars.begin ();
342  itc != l->area[i][j0].mapchars.end (); itc++)
343  if (itc->x == itc->base_tile->x && itc->y > itc->base_tile->y)
344  characters_draw.push_back (*itc);
345  }
346 
347  // Top right corner
348  for (it = l->area[ie - 1][j0].tiles.begin ();
349  it != l->area[ie - 1][j0].tiles.end (); it++)
350  if (it->x < it->base_tile->x && it->y > it->base_tile->y)
351  critical_draw.push_back (*(it->base_tile));
352 
353  for (itc = l->area[ie - 1][j0].mapchars.begin ();
354  itc != l->area[ie - 1][j0].mapchars.end (); itc++)
355  if (itc->x < itc->base_tile->x && itc->y > itc->base_tile->y)
356  characters_draw.push_back (*itc);
357 
358  // Drawing characters and top overflowing gfx
359  critical_draw.sort ();
360  characters_draw.sort ();
361 
362  it = critical_draw.begin ();
363  itc = characters_draw.begin ();
364  while (itc != characters_draw.end () || it != critical_draw.end ())
365  {
366  if (itc != characters_draw.end ())
367  {
368  if (it != critical_draw.end ())
369  {
370  if (it->base_tile->y <= itc->base_tile->y)
371  {
372  draw_tile (x, y, &tda, target, it);
373  it++;
374  }
375  else
376  {
377  draw_mapchar (x, y, &tda, target, itc);
378  if (itc->mchar->is_speaking ())
379  bubbles_draw.push_back (itc->mchar);
380  itc++;
381  }
382  }
383  else
384  {
385  draw_mapchar (x, y, &tda, target, itc);
386  if (itc->mchar->is_speaking ())
387  bubbles_draw.push_back (itc->mchar);
388  itc++;
389  }
390  }
391  else
392  {
393  draw_tile (x, y, &tda, target, it);
394  it++;
395  }
396  }
397  critical_draw.clear ();
398  characters_draw.clear ();
399 
400  // Now drawing objects without any top or bottom overflow
401  for (j = j0; j < je; j++)
402  {
403  // Left overflow
404  for (it = l->area[i0][j].tiles.begin ();
405  it != l->area[i0][j].tiles.end () && *(it->base_tile) <= *it;
406  it++)
407  if (it->y == it->base_tile->y && it->x > it->base_tile->x)
408  draw_tile (x, y, &tda, target, it);
409 
410  for (itc = l->area[i0][j].mapchars.begin ();
411  itc != l->area[i0][j].mapchars.end (); itc++)
412  if (itc->y == itc->base_tile->y && itc->x > itc->base_tile->x)
413  characters_draw.push_back (*itc);
414 
415  // Objects which base tile is visible on the map view
416  for (i = i0; i < ie; i++)
417  {
418  for (it = l->area[i][j].base_begin;
419  it != l->area[i][j].tiles.end () && *(it->base_tile) < *it;
420  it++);
421  for (; it != l->area[i][j].tiles.end () && *(it->base_tile) == *it;
422  it++)
423  draw_tile (x, y, &tda, target, it);
424 
425  for (itc = l->area[i][j].mapchars.begin ();
426  itc != l->area[i][j].mapchars.end (); itc++)
427  if (*itc == *(itc->base_tile) &&
428  itc->x == itc->mchar->posx () &&
429  itc->y == itc->mchar->posy ())
430  characters_draw.push_back (*itc);
431  }
432 
433  // Right overflow
434  for (it = l->area[ie - 1][j].tiles.begin ();
435  it != l->area[ie - 1][j].tiles.end (); it++)
436  if (it->y == it->base_tile->y && it->x < it->base_tile->x)
437  draw_tile (x, y, &tda, target, it);
438 
439  for (itc = l->area[ie - 1][j].mapchars.begin ();
440  itc != l->area[ie - 1][j].mapchars.end (); itc++)
441  if (itc->y == itc->base_tile->y && itc->x < itc->base_tile->x)
442  characters_draw.push_back (*itc);
443 
444  // Drawing characters
445  for (itc = characters_draw.begin (); itc != characters_draw.end ();
446  itc++)
447  {
448  draw_mapchar (x, y, &tda, target, itc);
449  if (itc->mchar->is_speaking ())
450  bubbles_draw.push_back (itc->mchar);
451  }
452  characters_draw.clear ();
453  }
454 
455  // Last horizontal parse to check bottom overflows
456  // Bottom left overflow
457  if (!l->area[i0][je - 1].tiles.empty ())
458  for (it = --l->area[i0][je - 1].tiles.end ();
459  it->y < it->base_tile->y; it--)
460  {
461  if (it->x > it->base_tile->x && it->y < it->base_tile->y)
462  critical_draw.push_front (*(it->base_tile));
463  if (it == l->area[i0][je - 1].tiles.begin ())
464  break;
465  }
466 
467  for (itc = l->area[i0][je - 1].mapchars.begin ();
468  itc != l->area[i0][je - 1].mapchars.end (); itc++)
469  if (itc->x > itc->base_tile->x && itc->y < itc->base_tile->y)
470  characters_draw.push_back (*itc);
471 
472  // Bottom line
473  for (i = i0; i < ie && i < l->area_length (); i++)
474  {
475  if (!l->area[i][je - 1].tiles.empty ())
476  for (it = --l->area[i][je - 1].tiles.end ();
477  it->y < it->base_tile->y; it--)
478  {
479  if (it->x == it->base_tile->x && it->y < it->base_tile->y)
480  critical_draw.push_front (*(it->base_tile));
481  if (it == l->area[i][je - 1].tiles.begin ())
482  break;
483  }
484 
485  for (itc = l->area[i][je - 1].mapchars.begin ();
486  itc != l->area[i][je - 1].mapchars.end (); itc++)
487  {
488  if (itc->x == itc->base_tile->x && itc->y < itc->base_tile->y)
489  {
490  characters_draw.push_back (*itc);
491  }
492  }
493  }
494 
495  // Bottom right corner
496  if (!l->area[ie - 1][je - 1].tiles.empty ())
497  for (it = --l->area[ie - 1][je - 1].tiles.end ();
498  it->y < it->base_tile->y; it--)
499  {
500  if (it->x < it->base_tile->x && it->y < it->base_tile->y)
501  critical_draw.push_front (*(it->base_tile));
502  if (it == l->area[ie - 1][je - 1].tiles.begin ())
503  break;
504  }
505 
506  for (itc = l->area[ie - 1][je - 1].mapchars.begin ();
507  itc != l->area[ie - 1][je - 1].mapchars.end (); itc++)
508  if (itc->x < itc->base_tile->x && itc->y < itc->base_tile->y)
509  characters_draw.push_back (*itc);
510 
511 
512  // Drawing characters and bottom overflowing gfx
513  critical_draw.sort ();
514  characters_draw.sort ();
515 
516  it = critical_draw.begin ();
517  itc = characters_draw.begin ();
518  while (itc != characters_draw.end () || it != critical_draw.end ())
519  {
520  if (itc != characters_draw.end ())
521  {
522  if (it != critical_draw.end ())
523  {
524  if (it->base_tile->y <= itc->base_tile->y)
525  {
526  draw_tile (x, y, &tda, target, it);
527  it++;
528  }
529  else
530  {
531  draw_mapchar (x, y, &tda, target, itc);
532  if (itc->mchar->is_speaking ())
533  bubbles_draw.push_back (itc->mchar);
534  itc++;
535  }
536  }
537  else
538  {
539  draw_mapchar (x, y, &tda, target, itc);
540  if (itc->mchar->is_speaking ())
541  bubbles_draw.push_back (itc->mchar);
542  itc++;
543  }
544  }
545  else
546  {
547  draw_tile (x, y, &tda, target, it);
548  it++;
549  }
550  }
551 
552  for (itb = bubbles_draw.begin (); itb != bubbles_draw.end (); itb++)
553  draw_bubble (x, y, &tda, target, itb);
554 
555  critical_draw.clear ();
556  characters_draw.clear ();
557  bubbles_draw.clear ();
558 
559  if (da_opt) da.detach_drawing_area ();
560 }
561 
562 
563 
564 // Private methods
565 
566 
567 void mapview::draw_tile (s_int16 x, s_int16 y, const drawing_area * da_opt,
568  surface * target, list<mapsquare_tile>::iterator it) const
569 {
570  it->mapobj->draw_from_base
571  ((it->base_tile->x - posx_) * MAPSQUARE_SIZE - offx_ + x,
572  (it->base_tile->y - posy_) * MAPSQUARE_SIZE - offy_ + y,
573  da_opt, target);
574 }
575 
576 void mapview::draw_mapchar (s_int16 x, s_int16 y, const drawing_area * da_opt,
577  surface * target, list<mapsquare_char>::iterator itc) const
578 {
579  u_int16 xdraw =
580  ((itc->mchar->posx () - posx_ - itc->mchar->base_x ()) * MAPSQUARE_SIZE)
581  + itc->mchar->offx () - offx_ + x;
582 
583  u_int16 ydraw =
584  ((itc->mchar->posy () - posy_ - itc->mchar->base_y ()) * MAPSQUARE_SIZE)
585  + itc->mchar->offy () - offy_ + y;
586 
587  itc->mchar->draw (xdraw, ydraw, da_opt, target);
588 }
589 
590 void mapview::draw_bubble (s_int16 x, s_int16 y, const drawing_area * da_opt,
591  surface * target, list<mapcharacter *>::iterator itc) const
592 {
593  u_int16 xdraw =
594  (((*itc)->posx () - posx_ - (*itc)->base_x ()) * MAPSQUARE_SIZE)
595  + (*itc)->offx () - offx_ + x;
596 
597  u_int16 ydraw =
598  (((*itc)->posy () - posy_ - (*itc)->base_y ()) * MAPSQUARE_SIZE)
599  + (*itc)->offy () - offy_ + y;
600 
601  (*itc)->draw_bubble (xdraw, ydraw, da_opt, target);
602 }
Class to write data from a Gzip compressed file.
Definition: fileops.h:227
void set_length(u_int16 l)
Sets the length of the drawable.
Definition: drawable.h:129
#define s_int32
32 bits long signed integer
Definition: types.h:50
u_int16 length() const
Returns the length of the drawable.
Definition: drawable.h:80
Class to read data from a Gzip compressed file.
Definition: fileops.h:135
void clear()
Resets the script to it&#39;s post-constructor state.
Definition: py_object.cc:46
s_int8 get_state(igzstream &file)
State saving/loading.
Definition: mapview.cc:172
bool can_scroll_down()
Returns whether it is possible to scroll to down.
Definition: mapview.h:243
bool can_scroll_up()
Returns whether it is possible to scroll to up.
Definition: mapview.h:231
bool update()
Updates the mapview&#39;s state and launchs his schedule.
Definition: mapview.cc:267
#define u_int16
16 bits long unsigned integer
Definition: types.h:38
void detach_drawing_area()
Detach (if needed) the drawing_area which was attached to this one.
Definition: drawing_area.h:150
void set_height(u_int16 h)
Sets the height of the drawable.
Definition: drawable.h:139
u_int16 area_height() const
Returns the height of the area.
Definition: mapsquare.h:416
Class where drawables can actually be drawn to.
Definition: surface.h:85
void resize(u_int16 nl, u_int16 nh)
Resize the drawing_area.
Definition: drawing_area.h:120
static void put_tuple(PyObject *tuple, ogzstream &file)
Save a Python tuple into a file.
string schedule_file()
Returns the name of the mapview&#39;s current schedule.
Definition: mapview.h:331
void detach_map()
Stops displaying a map.
Definition: mapview.cc:57
void assign_drawing_area(const drawing_area *da)
Assign a drawing_area to this drawing_area.
Definition: drawing_area.h:131
void scroll_left()
Scrolls 1 pixel to left, if possible.
Definition: mapview.cc:124
u_int16 area_length() const
Returns the length of the area.
Definition: mapsquare.h:405
void scroll_down()
Scrolls 1 pixel to down, if possible.
Definition: mapview.cc:137
void scroll_up()
Scrolls 1 pixel to up, if possible.
Definition: mapview.cc:150
bool can_scroll_right()
Basic movment.
Definition: mapview.h:206
bool create_instance(string file, string classname, PyObject *args=NULL)
Creates an instance of a Python class.
Definition: py_object.cc:57
SDL_Rect setup_rects() const
Gets the real parameters of this drawing_area.
Definition: drawing_area.cc:52
static PyObject * get_tuple(igzstream &file)
Loads a Python tuple previously saved with put_tuple ().
void run(PyObject *args=NULL)
Calls the run () method of this object.
Definition: py_object.h:125
Declares the mapview class.
Implements "drawing zones" for drawing operations.
Definition: drawing_area.h:54
void scroll_right()
Scrolls 1 pixel to right, if possible.
Definition: mapview.cc:111
u_int16 offy() const
Returns the Y offset of the mapview.
Definition: mapview.h:185
static PyObject * pass_instance(void *instance, const char *class_name)
Magic function that makes any C object available to Python!
u_int16 height() const
Returns the height of the drawable.
Definition: drawable.h:91
#define s_int16
16 bits long signed integer
Definition: types.h:47
Map where the world takes place.
Definition: landmap.h:56
void draw(s_int16 x, s_int16 y, const drawing_area *da_opt=NULL, surface *target=NULL) const
Draw the object on the screen.
Definition: mapview.cc:274
void set_schedule(string file, PyObject *args=NULL)
Assign a schedule to the mapview.
Definition: mapview.cc:234
const u_int16 MAPSQUARE_SIZE
Size of a mapsquare (in pixels).
bool can_scroll_left()
Returns whether it is possible to scroll to left.
Definition: mapview.h:219
void resize(u_int16 l, u_int16 h)
Resize the mapview.
Definition: mapview.cc:163
s_int8 set_pos(u_int16 sm, u_int16 x, u_int16 y, s_int16 ox=0, s_int16 oy=0)
Position settings.
Definition: mapview.cc:64
void move(s_int16 nx, s_int16 ny)
Move the drawing_area.
Definition: drawing_area.h:110
void attach_map(landmap *m)
Attach/Detach a map.
Definition: mapview.cc:50
mapview()
Default constructor.
Definition: mapview.cc:33
~mapview()
Destructor.
Definition: mapview.cc:44
s_int8 center_on(u_int16 sm, u_int16 x, u_int16 y, s_int16 ox=0, s_int16 oy=0)
Sets the position of the center of the mapview on the map.
Definition: mapview.cc:94
#define s_int8
8 bits long signed integer
Definition: types.h:44
s_int8 put_state(ogzstream &file)
Saves the mapview&#39;s state into an opened file.
Definition: mapview.cc:205
u_int16 offx() const
Returns the X offset of the mapview.
Definition: mapview.h:174
Area of mapsquares, for use with landmap.
Definition: mapsquare.h:372