Adonthell  0.4
mapcharacter.cc
Go to the documentation of this file.
00001 /*
00002    $Id: mapcharacter.cc,v 1.49 2003/02/17 19:31:21 ksterker Exp $
00003 
00004    Copyright (C) 1999/2000/2001/2002 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  * @file mapcharacter.cc
00017  *
00018  * @author Alexandre Courbot <alexandrecourbot@linuxgames.com>
00019  * @brief Defines the mapcharacter class.
00020  */
00021  
00022 #include "mapcharacter.h"
00023 #include "map_event.h"
00024 #include "time_event.h"
00025 #include "event_handler.h"
00026 #include "landmap.h"
00027 #include "win_manager.h"
00028 
00029 using namespace std; 
00030 
00031 
00032 // Public methods
00033 mapcharacter::mapcharacter () : mapsquare_walkable_area (), character_base (), event_list ()
00034 {
00035     submap_ = posx_ = posy_ = offx_ = offy_ = 0;
00036     refmap = NULL;
00037     anim.resize (NBR_MOVES);
00038     for (u_int16 i = 0; i < NBR_MOVES; i++)
00039         anim[i] = new animation;
00040     current_move = STAND_NORTH;
00041     previous_move = NO_MOVE;
00042 
00043     saying = NULL;
00044 
00045     schedule_activated = true;
00046     action_activated = true; 
00047     goal_reached_ = true;
00048 
00049     schedule_args = NULL;
00050     action_args = NULL;
00051     
00052     callback = NULL;
00053 }
00054  
00055 mapcharacter::~mapcharacter ()
00056 {
00057     clear ();
00058     for (u_int16 i = 0; i < anim.size (); i++)
00059         delete anim[i];
00060     anim.clear (); 
00061 }
00062 
00063 void mapcharacter::clear ()
00064 {
00065     event_list::clear ();
00066     
00067     if (saying) delete saying;
00068 
00069     for (u_int16 i = 0; i < anim.size (); i++)
00070         anim[i]->clear ();
00071     
00072     mapsquare_walkable_area::clear (); 
00073     
00074     schedule.clear (); 
00075     action.clear (); 
00076     
00077     filename_ = "";
00078 
00079     Py_XDECREF (schedule_args);
00080     schedule_args = NULL;
00081     
00082     Py_XDECREF (action_args);
00083     action_args = NULL; 
00084     schedule_file_ = "";
00085     action_file_ = "";
00086     
00087     if (callback) delete callback;
00088 }
00089 
00090 s_int8 mapcharacter::get (igzstream& file)
00091 {
00092     int i;
00093 
00094     for (i = 0; i < NBR_MOVES; i++)
00095     {
00096         anim[i]->get (file);
00097         anim[i]->stop ();
00098     }
00099 
00100     mapsquare_walkable_area::get (file); 
00101 
00102     return 0;
00103 }
00104 
00105 s_int8 mapcharacter::load (string fname)
00106 {
00107     string s = MAPCHAR_DIR;
00108 
00109     s += fname;
00110     igzstream file (s);
00111     if (!file.is_open ())
00112         return -1;
00113     
00114     s_int8 retvalue; 
00115     if (fileops::get_version (file, 1, 1, s))
00116         retvalue = get (file);
00117     file.close ();
00118     filename_ = fname;
00119 
00120     return 0;
00121 }
00122 
00123 s_int8 mapcharacter::put (ogzstream& file) const
00124 {
00125     int i;
00126 
00127     for (i = 0; i < NBR_MOVES; i++)
00128     {
00129         anim[i]->put (file);
00130     }
00131 
00132     mapsquare_walkable_area::put (file); 
00133 
00134     return 0;
00135 }
00136 
00137 s_int8 mapcharacter::save (string fname) const
00138 {
00139     string s = MAPCHAR_DIR;
00140 
00141     s += fname;
00142     ogzstream file (s);
00143     if (!file.is_open ())
00144         return -1;
00145     
00146     s_int8 retvalue; 
00147     fileops::put_version (file, 1); 
00148     retvalue = put (file);
00149     file.close ();
00150 
00151     return 0;
00152 }
00153 
00154 s_int8 mapcharacter::get_state (igzstream& file)
00155 {
00156     string t; 
00157     bool b;
00158     u_int16 current_move__; 
00159     s_int8 offx__, offy__; 
00160     
00161     remove_from_pos (); 
00162     
00163     t << file; 
00164     load (t);
00165 
00166     // Reads the data members
00167     current_move__ << file;
00168     previous_move << file;
00169     submap_ << file;
00170     posx_ << file;
00171     posy_ << file;
00172     offx__ << file;
00173     offy__ << file;
00174 
00175     jump_to (submap (), posx (), posy ());
00176     set_offset (offx__, offy__); 
00177     
00178     current_move = current_move__; 
00179     
00180     // Get the path state
00181     mypath.get_state (file);
00182     // The map must be attached manually for now! :(
00183     mypath.refmap = refmap; 
00184     
00185     pathindex << file; 
00186     goal_reached_ << file;
00187     
00188     // Schedule state
00189     PyObject * args; 
00190     t << file;
00191     b << file;
00192     args = NULL; 
00193     if (b) args = python::get_tuple (file); 
00194     set_schedule (t, args);      
00195     Py_XDECREF (args); 
00196     b << file;
00197     set_schedule_active (b);
00198 
00199     // Action state
00200     t << file;
00201     b << file; 
00202     args = NULL; 
00203     if (b) args = python::get_tuple (file); 
00204     set_action (t, args);      
00205     Py_XDECREF (args); 
00206     b << file;
00207     set_action_active (b);
00208 
00209     // get the events
00210     py_callback::instance = schedule.get_instance (false);
00211     return event_list::get_state (file);
00212 }
00213 
00214 s_int8 mapcharacter::put_state (ogzstream& file) const
00215 {
00216     // Write the mapcharacter's file name
00217     filename_ >> file;
00218 
00219     // Write the data members
00220     current_move >> file;
00221     previous_move >> file;
00222     submap_ >> file;
00223     posx_ >> file;
00224     posy_ >> file;
00225     offx_ >> file;
00226     offy_ >> file;
00227 
00228     // Save the path state
00229     mypath.put_state (file);
00230     pathindex >> file; 
00231     goal_reached_ >> file;
00232     
00233     // Save the schedule script state
00234     schedule_file () >> file;
00235     if (schedule_args) 
00236     {
00237         true >> file; 
00238         python::put_tuple (schedule_args, file);
00239     }
00240     else false >> file; 
00241     is_schedule_activated () >> file;
00242     
00243     // Save the action script state
00244     action_file () >> file;
00245     if (action_args) 
00246     {
00247         true >> file; 
00248         python::put_tuple (action_args, file);
00249     }
00250     else false >> file; 
00251     is_action_activated () >> file; 
00252     
00253     // save the events
00254     event_list::put_state (file);
00255     
00256     return 0;
00257 }
00258 
00259 void mapcharacter::set_map (landmap * m) 
00260 {
00261     if (mymap ()) return;
00262 
00263     m->mapchar.push_back (this);
00264     
00265     refmap = m;
00266 }
00267 
00268 void mapcharacter::remove_from_map ()
00269 {
00270     if (!mymap ()) return;
00271     
00272     leave_position ();
00273     
00274     vector <mapcharacter *>::iterator i;
00275     for (i = mymap ()->mapchar.begin (); (*i) != this; i++);
00276     mymap ()->mapchar.erase (i); 
00277     
00278     refmap = NULL;
00279 }
00280 
00281 void mapcharacter::remove_from_pos ()
00282 {
00283     leave_position (); 
00284 }
00285 
00286 void mapcharacter::jump_to (u_int16 smap, u_int16 x, u_int16 y,
00287                 u_int16 pos)
00288 {
00289     leave_position (); 
00290     set_pos (smap, x, y);
00291     set_offset (0, 0);
00292 
00293     switch (pos)
00294     {
00295         case STAND_NORTH:
00296             stand_north ();
00297             break;
00298         case STAND_SOUTH:
00299             stand_south ();
00300             break;
00301         case STAND_WEST:
00302             stand_west ();
00303             break;
00304         case STAND_EAST:
00305             stand_east ();
00306             break;
00307         default:
00308             stand ();
00309             break;
00310     }
00311 
00312     enter_event evt; 
00313     evt.submap = submap ();
00314     evt.x = posx ();
00315     evt.y = posy ();
00316     evt.c = this;
00317     evt.dir = pos; 
00318     event_handler::raise_event (&evt);
00319 }
00320 
00321 void mapcharacter::stand ()
00322 {
00323     if (current_move >= WALK_NORTH && current_move != NO_MOVE)
00324     {
00325         previous_move = current_move; 
00326         current_move -= WALK_NORTH;
00327     }
00328 }
00329 
00330 void mapcharacter::stand_north ()
00331 {
00332     previous_move = current_move; 
00333     current_move = STAND_NORTH;
00334 }
00335 
00336 void mapcharacter::stand_south ()
00337 {
00338     previous_move = current_move; 
00339     current_move = STAND_SOUTH;
00340 }
00341 
00342 void mapcharacter::stand_east ()
00343 {
00344     previous_move = current_move; 
00345     current_move = STAND_EAST;
00346 }
00347 
00348 void mapcharacter::stand_west ()
00349 {
00350     previous_move = current_move; 
00351     current_move = STAND_WEST;
00352 }
00353 
00354 bool mapcharacter::can_go_north () const
00355 {
00356     if (!posy ())
00357         return false;
00358     u_int16 i, j;
00359     u_int16 sx = (posx () - base_x ()  < 0) ? 0 : posx () - base_x ();
00360     u_int16 sy = (posy () - base_y ()  < 0) ? 0 : posy () - base_y ();
00361     s_int16 ax = sx - (posx () - base_x ());
00362     s_int16 ay = sy - (posy () - base_y ());
00363     u_int16 ex =
00364         (posx () - base_x () + area_length () >
00365          refmap->submap[submap ()]->area_length ()) ? refmap->submap[submap ()]->area_length ()
00366         : posx () - base_x () + area_length ();
00367     u_int16 ey =
00368         (posy () - base_y () + area_height () >
00369          refmap->submap[submap ()]->area_height ()) ? refmap->submap[submap ()]->area_height ()
00370         : posy () - base_y () + area_height ();
00371 
00372     for (j = sy; j < ey; j++)
00373         for (i = sx; i < ex; i++)
00374         {
00375             if (get_square (i - sx + ax, j - sy + ay)->get_walkable ())
00376                 continue;
00377             if (!j)
00378                 continue;
00379             if (!(refmap->submap[submap ()]->area[i][j].is_walkable_north () &&
00380                   refmap->submap[submap ()]->area[i][j - 1].is_walkable_south ()
00381                   && refmap->submap[submap ()]->area[i][j - 1].is_free ()))
00382                 return false;
00383         }
00384     return true;
00385 }
00386 
00387 bool mapcharacter::can_go_south () const
00388 {
00389     if (posy () == refmap->submap[submap ()]->area_height () - 1)
00390         return false;
00391     u_int16 i, j;
00392     u_int16 sx = (posx () - base_x () < 0) ? 0 : posx () - base_x ();
00393     u_int16 sy = (posy () - base_y () < 0) ? 0 : posy () - base_y ();
00394     s_int16 ax = sx - (posx () - base_x ());
00395     s_int16 ay = sy - (posy () - base_y ());
00396     u_int16 ex =
00397         (posx () - base_x () + area_length () >=
00398          refmap->submap[submap ()]->area_length ()) ? refmap->submap[submap ()]->area_length ()
00399         : posx () - base_x () + area_length ();
00400     u_int16 ey =
00401         (posy () - base_y () + area_height () >=
00402          refmap->submap[submap ()]->area_height ()) ? refmap->submap[submap ()]->area_height ()
00403         : posy () - base_y () + area_height ();
00404 
00405     for (j = sy; j < ey; j++)
00406         for (i = sx; i < ex; i++)
00407         {
00408             if (get_square (i - sx + ax, j - sy + ay)->get_walkable ())
00409                 continue;
00410             if (j == refmap->submap[submap ()]->area_height () - 1)
00411                 continue;
00412             if (!(refmap->submap[submap ()]->area[i][j].is_walkable_south () &&
00413                   refmap->submap[submap ()]->area[i][j +
00414                                                   1].is_walkable_north ()
00415                   && refmap->submap[submap ()]->area[i][j + 1].is_free ()))
00416                 return false;
00417         }
00418     return true;
00419 }
00420 
00421 bool mapcharacter::can_go_east () const
00422 {
00423     if (posx () == refmap->submap[submap ()]->area_length () - 1)
00424         return false;
00425     u_int16 i, j;
00426     u_int16 sx = (posx () - base_x () < 0) ? 0 : posx () - base_x ();
00427     u_int16 sy = (posy () - base_y () < 0) ? 0 : posy () - base_y ();
00428     s_int16 ax = sx - (posx () - base_x ());
00429     s_int16 ay = sy - (posy () - base_y ());
00430     u_int16 ex =
00431         (posx () - base_x () + area_length () >=
00432          refmap->submap[submap ()]->area_length ()) ? refmap->submap[submap ()]->area_length ()
00433         : posx () - base_x () + area_length ();
00434     u_int16 ey =
00435         (posy () - base_y () + area_height () >=
00436          refmap->submap[submap ()]->area_height ()) ? refmap->submap[submap ()]->area_height ()
00437         : posy () - base_y () + area_height ();
00438 
00439     for (j = sy; j < ey; j++)
00440         for (i = sx; i < ex; i++)
00441         {
00442             if (get_square (i - sx + ax, j - sy + ay)->get_walkable ())
00443                 continue;
00444             if (i == refmap->submap[submap ()]->area_length () - 1)
00445                 continue;
00446             if (!(refmap->submap[submap ()]->area[i][j].is_walkable_east () &&
00447                   refmap->submap[submap ()]->area[i + 1][j].is_walkable_west ()
00448                   && refmap->submap[submap ()]->area[i + 1][j].is_free ()))
00449                 return false;
00450         }
00451     return true;
00452 }
00453 
00454 bool mapcharacter::can_go_west () const
00455 {
00456     if (!posx ())
00457         return false;
00458     u_int16 i, j;
00459     u_int16 sx = (posx () - base_x () < 0) ? 0 : posx () - base_x ();
00460     u_int16 sy = (posy () - base_y () < 0) ? 0 : posy () - base_y ();
00461     s_int16 ax = sx - (posx () - base_x ());
00462     s_int16 ay = sy - (posy () - base_y ());
00463     u_int16 ex =
00464         (posx () - base_x () + area_length () >
00465          refmap->submap[submap ()]->area_length ()) ? refmap->submap[submap ()]->area_length ()
00466         : posx () - base_x () + area_length ();
00467     u_int16 ey =
00468         (posy () - base_y () + area_height () >
00469          refmap->submap[submap ()]->area_height ()) ? refmap->submap[submap ()]->area_height ()
00470         : posy () - base_y () + area_height ();
00471 
00472     for (j = sy; j < ey; j++)
00473         for (i = sx; i < ex; i++)
00474         {
00475             if (get_square (i - sx + ax, j - sy + ay)->get_walkable ())
00476                 continue;
00477             if (!i)
00478                 continue;
00479             if (!(refmap->submap[submap ()]->area[i][j].is_walkable_west () &&
00480                   refmap->submap[submap ()]->area[i - 1][j].is_walkable_east ()
00481                   && refmap->submap[submap ()]->area[i - 1][j].is_free ()))
00482                 return false;
00483         }
00484     return true;
00485 }
00486 
00487 bool mapcharacter::go_north ()
00488 {
00489     if (current_move < WALK_NORTH)
00490     {
00491         bool ret = can_go_north ();
00492         previous_move = current_move;  
00493         if (ret) 
00494             current_move = WALK_NORTH;
00495         else current_move = STAND_NORTH;
00496         return ret; 
00497     }
00498     return false; 
00499 }
00500 
00501 bool mapcharacter::go_south ()
00502 {
00503     if (current_move < WALK_NORTH)
00504     {
00505         bool ret = can_go_south (); 
00506         previous_move = current_move;
00507         if (ret) 
00508             current_move = WALK_SOUTH;
00509         else current_move = STAND_SOUTH; 
00510         return ret; 
00511     }
00512     return false; 
00513 }
00514 
00515 bool mapcharacter::go_east ()
00516 {
00517     if (current_move < WALK_NORTH)
00518     {
00519         bool ret = can_go_east (); 
00520         previous_move = current_move;
00521         if (ret) 
00522             current_move = WALK_EAST;
00523         else current_move = STAND_EAST; 
00524         return ret; 
00525     }
00526     return false; 
00527 }
00528 
00529 bool mapcharacter::go_west ()
00530 {
00531     if (current_move < WALK_NORTH)
00532     {
00533         bool ret = can_go_west (); 
00534         previous_move = current_move;
00535         if (ret) 
00536             current_move = WALK_WEST;
00537         else current_move = STAND_WEST; 
00538         return ret; 
00539     }
00540     return false; 
00541 }
00542 
00543 bool mapcharacter::set_goal (u_int16 x, u_int16 y, u_int16 dir)
00544 {
00545     mypath.refmap = mymap ();
00546     mypath.submap = submap (); 
00547     mypath.start.x = posx ();
00548     mypath.start.y = posy (); 
00549     mypath.goal.x = x;
00550     mypath.goal.y = y;
00551     mypath.dir = dir;
00552     pathindex = 0; 
00553     goal_reached_ = false;
00554     
00555     return mypath.calculate (); 
00556 }
00557 
00558 void mapcharacter::set_callback (PyObject *cb, PyObject *args)
00559 {
00560     if (callback) delete callback;
00561     callback = new py_callback (cb, args);
00562 }
00563 
00564 void mapcharacter::time_callback (string delay, PyObject *cb, PyObject *args)
00565 {
00566     time_event *ev = new time_event (delay);
00567     ev->set_callback (cb, args);
00568     add_event (ev);
00569 }
00570 
00571 void mapcharacter::time_callback_string (string delay, string cb, PyObject *args)
00572 {
00573     PyObject *instance = schedule.get_instance (false);
00574 
00575     // check that we have a valid instance that contains our callback
00576     if (instance == NULL)
00577     {
00578         fprintf (stderr, "*** error: mapcharacter::time_callback: Invalid instance!");
00579         return;
00580     }
00581      
00582     PyObject *callback = PyObject_GetAttrString (instance, (char *) cb.c_str ());
00583 
00584     if (!PyCallable_Check (callback))
00585     {
00586         fprintf (stderr, "*** error: mapcharacter::time_callback: Setting callback ' %s' failed!", cb.c_str ());
00587     }
00588     else
00589     {
00590         time_event *ev = new time_event (delay);
00591         ev->set_callback (callback, args);
00592         add_event (ev);
00593     }
00594     
00595     Py_XDECREF (callback);
00596 }
00597 
00598 bool mapcharacter::follow_path () 
00599 {
00600     //  If a movment is engaged, let it finish first.
00601     if (offx () || offy ()) 
00602         return false;
00603     
00604     // If the goal isn't reached yet.
00605     if (pathindex < mypath.nbr_moves ())
00606     {
00607         u_int16 dir = mypath.get_move (pathindex);
00608         u_int8 success = 0; 
00609 
00610         // Try to follow the direction
00611         switch (dir) 
00612         {
00613             case WALK_NORTH:
00614                 if (go_north ()) success = 1; 
00615                 break;
00616 
00617             case WALK_SOUTH:
00618                 if (go_south ()) success = 1; 
00619                 break;
00620                 
00621             case WALK_WEST:
00622                 if (go_west ()) success = 1; 
00623                 break;
00624                 
00625             case WALK_EAST:
00626                 if (go_east ()) success = 1; 
00627                 break;
00628         }
00629                  
00630         // Who the fuck is on my way!!?@! I have to find a new path now!
00631         if (!success) 
00632         {
00633             mypath.start.x = posx ();
00634             mypath.start.y = posy ();
00635             mypath.submap = submap ();
00636             mypath.calculate ();
00637             pathindex = 0; 
00638         }
00639         else pathindex++; 
00640     }
00641     else
00642     {
00643         switch (mypath.dir)
00644         {
00645             case STAND_NORTH:
00646                 stand_north ();
00647                 break;
00648             case STAND_SOUTH:
00649                 stand_south ();
00650                 break;
00651             case STAND_WEST:
00652                 stand_west ();
00653                 break;
00654             case STAND_EAST:
00655                 stand_east ();
00656                 break;
00657         }
00658 
00659         // goal reached -> notify script (as the script might immediately
00660         // set the next goal, we gotta set goal_reached_ before that)
00661         goal_reached_ = true;
00662         if (callback) callback->callback_func0 ();
00663         return true;
00664     }
00665     return false;
00666 }
00667 
00668 void mapcharacter::stop_moving ()
00669 {
00670     set_goal (posx (), posy ());
00671 }
00672 
00673 bool mapcharacter::goal_reached () 
00674 { 
00675     return goal_reached_;
00676 }
00677 
00678 void mapcharacter::look_invert (u_int16 p)
00679 {
00680     switch (p)
00681     {
00682         case STAND_NORTH:
00683             stand_south ();
00684             break;
00685         case STAND_SOUTH:
00686             stand_north ();
00687             break;
00688         case STAND_EAST:
00689             stand_west ();
00690             break;
00691         case STAND_WEST:
00692             stand_east ();
00693             break;
00694     }
00695 }
00696 
00697 mapcharacter *mapcharacter::whosnext () const
00698 {
00699     switch (current_move)
00700     {
00701         case STAND_NORTH:
00702             if (posy () == 0)
00703                 return NULL;
00704             return refmap->submap[submap ()]->area[posx ()][posy () - 1].whoshere ();
00705             break;
00706         case STAND_SOUTH:
00707             if (posy () == refmap->submap[submap ()]->area_height () - 1)
00708                 return NULL;
00709             return refmap->submap[submap ()]->area[posx ()][posy () + 1].whoshere ();
00710             break;
00711         case STAND_WEST:
00712             if (posx () == 0)
00713                 return NULL;
00714             return refmap->submap[submap ()]->area[posx () - 1][posy ()].whoshere ();
00715             break;
00716         case STAND_EAST:
00717             if (posx () == refmap->submap[submap ()]->area_length () - 1)
00718                 return NULL;
00719             return refmap->submap[submap ()]->area[posx () + 1][posy ()].whoshere ();
00720             break;
00721     }
00722     return NULL;
00723 }
00724 
00725 bool mapcharacter::do_stuff (string method, PyObject *args)
00726 {
00727     if (!schedule.has_attribute (method)) return false;
00728     else schedule.call_method (method, args);
00729     
00730     return true;
00731 }
00732 
00733 void mapcharacter::set_schedule (string file, PyObject * args)
00734 {     
00735     // Clears the schedule
00736     schedule.clear ();
00737     Py_XDECREF (schedule_args);
00738     schedule_args = NULL;
00739 
00740     // Set new schedule
00741     if (file != "")
00742     {
00743         Py_XINCREF (args); 
00744         schedule_args = args; 
00745         u_int16 argssize = args == NULL ? 1 : PyTuple_Size (args) + 1; 
00746         PyObject * theargs;
00747         
00748         theargs = PyTuple_New (argssize);
00749         
00750         // We can pass_instance directly 'cause PyTuple_SetItem steals a
00751         // reference to the result of pass_instance.
00752         PyTuple_SetItem (theargs, 0, python::pass_instance (this, "mapcharacter"));
00753         for (u_int16 i = 1; i < argssize; i++)
00754         {
00755             PyObject * intref = PyTuple_GetItem (args, i - 1);
00756             Py_INCREF (intref); 
00757             PyTuple_SetItem (theargs, i, intref); 
00758         }
00759         schedule.create_instance ("schedules.mapcharacters." + file, file, theargs);
00760         Py_DECREF (theargs);
00761         
00762         if (!schedule.has_attribute ("run"))
00763             set_schedule_active (false);
00764     }
00765     schedule_file_ = file;
00766 }
00767 
00768 void mapcharacter::set_action (string file, PyObject * args)
00769 {     
00770     // Clears the action script
00771     action.clear ();
00772     Py_XDECREF (action_args);
00773     action_args = NULL;
00774 
00775     if (file != "")
00776     {
00777         Py_XINCREF (args);
00778         action_args = args; 
00779         u_int16 argssize = args == NULL ? 1 : PyTuple_Size (args) + 1; 
00780         PyObject * theargs;
00781         
00782         theargs = PyTuple_New (argssize);
00783         
00784         // We can pass_instance directly 'cause PyTuple_SetItem steals a
00785         // reference to the result of pass_instance.
00786         PyTuple_SetItem (theargs, 0, python::pass_instance (this, "mapcharacter"));
00787         for (u_int16 i = 1; i < argssize; i++)
00788         {
00789             PyObject * intref = PyTuple_GetItem (args, i - 1);
00790             Py_INCREF (intref); 
00791             PyTuple_SetItem (theargs, i, intref); 
00792         }
00793         action.create_instance ("actions." + file, file, theargs);
00794         Py_DECREF (theargs); 
00795     }
00796     action_file_ = file;
00797 }
00798  
00799 bool mapcharacter::update ()
00800 {
00801     update_move ();
00802 
00803     if (is_schedule_activated ()) 
00804         schedule.run ();
00805 
00806     // if we have a goal, then go there!
00807     if (!goal_reached ()) 
00808         follow_path ();
00809 
00810     if (previous_move != NO_MOVE && previous_move != current_move) 
00811     {
00812         anim[previous_move]->stop ();
00813         anim[previous_move]->rewind ();
00814         anim[current_move]->play (); 
00815     }
00816     
00817     if (saying && !saying->update ())
00818     {
00819         delete saying;
00820         saying = NULL; 
00821     }
00822         
00823     return true;
00824 }
00825 
00826 void mapcharacter::launch_action (mapcharacter * requester)
00827 {
00828     PyObject *args = PyTuple_New (1);
00829     PyTuple_SetItem (args, 0, python::pass_instance (requester, "mapcharacter"));      
00830     if (is_action_activated ()) action.run (args); 
00831     Py_DECREF (args);
00832 }
00833 
00834 void mapcharacter::draw (s_int16 x, s_int16 y, const drawing_area * da_opt, surface * target) const
00835 {
00836     anim[current_move]->draw (x, y, da_opt, target);
00837 }
00838 
00839 void mapcharacter::draw_bubble (s_int16 x, s_int16 y, const drawing_area * da_opt,
00840                                 surface * target) const
00841 {
00842     if (saying) 
00843     {
00844         s_int16 dx = x - (saying->drawing_area::length () >> 1) + (anim[current_move]->length () >> 1); 
00845         s_int16 dy = y - (saying->drawing_area::height ()) + 5;
00846 
00847         if (dx < 4) dx = 4;
00848         else if (dx + saying->drawing_area::length () > da_opt->x () + da_opt->length () - 4)
00849             dx = da_opt->x () + da_opt->length () - saying->drawing_area::length () - 4; 
00850         
00851         saying->move (dx, dy);
00852         saying->assign_drawing_area (da_opt);
00853         saying->draw ();
00854         saying->detach_drawing_area (); 
00855     }     
00856 }
00857 
00858 mapcharacter & mapcharacter::operator = (const mapcharacter & src)
00859 {
00860     u_int16 i;
00861 
00862     clear (); 
00863 
00864     (mapsquare_walkable_area&) (*this) = (mapsquare_walkable_area&) src;
00865     (character_base&) (*this) = (character_base&) src;
00866     
00867     for (i = 0; i < NBR_MOVES; i++)
00868         (*anim[i]) = (*src.anim[i]);
00869 
00870     schedule = src.schedule;
00871 
00872     action = src.action;
00873 
00874     current_move = src.currentmove ();
00875     if (src.mymap ())
00876     {
00877         set_map (src.mymap ());
00878         set_pos (src.submap (), src.posx (), src.posy ());
00879         set_offset (src.offx (), src.offy ()); 
00880     }
00881 
00882     filename_ = src.filename_;
00883     
00884     return *this;
00885 }
00886 
00887 
00888 
00889 // Private methods
00890 
00891 
00892 void mapcharacter::occupy (u_int16 smap, u_int16 px, u_int16 py)
00893 {
00894     mapsquare_char mschar;
00895 
00896     list <mapsquare_char>::iterator it;
00897     u_int16 sx = (px - base_x () < 0) ? 0 : px - base_x ();
00898     u_int16 sy = (py - base_y () < 0) ? 0 : py - base_y ();
00899     u_int16 ex = (sx + area_length () > refmap->submap[smap]->area_length ()) ?
00900         refmap->submap[smap]->area_length () : sx + area_length ();
00901     u_int16 ey = (sy + area_height () > refmap->submap[smap]->area_height ()) ?
00902         refmap->submap[smap]->area_height () : sy + area_height ();
00903     u_int16 i, j;
00904 
00905     // Placing the base tile first
00906     mschar.mchar = this;
00907     mschar.is_base = true;
00908     mschar.x = px;
00909     mschar.y = py;
00910     mschar.walkable =
00911         get_square (base_x (), base_y ())->get_walkable ()  == ALL_WALKABLE;
00912     
00913     refmap->submap[smap]->area[px][py].mapchars.push_back (mschar);
00914     it = --refmap->submap[smap]->area[px][py].mapchars.end ();
00915     it->base_tile = it;
00916     mschar.base_tile = it;
00917     mschar.is_base = false;
00918     
00919     // Ready to place the rest now
00920     for (i = sx; i < ex; i++)
00921         for (j = sy; j < ey; j++)
00922             if (i != px || j != py)
00923             {
00924                 mschar.x = i;
00925                 mschar.y = j;
00926                 mschar.walkable =
00927                     get_square (sx + base_x () - px, sy + base_y () - py)->
00928                     get_walkable () == ALL_WALKABLE;
00929                 refmap->submap[smap]->area[i][j].mapchars.push_back (mschar);
00930             }
00931 } 
00932 
00933 void mapcharacter::leave (u_int16 smap, u_int16 px, u_int16 py)
00934 {
00935     list <mapsquare_char>::iterator it;
00936     list <mapsquare_char>::iterator e;
00937 
00938     u_int16 sx = (px - base_x () < 0) ? 0 : px - base_x ();
00939     u_int16 sy = (py - base_y () < 0) ? 0 : py - base_y ();
00940     u_int16 ex = (sx + area_length () > refmap->submap[smap]->area_length ()) ?
00941         refmap->submap[smap]->area_length () : sx + area_length ();
00942     u_int16 ey = (sy + area_height () > refmap->submap[smap]->area_height ()) ?
00943         refmap->submap[smap]->area_height () : sy + area_height ();
00944     u_int16 i, j;
00945 
00946 
00947     for (i = sx; i < ex; i++)
00948         for (j = sy; j < ey; j++)
00949         {
00950             it = refmap->submap[smap]->area[i][j].mapchars.begin ();
00951             e = refmap->submap[smap]->area[i][j].mapchars.end ();
00952 
00953             while (it != e && it->mchar != this)
00954                 it++;
00955             if (it != e)
00956                 refmap->submap[smap]->area[px][py].mapchars.erase (it);
00957         }
00958 }
00959 
00960 void mapcharacter::leave_position () 
00961 {
00962     leave (submap (), posx (), posy ());
00963     switch (current_move) 
00964     {
00965         case WALK_NORTH: 
00966         case WALK_SOUTH:
00967             leave (submap (), posx (), posy () - 1);
00968             break;
00969             
00970         case WALK_WEST:
00971         case WALK_EAST:
00972             leave (submap (), posx () - 1, posy ());
00973             break;
00974     }
00975 }
00976 
00977 void mapcharacter::set_pos (u_int16 smap, u_int16 x, u_int16 y)
00978 {
00979     // update character position
00980     submap_ = smap;
00981     posx_ = x;
00982     posy_ = y;
00983 
00984     // mark the character's place as occupied
00985     occupy (submap (), posx (), posy ()); 
00986 }
00987 
00988 void mapcharacter::update_move ()
00989 {
00990     if (refmap)
00991         switch (currentmove ())
00992         {
00993             case WALK_NORTH:
00994                 if (!offy ())
00995                 {
00996                     if (!can_go_north ())
00997                     {
00998                         stand_north ();
00999                         break;
01000                     }
01001                     leave_event evt;
01002                     
01003                     evt.submap = submap ();
01004                     evt.x = posx ();
01005                     evt.y = posy ();
01006                     evt.c = this;
01007                     evt.dir = WALK_NORTH; 
01008                     event_handler::raise_event (&evt);
01009                     
01010                     occupy (submap (), posx (), posy () - 1);
01011                     set_offset (offx (), offy () - 1);
01012                 }
01013                 
01014                 set_offset (offx (), offy () - 1);
01015 
01016                 if (offy () == -MAPSQUARE_SIZE)
01017                 {
01018                     leave (submap (), posx (), posy ());
01019                     leave (submap (), posx (), posy () - 1);
01020                     set_pos (submap (), posx (), posy () - 1);
01021                     set_offset (offx (), 0); 
01022                     stand_north ();
01023                     
01024                     enter_event evt;
01025 
01026                     evt.submap = submap ();
01027                     evt.x = posx ();
01028                     evt.y = posy ();
01029                     evt.c = this;
01030                     evt.dir = WALK_NORTH; 
01031                     event_handler::raise_event (&evt);
01032                 }
01033                 break;
01034             case WALK_SOUTH:
01035                 if (!offy ())
01036                 {
01037                     if (!can_go_south ())
01038                     {
01039                         stand_south ();
01040                         break;
01041                     }
01042                     leave_event evt;
01043 
01044                     evt.submap = submap ();
01045                     evt.x = posx ();
01046                     evt.y = posy ();
01047                     evt.c = this;
01048                     evt.dir = WALK_SOUTH; 
01049                     event_handler::raise_event (&evt);
01050 
01051                     leave (submap (), posx (), posy ());
01052                     occupy (submap (), posx (), posy ());
01053                     set_pos (submap (), posx (), posy () + 1);
01054                     set_offset (0, -(MAPSQUARE_SIZE - 1));
01055                  }
01056                 else
01057                 {
01058                     set_offset (offx (), offy () + 1);
01059 
01060                     if (!offy ())
01061                     {
01062                         leave (submap (), posx (), posy () - 1);
01063                         stand_south ();
01064 
01065                         enter_event evt; 
01066                         evt.submap = submap ();
01067                         evt.x = posx ();
01068                         evt.y = posy ();
01069                         evt.c = this;
01070                         evt.dir = WALK_SOUTH; 
01071                         event_handler::raise_event (&evt);
01072                     }
01073                 }
01074                 break;
01075             case WALK_WEST:
01076                 if (!offx ())
01077                 {
01078                     if (!can_go_west ())
01079                     {
01080                         stand_west ();
01081                         break;
01082                     }
01083                     leave_event evt;
01084 
01085                     evt.submap = submap ();
01086                     evt.x = posx ();
01087                     evt.y = posy ();
01088                     evt.c = this;
01089                     evt.dir = WALK_WEST; 
01090                     event_handler::raise_event (&evt);
01091 
01092                     occupy (submap (), posx () - 1, posy ()); 
01093                 }
01094                 set_offset (offx () -1, offy ());  
01095                 if (offx () == -MAPSQUARE_SIZE)
01096                 {
01097                     leave (submap (), posx (), posy ());
01098                     leave (submap (), posx () - 1, posy ());
01099                     set_pos (submap (), posx () - 1, posy ());
01100                     set_offset (0, offy ());  
01101                     stand_west ();
01102                     
01103                     enter_event evt; 
01104                     evt.submap = submap ();
01105                     evt.x = posx ();
01106                     evt.y = posy ();
01107                     evt.c = this;
01108                     evt.dir = WALK_WEST; 
01109                     event_handler::raise_event (&evt);
01110                 }
01111                 break;
01112             case WALK_EAST:
01113                 if (!offx ())
01114                 {
01115                     if (!can_go_east ())
01116                     {
01117                         stand_east ();
01118                         break;
01119                     }
01120                     leave_event evt;
01121                     
01122                     evt.submap = submap ();
01123                     evt.x = posx ();
01124                     evt.y = posy ();
01125                     evt.c = this;
01126                     evt.dir = WALK_EAST; 
01127                     event_handler::raise_event (&evt);
01128 
01129                     leave (submap (), posx (), posy ());
01130                     occupy (submap (), posx (), posy ());
01131                     set_pos (submap (), posx () + 1, posy ());
01132                     set_offset (-(MAPSQUARE_SIZE - 1), 0);  
01133                 }
01134                 else
01135                 {
01136                     set_offset (offx () + 1, offy ());  
01137                     if (!offx ())
01138                     {
01139                         leave (submap (), posx () - 1, posy ());
01140                         stand_east ();
01141                         
01142                         enter_event evt; 
01143                         evt.submap = submap ();
01144                         evt.x = posx ();
01145                         evt.y = posy ();
01146                         evt.c = this;
01147                         evt.dir = WALK_EAST; 
01148                         event_handler::raise_event (&evt);
01149                     }
01150                 }
01151                 break;
01152         }
01153     anim[current_move]->update ();     
01154 }
01155 
01156 void mapcharacter::speak (const string & text)
01157 {
01158     if (saying)
01159         delete saying;
01160 
01161     string col; 
01162     switch (get_color ()) 
01163     { 
01164         case 1: col = "yellow"; break; 
01165         case 2: col = "red"; break; 
01166         case 3: col = "violet"; break; 
01167         case 4: col = "blue"; break; 
01168         case 5: col = "green"; break;
01169         default: col = "white"; break; 
01170     } 
01171     
01172     saying = new text_bubble (text, col, "original"); 
01173 }