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