actions.cc

Go to the documentation of this file.
00001 /*
00002  *  actions.cc - Action controllers for actors.
00003  *
00004  *  Copyright (C) 2000-2001  The Exult Team
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; either version 2 of the License, or
00009  *  (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00019  */
00020 
00021 #ifdef HAVE_CONFIG_H
00022 #  include <config.h>
00023 #endif
00024 
00025 #include "gamewin.h"
00026 #include "actions.h"
00027 #include "actors.h"
00028 #include "Zombie.h"
00029 #include "Astar.h"
00030 #include "paths.h"
00031 #include "dir.h"
00032 #include "ucmachine.h"
00033 #include "frameseq.h"
00034 #include "ucmachine.h"
00035 #include "cheat.h"
00036 #include "party.h"
00037 
00038 using std::cout;
00039 using std::endl;
00040 
00041 long Actor_action::seqcnt = 0;
00042 
00043 /*
00044  *  Handle an event and check to see if we were deleted.
00045  *
00046  *  Output: Delay value from handle_event (0 if we've been deleted).
00047  */
00048 
00049 int Actor_action::handle_event_safely
00050   (
00051   Actor *actor,
00052   bool& deleted     // True returned if we're gone!
00053   )
00054   {
00055   Actor_action *old_action = actor->get_action();
00056   long old_seq = old_action->seq;
00057           // Do current action.
00058   int delay = handle_event(actor);
00059   if (actor->get_action() != old_action ||
00060       old_action->seq != old_seq)
00061     {
00062     deleted = true;   // We've been deleted.
00063     return 0;
00064     }
00065   deleted = false;
00066   return delay;
00067   }
00068 
00069 /*
00070  *  Set to walk from one point to another the dumb way.
00071  *
00072  *  Output: ->this, or 0 if unsuccessful.
00073  */
00074 
00075 Actor_action *Actor_action::walk_to_tile
00076   (
00077   Actor * /* npc */,
00078   Tile_coord src,
00079   Tile_coord dest,
00080   int /* dist */      // Ignored.
00081   )
00082   {
00083   Zombie *path = new Zombie();
00084   get_party = false;
00085           // Set up new path.
00086   if (path->NewPath(src, dest, 0))
00087     return (new Path_walking_actor_action(path));
00088   else
00089     {
00090     delete path;
00091     return (0);
00092     }
00093   }
00094 
00095 /*
00096  *  Set up an action to get an actor to a location (via pathfinding), and
00097  *  then execute another action when he gets there.
00098  *
00099  *  Output: ->action.  
00100  */
00101 
00102 Actor_action *Actor_action::create_action_sequence
00103   (
00104   Actor *actor,     // Whom to activate.
00105   Tile_coord dest,    // Where to walk to.
00106   Actor_action *when_there, // What to do when he gets there.
00107   bool from_off_screen    // Have actor walk from off-screen.
00108   )
00109   {
00110   Actor_action *act = when_there;
00111   Tile_coord actloc = actor->get_tile();
00112   if (from_off_screen)
00113     actloc.tx = actloc.ty = -1;
00114   if (dest != actloc)   // Get to destination.
00115     {
00116     Actor_action *w = new Path_walking_actor_action(new Astar());
00117     Actor_action *w2 = w->walk_to_tile(actor, actloc, dest);
00118     if (w2 != w)
00119       delete w;
00120     if (!w2)    // Failed?  Teleport.
00121       w2 = new Move_actor_action(dest);
00122           // And teleport if blocked walking.
00123     Actor_action *tel = new Move_actor_action(dest);
00124           // Walk there, then do whatever.
00125     Sequence_actor_action *seq;
00126     act = seq = new Sequence_actor_action(w2, tel, act);
00127     seq->set_speed(0);  // No delay between actions.
00128     }
00129   return act;
00130   }
00131 
00132 /*
00133  *  Null action.
00134  */
00135 
00136 int Null_action::handle_event
00137   (
00138   Actor *actor
00139   )
00140   {
00141   return 0;
00142   }
00143 
00144 /*
00145  *  Create action to follow a path.
00146  */
00147 
00148 Path_walking_actor_action::Path_walking_actor_action
00149   (
00150   PathFinder *p,      // Pathfinder, or 0 for Astar.
00151   int maxblk      // Max. retries when blocked.
00152   ) : reached_end(false), path(p), from_offscreen(false),
00153       subseq(0), blocked(0), max_blocked(maxblk)
00154   {
00155   if (!path)
00156     path = new Astar();
00157   Tile_coord src = path->get_src(), dest = path->get_dest();
00158   original_dir = static_cast<int>(Get_direction4(
00159         src.ty - dest.ty, dest.tx - src.tx));
00160   }
00161 
00162 /*
00163  *  Delete.
00164  */
00165 
00166 Path_walking_actor_action::~Path_walking_actor_action
00167   (
00168   )
00169   {
00170   delete path;
00171   delete subseq;
00172   subseq = 0;     // (Debugging).
00173   original_dir = -1;
00174   }
00175 
00176 /*
00177  *  Create action for walking to given destination using Astar.
00178  *  Note:  This is a static method.
00179  *
00180  *  Output: Action if successful, else 0.
00181  */
00182 
00183 Path_walking_actor_action *Path_walking_actor_action::create_path
00184   (
00185   Tile_coord src,     // Starting position.
00186   Tile_coord dest,    // Destination.
00187   Pathfinder_client& cost   // Cost for Astar.
00188   )
00189   {
00190   Astar *path = new Astar();
00191           // Get to within 1 tile.
00192   if (path->NewPath(src, dest, &cost))
00193     return new Path_walking_actor_action(path);
00194   else
00195     {
00196     delete path;
00197     return 0;
00198     }
00199   }
00200 
00201 /*
00202  *  Handle a time event.
00203  *
00204  *  Output: 0 if done with this action, else delay for next frame.
00205  */
00206 
00207 int Path_walking_actor_action::handle_event
00208   (
00209   Actor *actor
00210   )
00211   {
00212   if (subseq)     // Going through a door?
00213     {
00214     int delay = subseq->handle_event(actor);
00215     if (delay)
00216       return delay; // Still going.
00217     set_subseq(0);
00218           // He was stopped, so restore speed.
00219     actor->set_frame_time(speed);
00220     return speed;   // Come back in a moment.
00221     }
00222   Tile_coord tile;
00223   if (blocked)
00224     {
00225 #if 0
00226 std::cout << "Actor " << actor->get_name() << " blocked.  Retrying." << std::endl;
00227 #endif
00228     if (actor->step(blocked_tile, blocked_frame))
00229       {   // Successful?
00230       blocked = 0;
00231           // He was stopped, so restore speed.
00232       actor->set_frame_time(speed);
00233       return speed;
00234       }
00235           // Wait up to 1.6 secs.
00236     return (blocked++ > max_blocked ? 0 
00237           : 100 + blocked*(std::rand()%500));
00238     }
00239   speed = actor->get_frame_time();// Get time between frames.
00240   if (!speed)
00241     return 0;   // Not moving.
00242   bool done;      // So we'll know if this is the last.
00243   if (!path->GetNextStep(tile, done))
00244     {
00245     reached_end = true; // Did it.
00246     return (0);
00247     }
00248   if (done)     // In case we're deleted.
00249     reached_end = true;
00250   Tile_coord cur = actor->get_tile();
00251   int newdir = static_cast<int>(Get_direction4(cur.ty - tile.ty, 
00252               tile.tx - cur.tx));
00253   Frames_sequence *frames = actor->get_frames(newdir);
00254   int& step_index = actor->get_step_index();
00255   if (!step_index)    // First time?  Init.
00256     step_index = frames->find_unrotated(actor->get_framenum());
00257           // Get next (updates step_index).
00258   int frame = frames->get_next(step_index);
00259   int cur_speed = speed;    // Step() might delete us!
00260   if (from_offscreen)   // Teleport to 1st spot.
00261     {
00262     from_offscreen = false;
00263     actor->move(tile.tx, tile.ty, tile.tz);
00264     return cur_speed;
00265     }
00266   else if (actor->step(tile, frame))  // Successful.
00267     {
00268     if (get_party)    // MUST be the Avatar.
00269       Game_window::get_instance()->get_party_man()->
00270             get_followers(newdir);
00271     if (done)   // Was this the last step?
00272       return (0);
00273     return cur_speed;
00274     }
00275   reached_end = false;
00276   frames->decrement(step_index);  // We didn't take the step.
00277           // Blocked by a door?
00278   if (actor->get_tile().distance(tile) == 1 &&
00279       !cheat.in_map_editor()) // And NOT map-editing?
00280           // +++++Check for intelligence?
00281     {
00282     Game_object *door = Game_object::find_door(tile);
00283     if (door != 0 && door->is_closed_door() &&
00284           // Make sure it's not locked!
00285         door->get_framenum()%4 < 2)
00286 
00287           // Try to open it.
00288       {
00289       if (open_door(actor, door))
00290         return speed;
00291       }
00292     }
00293   if (!max_blocked ||   // No retries allowed?
00294       actor->is_dormant())  // Or actor off-screen?
00295     return 0;
00296   blocked = 1;
00297   blocked_tile = tile;
00298   blocked_frame = frame;
00299   return (100 + std::rand()%500); // Wait .1 to .6 seconds.
00300   }
00301 
00302 /*
00303  *  Open door that's blocking the NPC, and set action to walk past and
00304  *  close it.
00305  *
00306  *  Output: 1 if successful.
00307  */
00308 
00309 int Path_walking_actor_action::open_door
00310   (
00311   Actor *actor,
00312   Game_object *door
00313   )
00314   {
00315   Game_window *gwin = Game_window::get_instance();
00316   Tile_coord cur = actor->get_tile();
00317           // Get door's footprint in tiles.
00318   Rectangle foot = door->get_footprint();
00319           // Open it, but kludge quality to
00320           //   avoid unwanted usecode.
00321   int savequal = door->get_quality();
00322   door->set_quality(0);
00323   door->activate();
00324   door->set_quality(savequal);
00325   Tile_coord past;    // Tile on other side of door.
00326   past.tz = cur.tz;
00327   int dir;      // Get dir to face door afterwards.
00328   if (foot.w > foot.h)    // Horizontal?
00329     {
00330     past.tx = foot.x + foot.w/2;
00331     if (cur.ty <= foot.y) // N. of door?
00332       {
00333       past.ty = foot.y + foot.h;
00334       dir = 0;
00335       }
00336     else      // S. of door?
00337       {
00338       past.ty = foot.y - 1;
00339       dir = 4;
00340       }
00341     }
00342   else        // Vertical.
00343     {
00344     past.ty = foot.y + foot.h/2;
00345     if (cur.tx <= foot.x) // W. of door?
00346       {
00347       past.tx = foot.x + foot.w;
00348       dir = 6;
00349       }
00350     else      // E. of door?
00351       {
00352       past.tx = foot.x - 1;
00353       dir = 2;
00354       }
00355     }
00356   Tile_coord tmp = Map_chunk::find_spot(past, 1, actor, 1);
00357   if (past.tx != -1)    // Succeeded.  Walk past and close it.
00358     {
00359 #ifdef DEBUG
00360     cout << "Path_walking_actor_action::open_door()" << endl;
00361 #endif
00362     signed char frames[2];
00363     frames[0] = actor->get_dir_framenum(dir, Actor::standing);
00364     frames[1] = actor->get_dir_framenum(dir, 3);
00365     signed char standframe = frames[0];
00366     set_subseq(create_action_sequence(actor, past,
00367       new Sequence_actor_action(
00368         new Frames_actor_action(frames, 
00369               sizeof(frames)),
00370         new Activate_actor_action(door),
00371         new Frames_actor_action(&standframe, 1))));
00372     return 1;
00373     }
00374   return 0;
00375   }
00376 
00377 /*
00378  *  Stopped moving.
00379  */
00380 
00381 void Path_walking_actor_action::stop
00382   (
00383   Actor *actor
00384   )
00385   {
00386           // Don't set slimes.
00387   if (!actor->get_info().has_strange_movement())
00388     {     // ++++For now, just use original dir.
00389     Frames_sequence *frames = actor->get_frames(original_dir);
00390     actor->change_frame(frames->get_resting());
00391     }
00392   }
00393 
00394 /*
00395  *  Set to walk from one point to another, using the same pathfinder.
00396  *
00397  *  Output: ->this, or 0 if unsuccessful.
00398  */
00399 
00400 Actor_action *Path_walking_actor_action::walk_to_tile
00401   (
00402   Actor *npc,
00403   Tile_coord src,     // tx=-1 or ty=-1 means don't care.
00404   Tile_coord dest,    // Same here.
00405   int dist      // Distance to get to within dest.
00406   )
00407   {
00408   Game_window *gwin = Game_window::get_instance();
00409   blocked = 0;      // Clear 'blocked' count.
00410   reached_end = false;    // Starting new path.
00411   get_party = false;
00412   from_offscreen = false;
00413         //+++++Should dist be used below??:
00414           // Set up new path.
00415           // Don't care about 1 coord.?
00416   if (dest.tx == -1 || dest.ty == -1)
00417     {
00418     if (dest.tx == dest.ty) // Completely off-screen?
00419       {
00420       Offscreen_pathfinder_client cost(npc);
00421       if (!path->NewPath(src, dest, &cost))
00422         return (0);
00423       }
00424     else
00425       {
00426       Onecoord_pathfinder_client cost(npc);
00427       if (!path->NewPath(src, dest, &cost))
00428         return (0);
00429       }
00430     }
00431           // How about from source?
00432   else if (src.tx == -1 || src.ty == -1)
00433     {     // Figure path in opposite dir.
00434     if (src.tx == src.ty) // Both -1?
00435       {   // Aim from NPC's current pos.
00436       Offscreen_pathfinder_client cost(npc, npc->get_tile());
00437       if (!path->NewPath(dest, src, &cost))
00438         return (0);
00439       }
00440     else
00441       {
00442       Onecoord_pathfinder_client cost(npc);
00443       if (!path->NewPath(dest, src, &cost))
00444         return (0);
00445       }
00446     from_offscreen = true;
00447           // Set to go backwards.
00448     if (!path->set_backwards())
00449       return (0);
00450     }
00451   else
00452     {
00453     Actor_pathfinder_client cost(npc, dist);
00454     if (!path->NewPath(src, dest, &cost))
00455       return (0);
00456     }
00457           // Reset direction (but not index).
00458   original_dir = static_cast<int>(Get_direction4(
00459         src.ty - dest.ty, dest.tx - src.tx));
00460   return (this);
00461   }
00462 
00463 /*
00464  *  Return current destination.
00465  *
00466  *  Output: 0 if none.
00467  */
00468 
00469 int Path_walking_actor_action::get_dest
00470   (
00471   Tile_coord& dest    // Returned here.
00472   )
00473   {
00474   dest = path->get_dest();
00475   return (1);
00476   }
00477 
00478 /*
00479  *  Following an Astar path?
00480  */
00481 
00482 int Path_walking_actor_action::following_smart_path
00483   (
00484   )
00485   {
00486   return path != 0 && path->following_smart_path();
00487   }
00488 
00489 /*
00490  *  Create action to follow a path towards another object.
00491  */
00492 
00493 Approach_actor_action::Approach_actor_action
00494   (
00495   PathFinder *p,      // Path to follow.
00496   Game_object *d      // Destination object.
00497   ) : Path_walking_actor_action(p, 0),  // (Stop if blocked.)
00498       dest_obj(d), orig_dest_pos(d->get_tile()), cur_step(0)
00499   {
00500           // Get length of path.
00501   int nsteps = path->get_num_steps();
00502   if (nsteps >= 6)    // (May have to play with this).
00503     check_step = nsteps > 18 ? 9 : nsteps/2;
00504   else
00505     check_step = 10000;
00506   }
00507 
00508 /*
00509  *  Handle a time event.
00510  *
00511  *  Output: 0 if done with this action, else delay for next frame.
00512  */
00513 
00514 int Approach_actor_action::handle_event
00515   (
00516   Actor *actor
00517   )
00518   {
00519   int delay = Path_walking_actor_action::handle_event(actor);
00520   if (!delay)     // Done or blocked.
00521     return 0;
00522   if (++cur_step == check_step) // Time to check.
00523     {
00524     if (dest_obj->get_tile().distance(orig_dest_pos) > 2)
00525       return 0; // Moved too much, so stop.
00526           // Figure next check.
00527     int nsteps = path->get_num_steps();
00528     if (nsteps >= 6)
00529       check_step += nsteps/2;
00530     }
00531   return delay;
00532   }
00533 
00534 /*
00535  *  Create if-then-else path.
00536  */
00537 
00538 If_else_path_actor_action::If_else_path_actor_action
00539   (
00540   Actor *actor,
00541   Tile_coord dest,
00542   Actor_action *s,
00543   Actor_action *f
00544   ) : Path_walking_actor_action(0, 6),  // Maxblk = 6.
00545     succeeded(false), failed(false), done(false),
00546     success(s), failure(f)
00547   {
00548   if (!walk_to_tile(actor, actor->get_tile(), dest))
00549     {
00550     done = failed = true;
00551     }
00552   }
00553 
00554 /*
00555  *  Delete.
00556  */
00557 
00558 If_else_path_actor_action::~If_else_path_actor_action
00559   (
00560   )
00561   {
00562   delete success;
00563   delete failure;
00564   }
00565 
00566 /*
00567  *  Set failure action.
00568  */
00569 
00570 void If_else_path_actor_action::set_failure
00571   (
00572   Actor_action *f
00573   )
00574   {
00575   delete failure;
00576   failure = f;
00577   done = false;     // So it gets executed.
00578   }
00579 
00580 /*
00581  *  Handle a time event.
00582  *
00583  *  Output: 0 if done with this action, else delay for next frame.
00584  */
00585 
00586 int If_else_path_actor_action::handle_event
00587   (
00588   Actor *actor
00589   )
00590   {
00591   if (done)
00592     return 0;   // Shouldn't really get here.
00593   bool del;
00594   int delay;
00595   if (succeeded)      // Doing the success action?
00596     {
00597     if ((delay = success->handle_event_safely(actor, del)) == 0 &&
00598         !del)
00599       done = true;
00600     return delay;
00601     }
00602   else if (failed)
00603     {
00604     if ((delay = failure->handle_event_safely(actor, del)) == 0 &&
00605         !del)
00606       done = true;
00607     return delay;
00608     }
00609   delay = Path_walking_actor_action::handle_event(actor);
00610   if (delay)
00611     return delay;
00612   if (!reached_end)
00613     {     // Didn't get there.
00614     if (failure)
00615       {
00616       failed = true;
00617 #if DEBUG
00618       cout << "Executing 'failure' path usecode" << endl;
00619 #endif
00620       delay = failure->handle_event_safely(actor, del);
00621       if (del)  // Are we gone?
00622         return 0;
00623       }
00624     }
00625   else        // Success.
00626     {
00627     if (success)
00628       {
00629       succeeded = true;
00630       delay = success->handle_event_safely(actor, del);
00631       if (del)  // Are we gone?
00632         return 0;
00633       }
00634     }
00635   if (!delay)
00636     done = true;    // All done now.
00637   return delay;
00638   }     
00639 
00640 /*
00641  *  Handle a time event.
00642  *
00643  *  Output: 0 if done with this action, else delay for next frame.
00644  */
00645 
00646 int Move_actor_action::handle_event
00647   (
00648   Actor *actor
00649   )
00650   {
00651   if (dest.tx < 0 || actor->get_tile() == dest)
00652     return (0);   // Done.
00653   actor->move(dest);    // Zip right there.
00654   Game_window *gwin = Game_window::get_instance();
00655   if (actor == gwin->get_main_actor())
00656           // Teleported Avatar?
00657     gwin->center_view(dest);
00658   dest.tx = -1;     // Set to stop.
00659   return (100);     // Wait 1/10 sec.
00660   }
00661 
00662 /*
00663  *  Handle a time event.
00664  *
00665  *  Output: 0 if done with this action, else delay for next frame.
00666  */
00667 
00668 int Activate_actor_action::handle_event
00669   (
00670   Actor *actor
00671   )
00672   {
00673   obj->activate();
00674   return 0;     // That's all.
00675   }
00676 
00677 /*
00678  *  Handle a time event.
00679  *
00680  *  Output: 0 if done with this action, else delay for next frame.
00681  */
00682 
00683 int Usecode_actor_action::handle_event
00684   (
00685   Actor *actor
00686   )
00687   {
00688   Game_window *gwin = Game_window::get_instance();
00689   gwin->get_usecode()->call_usecode(fun, item, 
00690       (Usecode_machine::Usecode_events) eventid);
00691   gwin->set_all_dirty();    // Clean up screen.
00692   return 0;     // That's all.
00693   }
00694 
00695 /*
00696  *  Create sequence of frames.
00697  */
00698 
00699 Frames_actor_action::Frames_actor_action
00700   (
00701   signed char *f,     // Frames.  -1 means don't change.
00702   int c,        // Count.
00703   int spd,      // Frame delay in 1/1000 secs.
00704   Game_object *o
00705   ) : cnt(c), index(0), speed(spd), obj(o)
00706   {
00707   frames = new signed char[cnt];
00708   std::memcpy(frames, f, cnt);
00709   }
00710 
00711 /*
00712  *  Handle a time event.
00713  *
00714  *  Output: 0 if done with this action, else delay for next frame.
00715  */
00716 
00717 int Frames_actor_action::handle_event
00718   (
00719   Actor *actor
00720   )
00721   {
00722   Game_object *o = obj;
00723   if (index == cnt)
00724     return (0);   // Done.
00725   int frnum = frames[index++];  // Get frame.
00726   if (frnum >= 0)
00727     {
00728     Game_window *gwin = Game_window::get_instance();
00729     if (o)
00730       o->change_frame(frnum);
00731     else
00732       actor->change_frame(frnum);
00733     }
00734   return (speed);
00735   }
00736 
00737 /*
00738  *  Create a sequence with up to 4 actions.
00739  */
00740 
00741 Sequence_actor_action::Sequence_actor_action
00742   (
00743   Actor_action *a0,   // (These will be deleted when done.)
00744   Actor_action *a1,
00745   Actor_action *a2,
00746   Actor_action *a3
00747   ) : index(0), speed(100)
00748   {
00749   actions = new Actor_action *[5];// Create list.
00750   actions[0] = a0;
00751   actions[1] = a1;
00752   actions[2] = a2;
00753   actions[3] = a3;
00754   actions[4] = 0;     // 0-delimit.
00755   }
00756 
00757 /*
00758  *  Delete.
00759  */
00760 
00761 Sequence_actor_action::~Sequence_actor_action
00762   (
00763   )
00764   {
00765   for (int i = 0; actions[i]; i++)
00766     delete actions[i];
00767   delete [] actions;
00768   }
00769 
00770 /*
00771  *  Handle a time event.
00772  *
00773  *  Output: 0 if done with this action, else delay for next frame.
00774  */
00775 
00776 int Sequence_actor_action::handle_event
00777   (
00778   Actor *actor
00779   )
00780   {
00781   if (!actions[index])    // Done?
00782     return (0);
00783           // Do current action.
00784   bool deleted;
00785   int delay = actions[index]->handle_event_safely(actor, deleted);
00786   if (deleted)
00787     return 0;   // We've been deleted!
00788   if (!delay)
00789     {
00790     index++;    // That one's done now.
00791     if (!speed)   // Immediately?  Run with next.
00792       return handle_event(actor);
00793     delay = speed;
00794     }
00795   return (delay);
00796   }
00797 
00798 /*
00799  *  Create object animator.
00800  */
00801 Object_animate_actor_action::Object_animate_actor_action
00802   (
00803   Game_object *o,
00804   int cy,       // # of cycles.
00805   int spd       // Time between frames.
00806   ) : obj(o), cycles(cy), speed(spd)
00807   {
00808   Game_window *gwin = Game_window::get_instance();
00809   nframes = obj->get_num_frames();
00810   }
00811 
00812 Object_animate_actor_action::Object_animate_actor_action
00813   (
00814   Game_object *o,
00815   int nfr,
00816   int cy,
00817   int spd
00818   ) : obj(o), nframes(nfr), cycles(cy), speed(spd) 
00819   { }
00820   
00821 
00822 /*
00823  *  Handle tick of the clock.
00824  */
00825 
00826 int Object_animate_actor_action::handle_event
00827   (
00828   Actor *actor
00829   )
00830   {
00831   if (!cycles) return 0;
00832   int frnum = (obj->get_framenum() + 1) % nframes;
00833   if (!frnum)     // New cycle?
00834     --cycles;
00835   obj->change_frame(frnum);
00836   return (cycles ? speed : 0);
00837   }
00838 
00839 /*
00840  *  Pick up/put down an object.
00841  */
00842 Pickup_actor_action::Pickup_actor_action(Game_object *o, int spd)
00843   : obj(o), pickup(1), speed(spd), cnt(0), 
00844     objpos(obj->get_tile()), dir(0)
00845   {
00846   }
00847           // To put down an object:
00848 Pickup_actor_action::Pickup_actor_action(Game_object *o, Tile_coord opos, 
00849                 int spd)
00850   : obj(o), pickup(0), speed(spd), cnt(0), objpos(opos), dir(0)
00851   {
00852   }
00853 
00854 /*
00855  *  Pick up an item (or put it down).
00856  */
00857 
00858 int Pickup_actor_action::handle_event
00859   (
00860   Actor *actor
00861   )
00862   {
00863   Game_window *gwin = Game_window::get_instance();
00864   int frnum = -1;
00865   switch (cnt)
00866     {
00867   case 0:       // Face object.
00868     dir = actor->get_direction(objpos);
00869     frnum = actor->get_dir_framenum(dir, Actor::standing);
00870     cnt++;
00871     break;
00872   case 1:       // Bend down.
00873     frnum = actor->get_dir_framenum(dir, Actor::bow_frame);
00874     cnt++;
00875     if (pickup)
00876       {
00877       if (actor->distance(obj) > 8)
00878         { // No longer nearby.
00879         actor->notify_object_gone(obj);
00880         break;
00881         }
00882       gwin->add_dirty(obj);
00883       obj->remove_this(1);
00884       actor->add(obj, 1);
00885       }
00886     else
00887       {
00888       obj->remove_this(1);
00889       obj->move(objpos);
00890       gwin->add_dirty(obj);
00891       }
00892     break;
00893   default:
00894     return 0;   // Done.
00895     }
00896   actor->change_frame(frnum);
00897   return speed;
00898   }
00899 
00900 /*
00901  *  Action to turn towards a position or an object.
00902  */
00903 
00904 Face_pos_actor_action::Face_pos_actor_action(Tile_coord p, int spd)
00905   : speed(spd), pos(p)
00906   {
00907   }
00908 Face_pos_actor_action::Face_pos_actor_action(Game_object *o, int spd)
00909   : speed(spd),
00910     pos(o->get_tile())
00911   {
00912   }
00913 
00914 /*
00915  *  Just turn to face a tile.
00916  */
00917 
00918 int Face_pos_actor_action::handle_event
00919   (
00920   Actor *actor
00921   )
00922   {
00923   Game_window *gwin = Game_window::get_instance();
00924   int dir = actor->get_direction(pos);
00925   int frnum = actor->get_dir_framenum(dir, Actor::standing);
00926   if (actor->get_framenum() == frnum)
00927     return 0;   // There.
00928   actor->change_frame(frnum);
00929   return speed;
00930   }
00931 

Generated on Mon Jul 9 14:42:39 2007 for ExultEngine by  doxygen 1.5.1