mouse.cc

Go to the documentation of this file.
00001 /*
00002  *  mouse.cc - Mouse pointers.
00003  *
00004  *  Copyright (C) 2000-2002  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 "SDL_mouse.h"
00026 #include "SDL_timer.h"
00027 #include "mouse.h"
00028 #include "gamewin.h"
00029 #include "fnames.h"
00030 #include "Gump.h"
00031 #include "Gump_manager.h"
00032 #include "barge.h"
00033 #include "actors.h"
00034 #include "cheat.h"
00035 #include "combat_opts.h"
00036 #include "combat.h"
00037 #include "schedule.h" /* To get Schedule::combat */
00038 
00039 #ifndef _MSC_VER
00040 using std::max;
00041 #endif
00042 
00043 short Mouse::short_arrows[8] = {8, 9, 10, 11, 12, 13, 14, 15};
00044 short Mouse::med_arrows[8] = {16, 17, 18, 19, 20, 21, 22, 23};
00045 short Mouse::long_arrows[8] = {24, 25, 26, 27, 28, 29, 30, 31};
00046 
00047 short Mouse::short_combat_arrows[8] = {32, 33, 34, 35, 36, 37, 38, 39};
00048 short Mouse::med_combat_arrows[8] = {40, 41, 42, 43, 44, 45, 46, 47};
00049 
00050 Mouse* Mouse::mouse = 0;
00051 bool Mouse::mouse_update = false;
00052 
00053 /*
00054  *  Create.
00055  */
00056 
00057 Mouse::Mouse
00058   (
00059   Game_window *gw     // Where to draw.
00060   ) : gwin(gw), iwin(gwin->get_win()),backup(0),box(0,0,0,0),dirty(0,0,0,0), cur_framenum(0),cur(0),avatar_speed(100*gwin->get_std_delay()/slow_speed_factor)
00061 {
00062   SDL_GetMouseState(&mousex, &mousey);
00063   mousex /= gwin->get_fastmouse() ? 1 : iwin->get_scale();
00064   mousey /= gwin->get_fastmouse() ? 1 : iwin->get_scale();
00065   if (is_system_path_defined("<PATCH>") && U7exists(PATCH_POINTERS))
00066     pointers.load(PATCH_POINTERS);
00067   else
00068     pointers.load(POINTERS);
00069   Init();
00070   set_shape(get_short_arrow(east));   // +++++For now.
00071 }
00072   
00073 Mouse::Mouse
00074   (
00075   Game_window *gw,    // Where to draw.
00076   DataSource &shapes
00077   ) : gwin(gw), iwin(gwin->get_win()),backup(0),box(0,0,0,0),dirty(0,0,0,0),cur_framenum(0),cur(0),avatar_speed(100*gwin->get_std_delay()/slow_speed_factor)
00078 {
00079   SDL_GetMouseState(&mousex, &mousey);
00080   mousex /= gwin->get_fastmouse() ? 1 : iwin->get_scale();
00081   mousey /= gwin->get_fastmouse() ? 1 : iwin->get_scale();
00082   pointers.load(&shapes);
00083   Init();
00084   set_shape0(0);
00085 }
00086   
00087 void Mouse::Init()
00088 {
00089   int cnt = pointers.get_num_frames();
00090   int maxleft = 0, maxright = 0, maxabove = 0, maxbelow = 0;
00091   for (int i = 0; i < cnt; i++)
00092   {
00093     Shape_frame *frame = pointers.get_frame(i);
00094     int xleft = frame->get_xleft(), xright = frame->get_xright();
00095     int yabove = frame->get_yabove(), ybelow = frame->get_ybelow();
00096     if (xleft > maxleft)
00097       maxleft = xleft;
00098     if (xright > maxright)
00099       maxright = xright;
00100     if (yabove > maxabove)
00101       maxabove = yabove;
00102     if (ybelow > maxbelow)
00103       maxbelow = ybelow;
00104   }
00105   int maxw = maxleft + maxright, maxh = maxabove + maxbelow;
00106           // Create backup buffer.
00107   backup = iwin->create_buffer(maxw, maxh);
00108   box.w = maxw;
00109   box.h = maxh;
00110   
00111   onscreen = 0;                   // initially offscreen
00112 }
00113 
00114 /*
00115  *  Delete.
00116  */
00117 
00118 Mouse::~Mouse
00119   (
00120   )
00121 {
00122   delete backup;
00123 }
00124 
00125 /*
00126  *  Show the mouse.
00127  */
00128 
00129 void Mouse::show
00130   (
00131   )
00132 {
00133   if (!onscreen)
00134   {
00135     onscreen = 1;
00136           // Save background.
00137     iwin->get(backup, box.x, box.y);
00138           // Paint new location.
00139 //    cur->paint_rle(iwin->get_ib8(), mousex, mousey);
00140     cur->paint_rle(mousex, mousey);
00141   }
00142 }
00143 
00144 /*
00145  *  Move cursor
00146  */
00147 
00148 void Mouse::move(int x, int y) {
00149   bool warp = false;
00150   if (x >= gwin->get_width()) {
00151     x = gwin->get_width() - 1;
00152     warp = true;
00153   }
00154   if (y >= gwin->get_height()) {
00155     y = gwin->get_height() - 1;
00156     warp = true;
00157   }
00158   if (warp)
00159     SDL_WarpMouse(x, y);
00160 #ifdef DEBUG
00161   if (onscreen)
00162     std::cerr << "Trying to move mouse while onscreen!" << std::endl;
00163 #endif
00164   // Shift to new position.
00165   box.shift(x - mousex, y - mousey);
00166   dirty = dirty.add(box); // Enlarge dirty area.
00167   mousex = x;
00168   mousey = y;
00169 }
00170 
00171 /*
00172  *  Set to new shape.  Should be called after checking that frame #
00173  *  actually changed.
00174  */
00175 
00176 void Mouse::set_shape0
00177   (
00178   int framenum
00179   )
00180 {
00181   cur_framenum = framenum;
00182   cur = pointers.get_frame(framenum); 
00183   while (!cur)      // For newly-created games.
00184     cur = pointers.get_frame(--framenum);
00185           // Set backup box to cover mouse.
00186   box.x = mousex - cur->get_xleft();
00187   box.y = mousey - cur->get_yabove();
00188   dirty = dirty.add(box);   // Update dirty area.
00189 }
00190 
00191 /*
00192  *  Set to an arbitrary location.
00193  */
00194 
00195 void Mouse::set_location
00196   (
00197   int x, int y      // Mouse position.
00198   )
00199 {
00200   mousex = x;
00201   mousey = y;
00202   box.x = mousex - cur->get_xleft();
00203   box.y = mousey - cur->get_yabove();
00204 }
00205 
00206 /*
00207  *  Flash a desired shape for about 1/2 second.
00208  */
00209 
00210 void Mouse::flash_shape
00211   (
00212   Mouse_shapes flash
00213   )
00214 {
00215   Mouse_shapes saveshape = get_shape();
00216   hide();
00217   set_shape(flash);
00218   show();
00219   gwin->show(1);
00220   SDL_Delay(600);
00221   hide();
00222   gwin->paint();
00223   set_shape(saveshape);
00224   gwin->set_painted();
00225 }
00226 
00227 
00228 /*
00229  *  Set default cursor
00230  */
00231 
00232 void Mouse::set_speed_cursor()
00233 {
00234   Game_window *gwin = Game_window::get_instance();
00235   Gump_manager *gump_man = gwin->get_gump_man();
00236    
00237   int cursor = dontchange;
00238   int ax, ay;     // Get Avatar/barge screen location.
00239 
00240     // Check if we are in dont_move mode, in this case display the hand cursor
00241   if (gwin->main_actor_dont_move())
00242           cursor = hand;
00243       /* Can again, optionally move in gump mode. */
00244   else if (gump_man->gump_mode()) {
00245     if (gump_man->gumps_dont_pause_game())
00246     {
00247         Gump *gump = gump_man->find_gump(mousex, mousey);
00248         
00249       if (gump && !gump->no_handcursor())
00250         cursor = hand;
00251     }
00252     else cursor = hand;
00253   }
00254 
00255   else if (gwin->get_dragging_gump()) cursor = hand;
00256 
00257     else if (cheat.in_map_editor()) 
00258     {
00259   switch (cheat.get_edit_mode())
00260   {
00261   case Cheat::move:
00262       cursor = hand; break;
00263   case Cheat::paint:
00264       cursor = short_combat_arrows[4]; break; // Short S red arrow.
00265   case Cheat::paint_chunks:
00266       cursor = med_combat_arrows[0]; break; // Med. N red arrow.
00267 #if 0
00268   case Cheat::select:
00269       cursor = short_arrows[7]; break;    // Short NW green.
00270   case Cheat::hide:
00271       cursor = redx; break;
00272 #endif
00273   case Cheat::combo_pick:
00274       cursor = greenselect; break;
00275   }
00276     }
00277     else if (Combat::is_paused())
00278   cursor = short_combat_arrows[0];  // Short N red arrow.
00279     if (cursor == dontchange)
00280     {
00281         Barge_object *barge = gwin->get_moving_barge();
00282         if (barge)
00283         {     // Use center of barge.
00284             gwin->get_shape_location(barge, ax, ay);
00285             ax -= barge->get_xtiles()*(c_tilesize/2);
00286             ay -= barge->get_ytiles()*(c_tilesize/2);
00287         }
00288         else        
00289             gwin->get_shape_location(gwin->get_main_actor(), ax, ay);
00290     
00291         int dy = ay - mousey, dx = mousex - ax;
00292         Direction dir = Get_direction(dy, dx);
00293   Rectangle gamewin_dims = gwin->get_win_rect();
00294   float speed_section = max( max( -static_cast<float>(dx)/ax, static_cast<float>(dx)/(gamewin_dims.w-ax)), max(static_cast<float>(dy)/ay, -static_cast<float>(dy)/(gamewin_dims.h-ay)) );
00295 
00296   /* If there is a hostile NPC nearby, the avatar isn't allowed to
00297    * move very fast
00298    * Note that the range at which this occurs in the original is
00299    * less than the "potential target" range- that is, if I go into
00300    * combat mode, even when I'm allowed to run at full speed,
00301    * I'll sometime charge off to kill someone "too far away"
00302    * to affect a speed limit.
00303    * I don't know whether this is taken into account by 
00304    * get_nearby_npcs, but on the other hand, its a negligible point.
00305    */
00306   Actor_queue nearby;
00307   if (!cheat.in_god_mode())
00308     gwin->get_nearby_npcs( nearby );
00309 
00310   bool nearby_hostile = false;
00311   for( Actor_queue::const_iterator it = nearby.begin(); it != nearby.end(); ++it ) {
00312     Actor *actor = *it;
00313 
00314     if( !actor->is_dead() && actor->get_schedule() &&
00315       actor->get_alignment() >= Npc_actor::hostile && 
00316         actor->get_schedule_type() == Schedule::combat && 
00317       static_cast<Combat_schedule*>(actor->get_schedule())->
00318             has_started_battle())
00319     {
00320       /* TODO- I think invisibles still trigger the
00321        * slowdown, verify this. */
00322       nearby_hostile = true;
00323       break; /* No need to bother checking the rest :P */
00324     }
00325   }
00326 
00327         if( speed_section < 0.4 )
00328         {
00329             if( gwin->in_combat() )
00330                 cursor = get_short_combat_arrow( dir );
00331             else
00332                 cursor = get_short_arrow( dir );
00333             avatar_speed = 100*gwin->get_std_delay()/slow_speed_factor;
00334         }
00335         else if( speed_section < 0.8 || gwin->in_combat() || nearby_hostile )
00336         {
00337             if( gwin->in_combat() )
00338                 cursor = get_medium_combat_arrow( dir );
00339             else
00340                 cursor = get_medium_arrow( dir );
00341             if( gwin->in_combat() || nearby_hostile )
00342                 avatar_speed = 100*gwin->get_std_delay()/medium_combat_speed_factor;
00343             else
00344                 avatar_speed = 100*gwin->get_std_delay()/medium_speed_factor;
00345         }
00346         else /* Fast - NB, we can't get here in combat mode; there is no
00347               * long combat arrow, nor is there a fast combat speed. */
00348         {           
00349       cursor = get_long_arrow( dir );
00350             avatar_speed = 100*gwin->get_std_delay()/fast_speed_factor;
00351         }
00352     }
00353     
00354     if (cursor != dontchange)
00355         set_shape(cursor);
00356 }

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