00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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"
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
00053
00054 class Object_sfx : public Game_singletons
00055 {
00056 int sfxnum;
00057 int sfx;
00058 Game_object *obj;
00059 int distance;
00060 int dir;
00061 public:
00062
00063 Object_sfx(int snum, Game_object *o) : sfxnum(snum), distance(0), sfx(-1)
00064 { set_obj(o); }
00065
00066
00067 int get_sfxnum()
00068 { return sfxnum; }
00069 int get_distance()
00070 { return distance; }
00071 void set_obj(Game_object *o);
00072 void stop(Game_object *o)
00073 {
00074 if (o == obj)
00075 if(sfx >= 0)
00076 {
00077 Mix_HaltChannel(sfx);
00078 sfx = -1;
00079 }
00080 }
00081
00082 static int get_shape_sfx(int shapenum);
00083 static void play(Game_object *o, int snum, bool stop = false);
00084 };
00085
00086
00087
00088
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;
00103 obj = o;
00104 dir = 0;
00105 bool repeat = true;
00106 distance = new_distance;
00107 int volume = MIX_MAX_VOLUME;
00108 if (distance)
00109 {
00110 volume = (MIX_MAX_VOLUME*64)/(distance*distance);
00111 if (!volume)
00112 repeat = false;
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)
00120 {
00121
00122
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
00129 {
00130
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
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)
00157 {
00158 first = 0;
00159
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
00176 table[334] = 56;
00177 table[335] = 56;
00178 table[780] = 56;
00179
00180 table[893] = 36;
00181
00182 table[776] = 77;
00183 table[777] = 77;
00184 if (GAME_BG)
00185 {
00186 table[305] = 78;
00187 table[786] = 79;
00188 }
00189
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;
00198 table[695] = 116;
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
00213
00214
00215 void Object_sfx::play
00216 (
00217 Game_object *o,
00218 int snum,
00219 bool stop
00220 )
00221 {
00222
00223 static map<int, Object_sfx*> play_table;
00224
00225 std::map<int, Object_sfx*>::iterator it = play_table.find(snum);
00226 if (it == play_table.end())
00227 {
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);
00239 }
00240
00241
00242
00243
00244
00245 Animator *Animator::create
00246 (
00247 Game_object *ob
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())
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
00264
00265
00266 Animator::~Animator
00267 (
00268 )
00269 {
00270 while (gwin->get_tqueue()->remove(this))
00271 ;
00272 }
00273
00274
00275
00276
00277
00278 void Animator::start_animation
00279 (
00280 )
00281 {
00282
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
00290
00291
00292 int Animator::get_framenum()
00293 {
00294 return obj->get_framenum();
00295 }
00296
00297
00298
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
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
00324 if (Game::get_game_type() == SERPENT_ISLE)
00325 {
00326 switch (last_shape)
00327 {
00328
00329 case 284:
00330 type = FA_SUNDIAL;
00331 break;
00332
00333 case 768:
00334 type = FA_ENERGY_FIELD;
00335 created = Game::get_ticks();
00336 first_frame = last_frame;
00337 break;
00338
00339 case 153:
00340 case 184:
00341 case 222:
00342 case 289:
00343 case 305:
00344 case 326:
00345 case 456:
00346 case 614:
00347 case 655:
00348 case 695:
00349 case 726:
00350 case 743:
00351 case 794:
00352 case 992:
00353 first_frame = 6*(last_frame/6);
00354 frames = 6;
00355 created = last_frame%6;
00356 break;
00357
00358 case 779:
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:
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:
00380 case 714:
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
00400 else
00401 {
00402 switch (last_shape)
00403 {
00404
00405 case 284:
00406 type = FA_SUNDIAL;
00407 break;
00408
00409 case 768:
00410 type = FA_ENERGY_FIELD;
00411 created = Game::get_ticks();
00412 first_frame = last_frame;
00413 break;
00414
00415
00416 case 862:
00417 case 880:
00418 case 933:
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
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
00477
00478
00479 void Frame_animator::handle_event
00480 (
00481 unsigned long curtime,
00482 long udata
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 {
00497 animating = 0;
00498
00499 Object_sfx::play(obj, sfxnum, true);
00500 return;
00501 }
00502
00503 if (!framenum && sfxnum >= 0)
00504 Object_sfx::play(obj, sfxnum);
00505
00506 if (animating)
00507 {
00508
00509 gwin->get_tqueue()->add(ticks + delay- (ticks%delay), this, udata);
00510 }
00511 }
00512
00513
00514
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
00526
00527
00528 void Sfx_animator::handle_event
00529 (
00530 unsigned long curtime,
00531 long udata
00532 )
00533 {
00534 const int delay = 200;
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 {
00541 animating = 0;
00542
00543 Object_sfx::play(obj, sfxnum, true);
00544 return;
00545 }
00546
00547 if (sfxnum >= 0)
00548 Object_sfx::play(obj, sfxnum);
00549
00550 if (animating)
00551
00552 gwin->get_tqueue()->add(ticks + delay- (ticks%delay),
00553 this, udata);
00554 }
00555
00556
00557
00558
00559
00560 Field_frame_animator::Field_frame_animator
00561 (
00562 Game_object *o,
00563 int rcy
00564 ) : Animator(o), recycle(rcy), activated(true)
00565 {
00566 int shapenum = obj->get_shapenum();
00567 frames = obj->get_num_frames();
00568 }
00569
00570
00571
00572
00573
00574 void Field_frame_animator::handle_event
00575 (
00576 unsigned long curtime,
00577 long udata
00578 )
00579 {
00580 int delay = 100;
00581 Game_window *gwin = (Game_window *) udata;
00582 if (!gwin->add_dirty(obj))
00583 {
00584 animating = 0;
00585 return;
00586 }
00587 int framenum = obj->get_framenum() + 1;
00588 if (framenum == frames)
00589 framenum = recycle;
00590 obj->set_frame(framenum);
00591 gwin->add_dirty(obj);
00592
00593 if (animating)
00594 gwin->get_tqueue()->add(curtime + delay, this, udata);
00595 if (activated && rand()%10 == 0)
00596 obj->activate(0);
00597 }
00598
00599
00600
00601
00602
00603 void Wiggle_animator::handle_event
00604 (
00605 unsigned long curtime,
00606 long udata
00607 )
00608 {
00609 int delay = 100;
00610 Game_window *gwin = (Game_window *) udata;
00611 if (!gwin->add_dirty(obj))
00612 {
00613 animating = 0;
00614 return;
00615 }
00616 Tile_coord t = obj->get_tile();
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
00625 if (animating)
00626 gwin->get_tqueue()->add(curtime + delay, this, udata);
00627 }
00628
00629
00630
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
00646
00647
00648 Animated_object::~Animated_object
00649 (
00650 )
00651 {
00652 delete animator;
00653 }
00654
00655
00656
00657
00658
00659 void Animated_object::paint
00660 (
00661 )
00662 {
00663 animator->want_animation();
00664 Game_object::paint();
00665 }
00666
00667
00668
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
00684
00685
00686 Animated_ireg_object::~Animated_ireg_object
00687 (
00688 )
00689 {
00690 delete animator;
00691 }
00692
00693
00694
00695
00696
00697 void Animated_ireg_object::paint
00698 (
00699 )
00700 {
00701 animator->want_animation();
00702 Ireg_game_object::paint();
00703 }
00704
00705
00706
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
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
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
00743
00744
00745 Animated_ifix_object::~Animated_ifix_object
00746 (
00747 )
00748 {
00749 delete animator;
00750 }
00751
00752
00753
00754
00755
00756 void Animated_ifix_object::paint
00757 (
00758 )
00759 {
00760 animator->want_animation();
00761 Ifix_game_object::paint();
00762 }
00763
00764
00765
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