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