animate.cc

Go to the documentation of this file.
00001 
00007 /*
00008 Copyright (C) 2000  Jeffrey S. Freedman
00009 
00010 This program is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU General Public License
00012 as published by the Free Software Foundation; either version 2
00013 of the License, or (at your option) any later version.
00014 
00015 This program is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00023 */
00024 
00025 #ifdef HAVE_CONFIG_H
00026 #  include <config.h>
00027 #endif
00028 
00029 #include "animate.h"
00030 #include "gamewin.h"
00031 #include "game.h"
00032 #include "gameclk.h"
00033 #include "Audio.h"
00034 #include "actors.h"     /* Only need this for Object_sfx. */
00035 #include "dir.h"
00036 #include "Flex.h"
00037 #include <map>
00038 #include <string>
00039 
00040 #ifndef UNDER_CE
00041 using std::map;
00042 using std::ostream;
00043 using std::rand;
00044 using std::endl;
00045 using std::cout;
00046 #endif
00047 
00048 
00049 
00050 
00051 /*
00052  *  A class for playing sound effects when certain objects are nearby.
00053  */
00054 class Object_sfx : public Game_singletons
00055   {
00056   int sfxnum;     // Sound effect #.
00057   int sfx;      // ID of sound effect being played.
00058   Game_object *obj;   // Object that caused the sound.
00059   int distance;     // Distance in tiles from Avatar.
00060   int dir;      // Direction (0-15) from Avatar.
00061 public:
00062           // Create & start playing sound.
00063   Object_sfx(int snum, Game_object *o) : sfxnum(snum), distance(0), sfx(-1)
00064     { set_obj(o); }
00065 //  bool is_active()    // Is sound still active?
00066 //    { return sfx.is_active(); }
00067   int get_sfxnum()
00068     { return sfxnum; }
00069   int get_distance()
00070     { return distance; }
00071   void set_obj(Game_object *o); // Set to new object.
00072   void stop(Game_object *o) // Stop if from given object.
00073     {
00074     if (o == obj)
00075       if(sfx >= 0)
00076         {
00077         Mix_HaltChannel(sfx);
00078         sfx = -1;
00079         }
00080     }
00081           // Get sfx to play for given shape.
00082   static int get_shape_sfx(int shapenum);
00083   static void play(Game_object *o, int snum, bool stop = false);
00084   };
00085 
00086 /*
00087  *  Set to new object if it's closer than the old object, or we're
00088  *  inactive.
00089  */
00090 void Object_sfx::set_obj
00091   (
00092   Game_object *o
00093   )
00094   {
00095   Tile_coord apos = gwin->get_main_actor()->get_tile();
00096   Tile_coord opos = o->get_tile();
00097   int active = 0;
00098   if(sfx != -1)
00099     active = Mix_Playing(sfx);
00100   int new_distance = apos.distance(opos);
00101   if (active && new_distance >= distance && o != obj)
00102     return;     // Farther than current source.
00103   obj = o;
00104   dir = 0;
00105   bool repeat = true;
00106   distance = new_distance;
00107   int volume = MIX_MAX_VOLUME;  // Set volume based on distance.
00108   if (distance)
00109     {     // 160/8 = 20 tiles. 20*20=400.
00110     volume = (MIX_MAX_VOLUME*64)/(distance*distance);
00111     if (!volume)    // Dead?
00112       repeat = false; // Time to kill it.
00113     if (volume < 8)
00114       volume = 8;
00115     else if (volume > MIX_MAX_VOLUME)
00116       volume = MIX_MAX_VOLUME;
00117     dir = Get_direction16(apos.ty - opos.ty, opos.tx - apos.tx);
00118     }
00119   if (sfx == -1)    // First time?
00120     { 
00121 
00122           // Start playing, and repeat.
00123     sfx = Audio::get_ptr()->play_sound_effect(sfxnum, MIX_MAX_VOLUME, dir, -1);
00124     if(sfx >= 0)
00125 
00126       Mix_Volume(sfx, volume);
00127     }
00128   else        // Set new volume, position.
00129     {
00130     //Just change the "location" of the sound
00131     if(!repeat)
00132       {
00133       Mix_HaltChannel(sfx);
00134       sfx = -1;
00135       }
00136     else
00137       {
00138       Mix_Volume(sfx, volume);
00139       Mix_SetPosition(sfx, (dir * 22), 0);
00140       }
00141     }
00142   }
00143 
00144 /*
00145  *  Get the sound-effect # for a given shape, or -1 if not found.
00146  */
00147 
00148 int Object_sfx::get_shape_sfx
00149   (
00150   int shapenum
00151   )
00152   {
00153   static map<int, int> table;
00154   static int first = 1;
00155 
00156   if (first)      // First time?
00157     {
00158     first = 0;
00159           // Surf: (47 or 49)
00160     table[612] = 49;
00161     table[613] = 49;
00162     table[632] = 49;
00163     table[736] = 49;
00164     table[737] = 49;
00165     table[751] = 49;
00166     table[808] = 49;
00167     table[834] = 49;
00168     table[875] = 49;
00169     table[907] = 49;
00170     table[911] = 49;
00171     table[918] = 49;
00172     table[1012] = 49;
00173     table[1020] = 49;
00174     table[1022] = 49;
00175           // Bubbles: (54, 56).
00176     table[334] = 56;
00177     table[335] = 56;
00178     table[780] = 56;
00179           // Fountains:
00180     table[893] = 36;
00181           // Moongates:
00182     table[776] = 77;
00183     table[777] = 77;
00184     if (GAME_BG)
00185       {
00186       table[305] = 78;  // Black gate.
00187       table[786] = 79;  // Vortex cube.
00188       }
00189     // Grandfather clock tick tock, only in the SQSFX files,
00190      if (Audio::get_ptr()->get_sfx_file() != 0)
00191       {
00192       std::string s = 
00193         Audio::get_ptr()->get_sfx_file()->filename;
00194       to_uppercase(s);
00195       if(s.find("SQSFX") != std::string::npos)
00196         {
00197         table[252] = 116; // Grandfather clock 
00198         table[695] = 116; // Grandfather clock 
00199         }
00200       } 
00201         
00202     }
00203   std::map<int, int>::iterator it = table.find(shapenum);
00204   if (it == table.end())
00205     return -1;
00206   int sfx = (*it).second;
00207   return Audio::game_sfx(sfx);
00208   return sfx;
00209   }
00210 
00211 /*
00212  *  Play a sound, or modify its volume/position.
00213  */
00214 
00215 void Object_sfx::play
00216   (
00217   Game_object *o,     // Object.
00218   int snum,     // Object's sound-effect #.
00219   bool stop     // Time to stop.
00220   )
00221   {
00222           // Play a given sfx only once.
00223   static map<int, Object_sfx*> play_table;
00224           // Already playing?
00225   std::map<int, Object_sfx*>::iterator it = play_table.find(snum);
00226   if (it == play_table.end()) // No.
00227     {     // Start new SFX for it.
00228     if (!stop)
00229       play_table[snum] = new Object_sfx(snum, o);
00230     return;
00231     }
00232   Object_sfx *sfx = (*it).second;
00233   if (stop)
00234   {
00235     sfx->stop(o);
00236   }
00237   else
00238     sfx->set_obj(o);  // Modify/restart.
00239   }
00240 
00241 /*
00242  *  Create appropriate animator.
00243  */
00244 
00245 Animator *Animator::create
00246   (
00247   Game_object *ob     // Animated object.
00248   )
00249   {
00250   int shnum = ob->get_shapenum();
00251   int frames = ob->get_num_frames();
00252   Shape_info& info = ob->get_info();
00253   if (!info.is_animated())  // Assume it's just SFX.
00254     return new Sfx_animator(ob);
00255   else if (frames > 1)
00256     return new Frame_animator(ob);
00257   else
00258     return new Wiggle_animator(ob);
00259   }
00260 
00261 
00262 /*
00263  *  When we delete, better remove from queue.
00264  */
00265 
00266 Animator::~Animator
00267   (
00268   )
00269   {
00270   while (gwin->get_tqueue()->remove(this))
00271     ;
00272   }
00273 
00274 /*
00275  *  Start animation.
00276  */
00277 
00278 void Animator::start_animation
00279   (
00280   )
00281   {
00282           // Clean out old entry if there.
00283   gwin->get_tqueue()->remove(this);
00284   gwin->get_tqueue()->add(Game::get_ticks() + 20, this, (long) gwin);
00285   animating = 1;
00286   }
00287 
00288 /*
00289  *  Retrieve current frame
00290  */
00291 
00292 int Animator::get_framenum()
00293 {
00294   return obj->get_framenum();
00295 }
00296 
00297 /*
00298  *  Create a frame animator.
00299  */
00300 
00301 Frame_animator::Frame_animator
00302   (
00303   Game_object *o
00304   ) : Animator(o, Object_sfx::get_shape_sfx(o->get_shapenum()))
00305 {
00306   Initialize();
00307 }
00308 
00309 /*
00310  *  Initialize a frame animator.
00311  */
00312 void Frame_animator::Initialize()
00313 {
00314   first_frame = 0;
00315   created = 0;
00316   delay = 100;
00317   type = FA_LOOPING;
00318 
00319   last_shape = obj->get_shapenum();
00320   last_frame = obj->get_framenum();
00321   frames = obj->get_num_frames();
00322 
00323   // Serpent Isle
00324   if (Game::get_game_type() == SERPENT_ISLE)
00325   {
00326     switch (last_shape)
00327     {
00328     
00329     case 284:   // Sundial is a special case.
00330       type = FA_SUNDIAL;
00331       break;
00332     
00333     case 768:   // Energy field.  Stop at top.
00334       type = FA_ENERGY_FIELD;
00335       created = Game::get_ticks();
00336       first_frame = last_frame;
00337       break;
00338     
00339     case 153:   // Fountain
00340     case 184:   // Lava
00341     case 222:   // Pennant
00342     case 289:   // Fire 
00343     case 305:   // Serpent Statue
00344     case 326:   // Fountain
00345     case 456:   // Flux Analyzer
00346     case 614:   // Magic music box
00347     case 655:   // Planets 
00348     case 695:   // Grandfather clock
00349     case 726:   // Pulsating Object
00350     case 743:   // Statue??
00351     case 794:   // Severed limb
00352     case 992:   // Burning urn
00353       first_frame = 6*(last_frame/6);
00354       frames = 6;
00355       created = last_frame%6;
00356       break;
00357 
00358     case 779:   // Magic Wave.
00359       first_frame = 6*(last_frame/6);
00360       frames = 6;
00361       if (last_frame < 6) created = 1;
00362       else created = 0;
00363       break;
00364 
00365     case 335:   // Bubbles
00366       created = last_frame;
00367       if (last_frame < 6)
00368       {
00369         first_frame = 0;
00370         frames = 6;
00371       }
00372       else
00373       {
00374         first_frame = 6;
00375         frames = frames-6;
00376       }
00377       break;
00378 
00379     case 322:   // Basin
00380     case 714:   // Basin
00381       created = last_frame;
00382       if (last_frame != frames-1)
00383       {
00384         first_frame = 0;
00385         frames = frames - 1;
00386       }
00387       else
00388       {
00389         first_frame = frames -1;
00390         frames = 1;
00391       }
00392       break;
00393 
00394 
00395     default:
00396       break;
00397     }
00398   }
00399   // Black Gate
00400   else
00401   {
00402     switch (last_shape)
00403     {
00404     
00405     case 284:   // Sundial is a special case.
00406       type = FA_SUNDIAL;
00407       break;
00408     
00409     case 768:   // Energy field.  Stop at top.
00410       type = FA_ENERGY_FIELD;
00411       created = Game::get_ticks();
00412       first_frame = last_frame;
00413       break;
00414     
00415           // First frame isn't animated
00416     case 862:   // Shafts
00417     case 880:
00418     case 933:   // Millsaw
00419       if (last_frame == 0)
00420       {
00421         first_frame = 0;
00422         frames = 1;
00423       }
00424       else
00425       {
00426         frames = frames -1;
00427         first_frame = 1;
00428       }
00429       break;
00430 
00431     default:
00432       break;
00433     }
00434   }
00435 }
00436 
00437 /*
00438  *  Retrieve current frame
00439  */
00440 
00441 int Frame_animator::get_framenum()
00442 {
00443   unsigned int ticks = Game::get_ticks();
00444   int framenum = 0;
00445 
00446   if (last_shape != obj->get_shapenum() || last_frame != obj->get_framenum())
00447     Initialize();
00448 
00449   bool dirty_first = gwin->add_dirty(obj);
00450 
00451   if (last_shape != obj->get_shapenum() || last_frame != obj->get_framenum())
00452     Initialize();
00453 
00454   switch (type)
00455   {
00456   case FA_SUNDIAL:
00457     framenum = gclock->get_hour() % frames;  
00458     break;
00459 
00460   case FA_ENERGY_FIELD:
00461     framenum = (ticks - created) / delay + first_frame;
00462     if (framenum >= frames) framenum = frames-1;
00463     break;
00464 
00465   case FA_LOOPING:
00466     framenum = (ticks / delay) + created;
00467     framenum %= frames;
00468     framenum += first_frame;
00469     break;
00470   }
00471 
00472   return framenum;
00473 }
00474 
00475 /*
00476  *  Animation.
00477  */
00478 
00479 void Frame_animator::handle_event
00480   (
00481   unsigned long curtime,    // Current time of day.
00482   long udata      // Game window.
00483   )
00484 {
00485   unsigned int ticks = Game::get_ticks();
00486 
00487   Game_window *gwin = (Game_window *) udata;
00488 
00489   bool dirty_first = gwin->add_dirty(obj);
00490 
00491   int framenum = get_framenum();
00492 
00493   obj->set_frame(last_frame = framenum);
00494 
00495   if (!dirty_first && !gwin->add_dirty(obj))
00496   {       // No longer on screen.
00497     animating = 0;
00498           // Stop playing sound.
00499     Object_sfx::play(obj, sfxnum, true);
00500     return;
00501   }
00502 
00503   if (!framenum && sfxnum >= 0) // Sound effect?
00504     Object_sfx::play(obj, sfxnum);
00505           // Add back to queue for next time.
00506   if (animating)
00507   {
00508     // Ensure all animations are synced
00509     gwin->get_tqueue()->add(ticks  + delay- (ticks%delay), this, udata);
00510   }
00511 }
00512 
00513 /*
00514  *  Create a pure SFX player.
00515  */
00516 
00517 Sfx_animator::Sfx_animator
00518   (
00519   Game_object *o
00520   ) : Animator(o, Object_sfx::get_shape_sfx(o->get_shapenum()))
00521 {
00522 }
00523 
00524 /*
00525  *  Play SFX.
00526  */
00527 
00528 void Sfx_animator::handle_event
00529   (
00530   unsigned long curtime,    // Current time of day.
00531   long udata      // Game window.
00532   )
00533 {
00534   const int delay = 200;    // Guessing this will be enough.
00535   unsigned int ticks = Game::get_ticks();
00536 
00537   Game_window *gwin = (Game_window *) udata;
00538   Rectangle rect = gwin->clip_to_win(gwin->get_shape_rect(obj));
00539   if (rect.w <= 0 || rect.h <= 0)
00540   {       // No longer on screen.
00541     animating = 0;
00542           // Stop playing sound.
00543     Object_sfx::play(obj, sfxnum, true);
00544     return;
00545   }
00546 
00547   if (sfxnum >= 0)    // Sound effect?
00548     Object_sfx::play(obj, sfxnum);
00549           // Add back to queue for next time.
00550   if (animating)
00551     // Ensure all animations are synced
00552     gwin->get_tqueue()->add(ticks  + delay- (ticks%delay), 
00553                 this, udata);
00554 }
00555 
00556 /*
00557  *  Create a field frame animator.
00558  */
00559 
00560 Field_frame_animator::Field_frame_animator
00561   (
00562   Game_object *o,
00563   int rcy       // Frame to start recycling at.
00564   ) : Animator(o), recycle(rcy), activated(true)
00565   {
00566   int shapenum = obj->get_shapenum();
00567   frames = obj->get_num_frames();
00568   }
00569 
00570 /*
00571  *  Animation.
00572  */
00573 
00574 void Field_frame_animator::handle_event
00575   (
00576   unsigned long curtime,    // Current time of day.
00577   long udata      // Game window.
00578   )
00579   {
00580   int delay = 100;    // Delay between frames.
00581   Game_window *gwin = (Game_window *) udata;
00582   if (!gwin->add_dirty(obj))
00583     {     // No longer on screen.
00584     animating = 0;
00585     return;
00586     }
00587   int framenum = obj->get_framenum() + 1;
00588   if (framenum == frames)
00589     framenum = recycle; // Restart cycle here.
00590   obj->set_frame(framenum);
00591   gwin->add_dirty(obj);
00592           // Add back to queue for next time.
00593   if (animating)
00594     gwin->get_tqueue()->add(curtime + delay, this, udata);
00595   if (activated && rand()%10 == 0)// Check for damage?
00596     obj->activate(0);
00597   }
00598 
00599 /*
00600  *  Animation.
00601  */
00602 
00603 void Wiggle_animator::handle_event
00604   (
00605   unsigned long curtime,    // Current time of day.
00606   long udata      // Game window.
00607   )
00608   {
00609   int delay = 100;    // Delay between frames.
00610   Game_window *gwin = (Game_window *) udata;
00611   if (!gwin->add_dirty(obj))
00612     {     // No longer on screen.
00613     animating = 0;
00614     return;
00615     }
00616   Tile_coord t = obj->get_tile(); // Get current position.
00617   int newdx = rand()%3;
00618   int newdy = rand()%3;
00619   t.tx += -deltax + newdx;
00620   t.ty += -deltay + newdy;
00621   deltax = newdx;
00622   deltay = newdy;
00623   obj->Game_object::move(t.tx, t.ty, t.tz);
00624           // Add back to queue for next time.
00625   if (animating)
00626     gwin->get_tqueue()->add(curtime + delay, this, udata);
00627   }
00628 
00629 /*
00630  *  Create at given position.
00631  */
00632 
00633 Animated_object::Animated_object
00634   (
00635   int shapenum, 
00636   int framenum, 
00637   unsigned int tilex, unsigned int tiley, 
00638   unsigned int lft
00639   ) : Terrain_game_object(shapenum, framenum, tilex, tiley, lft)
00640   {
00641   animator = Animator::create(this);
00642   }
00643 
00644 /*
00645  *  When we delete, better remove from queue.
00646  */
00647 
00648 Animated_object::~Animated_object
00649   (
00650   )
00651   {
00652   delete animator;
00653   }
00654 
00655 /*
00656  *  Render.
00657  */
00658 
00659 void Animated_object::paint
00660   (
00661   )
00662   {
00663   animator->want_animation(); // Be sure animation is on.
00664   Game_object::paint();
00665   }
00666 
00667 /*
00668  *  Create at given position.
00669  */
00670 
00671 Animated_ireg_object::Animated_ireg_object
00672   (
00673   int shapenum, 
00674   int framenum, 
00675   unsigned int tilex, unsigned int tiley, 
00676   unsigned int lft
00677   ) : Ireg_game_object(shapenum, framenum, tilex, tiley, lft)
00678   {
00679   animator = Animator::create(this);
00680   }
00681 
00682 /*
00683  *  When we delete, better remove from queue.
00684  */
00685 
00686 Animated_ireg_object::~Animated_ireg_object
00687   (
00688   )
00689   {
00690   delete animator;
00691   }
00692 
00693 /*
00694  *  Render.
00695  */
00696 
00697 void Animated_ireg_object::paint
00698   (
00699   )
00700   {
00701   animator->want_animation(); // Be sure animation is on.
00702   Ireg_game_object::paint();
00703   }
00704 
00705 /*
00706  *  Write out.
00707  */
00708 
00709 void Animated_ireg_object::write_ireg(DataSource *out)
00710 {
00711   int oldframe = get_framenum();
00712   set_frame(animator->get_framenum());
00713   Ireg_game_object::write_ireg(out);
00714   set_frame(oldframe);
00715 }
00716 
00717 /*
00718  *  Create at given position.
00719  */
00720 
00721 Animated_ifix_object::Animated_ifix_object
00722   (
00723   int shapenum, 
00724   int framenum, 
00725   unsigned int tilex, unsigned int tiley, 
00726   unsigned int lft
00727   ) : Ifix_game_object(shapenum, framenum, tilex, tiley, lft)
00728   {
00729   animator = Animator::create(this);
00730   }
00731 
00732 /*
00733  *  Create from IFIX
00734  */
00735 
00736 Animated_ifix_object::Animated_ifix_object(unsigned char *ifix) : Ifix_game_object(ifix)
00737   {
00738   animator = Animator::create(this);
00739   }
00740 
00741 /*
00742  *  When we delete, better remove from queue.
00743  */
00744 
00745 Animated_ifix_object::~Animated_ifix_object
00746   (
00747   )
00748   {
00749   delete animator;
00750   }
00751 
00752 /*
00753  *  Render.
00754  */
00755 
00756 void Animated_ifix_object::paint
00757   (
00758   )
00759   {
00760   animator->want_animation(); // Be sure animation is on.
00761   Ifix_game_object::paint();
00762   }
00763 
00764 /*
00765  *  Write out an IFIX object.
00766  */
00767 
00768 void Animated_ifix_object::write_ifix(DataSource *ifix)
00769 
00770 {
00771   int oldframe = get_framenum();
00772   set_frame(animator->get_framenum());
00773   Ifix_game_object::write_ifix(ifix);
00774   set_frame(oldframe);
00775 }
00776 
00777 

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