00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #ifdef HAVE_CONFIG_H
00022 # include <config.h>
00023 #endif
00024
00025 #include "gamewin.h"
00026 #include "gamemap.h"
00027 #include "gameclk.h"
00028 #include "actors.h"
00029 #include "effects.h"
00030 #include "Zombie.h"
00031 #include "dir.h"
00032 #include "chunks.h"
00033 #include "Audio.h"
00034 #include "Gump_manager.h"
00035 #include "game.h"
00036 #include "Gump.h"
00037 #include "egg.h"
00038
00039 #include "SDL_timer.h"
00040
00041 #ifndef UNDER_CE
00042 using std::cout;
00043 using std::endl;
00044 using std::rand;
00045 using std::string;
00046 using std::strlen;
00047 #endif
00048
00049 int Cloud::randcnt = 0;
00050 int Lightning_effect::active = 0;
00051
00052
00053
00054
00055
00056 Effects_manager::~Effects_manager()
00057 {
00058 remove_all_effects(false);
00059 }
00060
00061
00062
00063
00064
00065 void Effects_manager::add_text
00066 (
00067 const char *msg,
00068 Game_object *item
00069 )
00070 {
00071 if (!msg)
00072 return;
00073
00074 for (Text_effect *each = texts; each; each = each->next)
00075 if (each->is_text(item))
00076 return;
00077 Text_effect *txt = new Text_effect(msg, item);
00078
00079
00080 add_text_effect(txt);
00081 }
00082
00083
00084
00085
00086
00087 void Effects_manager::add_text
00088 (
00089 const char *msg,
00090 int x, int y
00091 )
00092 {
00093 Text_effect *txt = new Text_effect(msg,
00094 gwin->get_scrolltx() + x/c_tilesize,
00095 gwin->get_scrollty() + y/c_tilesize);
00096 add_text_effect(txt);
00097 }
00098
00099
00100
00101
00102
00103 void Effects_manager::center_text
00104 (
00105 const char *msg
00106 )
00107 {
00108 remove_text_effects();
00109 Shape_manager *sman = Shape_manager::get_instance();
00110 add_text(msg, (gwin->get_width()-sman->get_text_width(0,msg))/2,
00111 gwin->get_height()/2);
00112 }
00113
00114
00115
00116
00117
00118 void Effects_manager::add_effect
00119 (
00120 Special_effect *effect
00121 )
00122 {
00123 effect->next = effects;
00124 effect->prev = 0;
00125 if (effect->next)
00126 effect->next->prev = effect;
00127 effects = effect;
00128 }
00129
00130
00131
00132
00133
00134 void Effects_manager::add_text_effect
00135 (
00136 Text_effect *effect
00137 )
00138 {
00139 effect->next = texts;
00140 effect->prev = 0;
00141 if (effect->next)
00142 effect->next->prev = effect;
00143 texts = effect;
00144 }
00145
00146
00147
00148
00149
00150 void Effects_manager::remove_text_effect
00151 (
00152 Game_object *item
00153 )
00154 {
00155 for (Text_effect *each = texts; each; each = each->next)
00156 if (each->is_text(item))
00157 {
00158 remove_text_effect(each);
00159 gwin->paint();
00160 return;
00161 }
00162 }
00163
00164
00165
00166
00167
00168 void Effects_manager::remove_effect
00169 (
00170 Special_effect *effect
00171 )
00172 {
00173 if (effect->in_queue())
00174 gwin->get_tqueue()->remove(effect);
00175 if (effect->next)
00176 effect->next->prev = effect->prev;
00177 if (effect->prev)
00178 effect->prev->next = effect->next;
00179 else
00180 effects = effect->next;
00181 delete effect;
00182 }
00183
00184
00185
00186
00187
00188 void Effects_manager::remove_text_effect
00189 (
00190 Text_effect *txt
00191 )
00192 {
00193 if (txt->in_queue())
00194 gwin->get_tqueue()->remove(txt);
00195 if (txt->next)
00196 txt->next->prev = txt->prev;
00197 if (txt->prev)
00198 txt->prev->next = txt->next;
00199 else
00200 texts = txt->next;
00201 delete txt;
00202 }
00203
00204
00205
00206
00207
00208 void Effects_manager::remove_all_effects
00209 (
00210 bool repaint
00211 )
00212 {
00213 if (!effects && !texts)
00214 return;
00215 while (effects)
00216 remove_effect(effects);
00217 while (texts)
00218 remove_text_effect(texts);
00219 if (repaint)
00220 gwin->paint();
00221 }
00222
00223
00224
00225
00226
00227 void Effects_manager::remove_text_effects
00228 (
00229 )
00230 {
00231 while (texts)
00232 remove_text_effect(texts);
00233 gwin->set_all_dirty();
00234 }
00235
00236
00237
00238
00239
00240
00241 void Effects_manager::remove_weather_effects
00242 (
00243 int dist
00244
00245 )
00246 {
00247 Actor *main_actor = gwin->get_main_actor();
00248 Tile_coord apos = main_actor ? main_actor->get_tile()
00249 : Tile_coord(-1, -1, -1);
00250 Special_effect *each = effects;
00251 while (each)
00252 {
00253 Special_effect *next = each->next;
00254
00255 if (each->is_weather() && (!dist ||
00256 ((Weather_effect *) each)->out_of_range(apos, dist)))
00257 remove_effect(each);
00258 each = next;
00259 }
00260 gwin->set_all_dirty();
00261 }
00262
00263
00264
00265
00266
00267 int Effects_manager::get_weather
00268 (
00269 )
00270 {
00271 Special_effect *each = effects;
00272 while (each)
00273 {
00274 Special_effect *next = each->next;
00275 if (each->is_weather())
00276 {
00277 Weather_effect *weather = (Weather_effect *) each;
00278 if (weather->get_num() >= 0)
00279 return weather->get_num();
00280 }
00281 each = next;
00282 }
00283 return 0;
00284 }
00285
00286
00287
00288
00289
00290 void Effects_manager::paint
00291 (
00292 )
00293 {
00294 for (Special_effect *effect = effects; effect; effect = effect->next)
00295 effect->paint();
00296 }
00297
00298
00299
00300
00301
00302 void Effects_manager::paint_text
00303 (
00304 )
00305 {
00306 for (Text_effect *txt = texts; txt; txt = txt->next)
00307 txt->paint();
00308 }
00309
00310
00311
00312
00313
00314 void Special_effect::paint
00315 (
00316 )
00317 {
00318 }
00319
00320
00321
00322
00323
00324 Sprites_effect::Sprites_effect
00325 (
00326 int num,
00327 Tile_coord p,
00328 int dx, int dy,
00329 int delay
00330 ) : sprite(num, 0, SF_SPRITES_VGA), item(0), pos(p), xoff(0), yoff(0),
00331 deltax(dx), deltay(dy)
00332 {
00333 Game_window *gwin = Game_window::get_instance();
00334 frames = sprite.get_num_frames();
00335
00336 gwin->get_tqueue()->add(Game::get_ticks() + delay, this, 0L);
00337 }
00338
00339
00340
00341
00342
00343 Sprites_effect::Sprites_effect
00344 (
00345 int num,
00346 Game_object *it,
00347 int xf, int yf,
00348 int dx, int dy
00349 ) : sprite(num, 0, SF_SPRITES_VGA), item(it), xoff(xf),
00350 yoff(yf), deltax(dx), deltay(dy)
00351 {
00352 pos = item->get_tile();
00353 Game_window *gwin = Game_window::get_instance();
00354 frames = sprite.get_num_frames();
00355
00356 gwin->get_tqueue()->add(Game::get_ticks(), this, 0L);
00357 }
00358
00359
00360
00361
00362
00363 inline void Sprites_effect::add_dirty
00364 (
00365 int frnum
00366 )
00367 {
00368 if (pos.tx == -1 || frnum == -1)
00369 return;
00370 Shape_frame *shape = sprite.get_shape();
00371 int lp = pos.tz/2;
00372
00373 gwin->add_dirty(gwin->clip_to_win(gwin->get_shape_rect(shape,
00374 xoff + (pos.tx - lp - gwin->get_scrolltx())*c_tilesize,
00375 yoff + (pos.ty - lp -
00376 gwin->get_scrollty())*c_tilesize).enlarge(12)));
00377 }
00378
00379
00380
00381
00382
00383 void Sprites_effect::handle_event
00384 (
00385 unsigned long curtime,
00386 long udata
00387 )
00388 {
00389 int frame_num = sprite.get_framenum();
00390 Game_window *gwin = Game_window::get_instance();
00391 int delay = gwin->get_std_delay();
00392
00393 if (frame_num == frames)
00394 {
00395 eman->remove_effect(this);
00396 gwin->set_all_dirty();
00397 return;
00398 }
00399 add_dirty(frame_num);
00400 gwin->set_painted();
00401 if (item)
00402 pos = item->get_tile();
00403 xoff += deltax;
00404 yoff += deltay;
00405 frame_num++;
00406 add_dirty(frame_num);
00407 sprite.set_frame(frame_num);
00408
00409 gwin->get_tqueue()->add(curtime + delay, this, udata);
00410 }
00411
00412
00413
00414
00415
00416 void Sprites_effect::paint
00417 (
00418 )
00419 {
00420 if (sprite.get_framenum() >= frames)
00421 return;
00422 int lp = pos.tz/2;
00423 sprite.paint_shape(
00424 xoff + (pos.tx - lp - gwin->get_scrolltx())*c_tilesize,
00425 yoff + (pos.ty - lp - gwin->get_scrollty())*c_tilesize);
00426 }
00427
00428
00429
00430
00431
00432 Explosion_effect::Explosion_effect
00433 (
00434 Tile_coord p,
00435 Game_object *exp,
00436 int delay,
00437 int weap
00438
00439 ) : Sprites_effect(1, p, 0, 0, delay), explode(exp),
00440 weapon(weap >= 0 ? weap : 704)
00441 {
00442 if (exp && exp->get_shapenum() == 704) {
00443 exp->set_quality(1);
00444 }
00445 }
00446
00447
00448 void Explosion_effect::handle_event
00449 (
00450 unsigned long curtime,
00451 long udata
00452 )
00453 {
00454 int frnum = sprite.get_framenum();
00455 if (!frnum)
00456 {
00457 Tile_coord apos = gwin->get_main_actor()->get_tile();
00458 int dir = Get_direction16(apos.ty - pos.ty, pos.tx - apos.tx);
00459
00460 Audio::get_ptr()->play_sound_effect(
00461 Audio::game_sfx(9), SDL_MIX_MAXVOLUME, dir);
00462 }
00463 if (frnum == frames/4) {
00464
00465 if (explode && !explode->is_pos_invalid())
00466 {
00467 Game_window::get_instance()->add_dirty(explode);
00468 explode->remove_this();
00469 explode = 0;
00470 }
00471 Game_object_vector vec;
00472 Game_object::find_nearby(vec, pos, c_any_shapenum, 5, 0);
00473 for (Game_object_vector::const_iterator it = vec.begin(); it != vec.end(); ++it)
00474 {
00475 (**it).attacked(0, -704, 0);
00476 }
00477 }
00478 Sprites_effect::handle_event(curtime, udata);
00479 }
00480
00481
00482
00483
00484
00485 inline int Get_dir16
00486 (
00487 Tile_coord& t1,
00488 Tile_coord& t2
00489 )
00490 {
00491
00492 return Get_direction16(t1.ty - t2.ty, t2.tx - t1.tx);
00493 }
00494
00495
00496
00497
00498
00499 void Projectile_effect::init
00500 (
00501 Tile_coord s,
00502 Tile_coord d
00503 )
00504 {
00505 no_blocking = false;
00506 Game_window *gwin = Game_window::get_instance();
00507 Shape_info& info = ShapeID::get_info(projectile_shape);
00508 Weapon_info *winfo = info.get_weapon_info();
00509 if (winfo)
00510 {
00511 if (winfo->get_projectile())
00512 sprite.set_shape(winfo->get_projectile());
00513 no_blocking = no_blocking || winfo->no_blocking();
00514 }
00515 Ammo_info *ainfo = info.get_ammo_info();
00516 if (ainfo)
00517 no_blocking = no_blocking || ainfo->no_blocking();
00518 frames = sprite.get_num_frames();
00519 pos = s;
00520 if (attacker)
00521 {
00522 Shape_info& info = attacker->get_info();
00523
00524 pos.tz += info.get_3d_height() - 1;
00525 if (d.tx < pos.tx)
00526 pos.tx -= info.get_3d_xtiles();
00527 else
00528 pos.tx++;
00529 if (d.ty < pos.ty)
00530 pos.ty -= info.get_3d_ytiles();
00531 else
00532 pos.ty++;
00533 }
00534 path = new Zombie();
00535
00536 path->NewPath(pos, d, 0);
00537 if (frames >= 24)
00538 {
00539 int dir = Get_dir16(s, d);
00540 sprite.set_frame(8 + dir);
00541 }
00542 else if (frames == 1 && sprite.get_shapenum() != 704)
00543 sprite.set_frame(0);
00544 else
00545 sprite.set_frame(-1);
00546
00547 gwin->get_tqueue()->add(Game::get_ticks(), this, 0L);
00548 }
00549
00550
00551
00552
00553
00554
00555 Projectile_effect::Projectile_effect
00556 (
00557 Actor *att,
00558 Game_object *to,
00559 int shnum,
00560 int weap
00561 ) : attacker(att), target(to), projectile_shape(shnum),
00562 sprite(shnum, 0), weapon(weap),
00563 return_path(false)
00564 {
00565 init(attacker->get_tile(), to->get_tile());
00566 }
00567
00568
00569
00570
00571
00572 Projectile_effect::Projectile_effect
00573 (
00574 Tile_coord s,
00575 Tile_coord d,
00576 int shnum,
00577 int weap
00578 ) : attacker(0), target(0), projectile_shape(shnum),
00579 sprite(shnum, 0), weapon(weap),
00580 return_path(false)
00581 {
00582 init(s, d);
00583 }
00584
00585
00586
00587
00588
00589 Projectile_effect::Projectile_effect
00590 (
00591 Tile_coord s,
00592 Game_object *to,
00593 int shnum,
00594 int weap,
00595 bool retpath
00596 ) : attacker(0), target(to), projectile_shape(shnum),
00597 sprite(shnum, 0), weapon(weap),
00598 return_path(retpath)
00599 {
00600 init(s, to->get_tile());
00601 }
00602
00603
00604
00605
00606
00607 Projectile_effect::~Projectile_effect
00608 (
00609 )
00610 {
00611 delete path;
00612 }
00613
00614
00615
00616
00617
00618 inline void Projectile_effect::add_dirty
00619 (
00620 )
00621 {
00622 if (pos.tx == -1 || sprite.get_framenum() == -1)
00623 return;
00624 Shape_frame *shape = sprite.get_shape();
00625
00626 int liftpix = pos.tz*c_tilesize/2;
00627 gwin->add_dirty(gwin->clip_to_win(gwin->get_shape_rect(shape,
00628 (pos.tx - gwin->get_scrolltx())*c_tilesize - liftpix,
00629 (pos.ty - gwin->get_scrollty())*c_tilesize - liftpix).enlarge(4)));
00630 }
00631
00632
00633
00634
00635
00636
00637
00638 inline Game_object *Find_target
00639 (
00640 Game_window *gwin,
00641 Tile_coord pos
00642 )
00643 {
00644 if (pos.tz%5 == 0)
00645 pos.tz++;
00646 Tile_coord dest = pos;
00647 if (!Map_chunk::is_blocked(pos, 1, MOVE_FLY, 0) &&
00648 dest == pos)
00649 return (0);
00650 return Game_object::find_blocking(pos);
00651 }
00652
00653
00654
00655
00656
00657 void Projectile_effect::handle_event
00658 (
00659 unsigned long curtime,
00660 long udata
00661 )
00662 {
00663 Game_window *gwin = Game_window::get_instance();
00664 int delay = gwin->get_std_delay()/2;
00665 add_dirty();
00666 Tile_coord epos = pos;
00667 if (!path->GetNextStep(pos) ||
00668
00669 (!target && !no_blocking && (target = Find_target(gwin, pos)) != 0))
00670 {
00671 int delay = 0;
00672 switch (projectile_shape)
00673 {
00674 case 287:
00675 eman->add_effect(new Sprites_effect(23, epos));
00676 break;
00677 case 554:
00678 eman->add_effect(new Sprites_effect(19, epos));
00679 break;
00680 case 565:
00681 eman->add_effect(new Sprites_effect(18, epos));
00682 break;
00683 case 639:
00684 eman->add_effect(new Death_vortex(target, epos));
00685 target = 0;
00686 break;
00687 case 82:
00688 case 621:
00689 delay = 3000;
00690 case 78:
00691 case 702:
00692 case 704:
00693 eman->add_effect(new Explosion_effect(epos, 0, delay));
00694 target = 0;
00695 break;
00696 }
00697 if (return_path)
00698 target->add(gmap->create_ireg_object(weapon, 0));
00699 else
00700 {
00701 if (target && epos.distance(target->get_tile()) < 50)
00702 target->attacked(attacker, weapon,
00703 projectile_shape);
00704 if (attacker &&
00705 weapon == projectile_shape &&
00706 epos.distance(attacker->get_tile() ) < 50)
00707 {
00708 Weapon_info *winf =
00709 ShapeID::get_info(weapon).get_weapon_info();
00710 if (winf && winf->returns())
00711 eman->add_effect(new Projectile_effect(
00712 pos, attacker, weapon, weapon,
00713 true));
00714 }
00715 }
00716 add_dirty();
00717 pos.tx = -1;
00718 eman->remove_effect(this);
00719 return;
00720 }
00721 add_dirty();
00722
00723 gwin->get_tqueue()->add(curtime + delay, this, udata);
00724 }
00725
00726
00727
00728
00729
00730 void Projectile_effect::paint
00731 (
00732 )
00733 {
00734 if (pos.tx == -1 || sprite.get_framenum() == -1)
00735 return;
00736 int liftpix = pos.tz*c_tilesize/2;
00737 sprite.paint_shape(
00738 (pos.tx - gwin->get_scrolltx())*c_tilesize - liftpix,
00739 (pos.ty - gwin->get_scrollty())*c_tilesize - liftpix);
00740 }
00741
00742
00743
00744
00745
00746 Death_vortex::Death_vortex
00747 (
00748 Game_object *trg,
00749 Tile_coord tp
00750 ) : vortex(8, 0, SF_SPRITES_VGA), next_damage_time(0)
00751 {
00752 pos = trg ? trg->get_tile() : tp;
00753 target = trg ? trg->as_actor() : 0;
00754 Game_window *gwin = Game_window::get_instance();
00755 frames = vortex.get_num_frames();
00756
00757 stop_time = Game::get_ticks() + 20*1000;
00758
00759 gwin->get_tqueue()->add(Game::get_ticks(), this, 0L);
00760 }
00761
00762
00763
00764
00765
00766
00767
00768 inline int Death_vortex::add_dirty
00769 (
00770 )
00771 {
00772 Shape_frame *shape = vortex.get_shape();
00773 int liftpix = pos.tz*c_tilesize/2;
00774 gwin->add_dirty(gwin->clip_to_win(gwin->get_shape_rect(shape,
00775 (pos.tx - gwin->get_scrolltx())*c_tilesize - liftpix,
00776 (pos.ty - gwin->get_scrollty())*c_tilesize - liftpix).enlarge(4)));
00777 return shape->get_width();
00778 }
00779
00780
00781
00782
00783
00784 void Death_vortex::handle_event
00785 (
00786 unsigned long curtime,
00787 long udata
00788 )
00789 {
00790 Game_window *gwin = Game_window::get_instance();
00791 int width = add_dirty();
00792 if (target && !target->is_dead())
00793 {
00794 Tile_coord tpos = target->get_tile();
00795 int deltax = tpos.tx - pos.tx, deltay = tpos.ty - pos.ty;
00796 int absx = deltax >= 0 ? deltax : -deltax;
00797 int absy = deltay >= 0 ? deltay : -deltay;
00798 if (absx > 2 || absy > 2)
00799 {
00800 if (deltax)
00801 pos.tx += deltax/absx;
00802 if (deltay)
00803 pos.ty += deltay/absy;
00804 }
00805 }
00806 if (curtime > next_damage_time)
00807 {
00808 next_damage_time = curtime + 1000;
00809 Actor_vector npcs;
00810 Game_object::find_nearby(npcs, pos, -1, width/(2*c_tilesize),
00811 8);
00812 for (Actor_vector::const_iterator it = npcs.begin();
00813 it != npcs.end(); ++it)
00814 {
00815 Actor *npc = *it;
00816 if (!npc->is_in_party())
00817 npc->reduce_health(40);
00818 }
00819 }
00820 vortex.set_frame((vortex.get_framenum() + 1)%frames);
00821 add_dirty();
00822 if (curtime < stop_time)
00823 gwin->get_tqueue()->add(curtime + 100, this, udata);
00824 else
00825 {
00826 gwin->set_all_dirty();
00827 eman->remove_effect(this);
00828 }
00829 }
00830
00831
00832
00833
00834
00835 void Death_vortex::paint
00836 (
00837 )
00838 {
00839 int liftpix = pos.tz*c_tilesize/2;
00840 vortex.paint_shape(
00841 (pos.tx - gwin->get_scrolltx())*c_tilesize - liftpix,
00842 (pos.ty - gwin->get_scrollty())*c_tilesize - liftpix);
00843 }
00844
00845
00846
00847
00848
00849 static inline Tile_coord Figure_text_pos
00850 (
00851 Game_object *item
00852 )
00853 {
00854 Game_window *gwin = Game_window::get_instance();
00855 Gump_manager *gumpman = gwin->get_gump_man();
00856 Rectangle box;
00857
00858 Gump *gump = gumpman->find_gump(item);
00859 if (gump)
00860 box = gump->get_shape_rect(item);
00861 else
00862 box = gwin->get_shape_rect(item->get_outermost());
00863 return Tile_coord(gwin->get_scrolltx() + box.x/c_tilesize,
00864 gwin->get_scrollty() + box.y/c_tilesize, 0);
00865 }
00866
00867
00868
00869
00870
00871 void Text_effect::add_dirty
00872 (
00873 )
00874 {
00875 Game_window *gwin = Game_window::get_instance();
00876
00877 Rectangle rect((pos.tx - gwin->get_scrolltx() - 1)*c_tilesize,
00878 (pos.ty - gwin->get_scrollty() - 1)*c_tilesize,
00879 width + 2*c_tilesize, height + 2*c_tilesize);
00880 gwin->add_dirty(gwin->clip_to_win(rect));
00881 }
00882
00883
00884
00885
00886
00887 void Text_effect::init
00888 (
00889 )
00890 {
00891 set_always(true);
00892
00893 Game_window *gwin = Game_window::get_instance();
00894 width = 8 + sman->get_text_width(0, msg.c_str());
00895 height = 8 + sman->get_text_height(0);
00896 add_dirty();
00897
00898 gwin->get_tqueue()->add(Game::get_ticks(), this, 0L);
00899 if (msg[0] == '@')
00900 msg[0] = '"';
00901 int len = msg.size();
00902 if (msg[len - 1] == '@')
00903 msg[len - 1] = '"';
00904 }
00905
00906
00907
00908
00909
00910 Text_effect::Text_effect
00911 (
00912 const string &m,
00913 Game_object *it
00914 ) : msg(m), item(it), pos(Figure_text_pos(it)), num_ticks(0)
00915 {
00916 init();
00917 }
00918
00919
00920
00921
00922
00923 Text_effect::Text_effect
00924 (
00925 const string &m,
00926 int t_x, int t_y
00927 ) : msg(m), item(0), pos(t_x, t_y, 0), num_ticks(0)
00928 {
00929 init();
00930 }
00931
00932
00933
00934
00935
00936 void Text_effect::handle_event
00937 (
00938 unsigned long curtime,
00939 long udata
00940 )
00941 {
00942 Game_window *gwin = Game_window::get_instance();
00943 if (++num_ticks == 10)
00944 {
00945 add_dirty();
00946 eman->remove_text_effect(this);
00947 return;
00948 }
00949
00950 gwin->get_tqueue()->add(Game::get_ticks() + gwin->get_std_delay(),
00951 this, 0L);
00952 if (!item)
00953 return;
00954
00955 Tile_coord npos = Figure_text_pos(item);
00956 if (npos == pos)
00957 return;
00958 add_dirty();
00959 pos = npos;
00960 add_dirty();
00961 }
00962
00963
00964
00965
00966
00967 void Text_effect::paint
00968 (
00969 )
00970 {
00971 const char *ptr = msg.c_str();
00972 int len = strlen(ptr);
00973 sman->paint_text(0, ptr, len,
00974 (pos.tx - gwin->get_scrolltx())*c_tilesize,
00975 (pos.ty - gwin->get_scrollty())*c_tilesize);
00976 }
00977
00978
00979
00980
00981
00982 Weather_effect::Weather_effect
00983 (
00984 int duration,
00985 int delay,
00986 int n,
00987 Game_object *egg
00988 ) : num(n)
00989 {
00990 Game_window *gwin = Game_window::get_instance();
00991 if (egg)
00992 eggloc = egg->get_tile();
00993 else
00994 eggloc = Tile_coord(-1, -1, -1);
00995 stop_time = Game::get_ticks() + delay + 1000*((duration*60)/time_factor);
00996
00997 gwin->get_tqueue()->add(Game::get_ticks() + delay, this, 0L);
00998 }
00999
01000
01001
01002
01003
01004 int Weather_effect::out_of_range
01005 (
01006 Tile_coord& avpos,
01007 int dist
01008 )
01009 {
01010 if (eggloc.tx == -1)
01011 return 0;
01012 return eggloc.distance(avpos) >= dist;
01013 }
01014
01015
01016
01017
01018
01019 inline void Raindrop::paint
01020 (
01021 Image_window8 *iwin,
01022 int scrolltx, int scrollty,
01023 Xform_palette& xform
01024 )
01025 {
01026 uint32 ascrollx = scrolltx*(uint32)c_tilesize,
01027 ascrolly = scrollty*(uint32)c_tilesize;
01028 int x = ax - ascrollx, y = ay - ascrolly;
01029 if (x < 0 || y < 0 ||
01030 x >= iwin->get_width() || y >= iwin->get_height())
01031 return;
01032 if (oldpix == 255)
01033 oldpix = iwin->get_pixel8(x, y);
01034 iwin->put_pixel8(xform[oldpix], x, y);
01035 }
01036
01037
01038
01039
01040
01041 inline void Raindrop::next
01042 (
01043 Image_window8 *iwin,
01044 int scrolltx, int scrollty,
01045 Xform_palette& xform,
01046 int w, int h
01047 )
01048 {
01049 uint32 ascrollx = scrolltx*(uint32)c_tilesize,
01050 ascrolly = scrollty*(uint32)c_tilesize;
01051 int x = ax - ascrollx, y = ay - ascrolly;
01052
01053 if (x >= 0 && y >= 0 && x < w && y < h && oldpix != 255)
01054 iwin->put_pixel8(oldpix, x, y);
01055 oldpix = 255;
01056
01057
01058 if (x < 0 || x >= w || y < 0 || y >= h)
01059 {
01060 int r = rand();
01061
01062 yperx = (r%4) ? 1 : 2;
01063 ax = ascrollx + r%(w - w/8);
01064 ay = ascrolly + r%(h - h/4);
01065 }
01066 else
01067 {
01068 int delta = 1 + rand()%4;
01069 ax += delta;
01070 ay += delta + yperx;
01071 }
01072
01073 paint(iwin, scrolltx, scrollty, xform);
01074 }
01075
01076
01077
01078
01079
01080 inline void Raindrop::next_random
01081 (
01082 Image_window8 *iwin,
01083 int scrolltx, int scrollty,
01084 Xform_palette& xform,
01085 int w, int h
01086 )
01087 {
01088 uint32 ascrollx = scrolltx*(uint32)c_tilesize,
01089 ascrolly = scrollty*(uint32)c_tilesize;
01090 int x = ax - ascrollx, y = ay - ascrolly;
01091
01092 if (x >= 0 && y >= 0 && x < w && y < h && oldpix != 255)
01093 iwin->put_pixel8(oldpix, x, y);
01094 oldpix = 255;
01095
01096 int newx = rand()%w, newy = rand()%h;
01097 ax = ascrollx + newx;
01098 ay = ascrolly + newy;
01099
01100 paint(iwin, scrolltx, scrollty, xform);
01101 }
01102
01103
01104
01105
01106
01107 void Rain_effect::handle_event
01108 (
01109 unsigned long curtime,
01110 long udata
01111 )
01112 {
01113 Game_window *gwin = Game_window::get_instance();
01114 if (!gwin->is_main_actor_inside() &&
01115 !gumpman->showing_gumps(true))
01116 {
01117 Image_window8 *win = gwin->get_win();
01118 int w = win->get_width(), h = win->get_height();
01119
01120 Xform_palette& xform = sman->get_xform(8);
01121 int scrolltx = gwin->get_scrolltx(),
01122 scrollty = gwin->get_scrollty();
01123
01124 for (int i = 0; i < num_drops; i++)
01125 drops[i].next(win, scrolltx, scrollty, xform, w, h);
01126 gwin->set_painted();
01127 }
01128 if (curtime < stop_time)
01129 gwin->get_tqueue()->add(curtime + 100, this, udata);
01130 else
01131 {
01132 gwin->set_all_dirty();
01133 eman->remove_effect(this);
01134 }
01135 }
01136
01137
01138
01139
01140
01141 void Rain_effect::paint
01142 (
01143 )
01144 {
01145 if (gwin->is_main_actor_inside())
01146 return;
01147
01148 Xform_palette& xform = sman->get_xform(8);
01149 int scrolltx = gwin->get_scrolltx(),
01150 scrollty = gwin->get_scrollty();
01151 Image_window8 *win = gwin->get_win();
01152 for (int i = 0; i < num_drops; i++)
01153 drops[i].paint(win, scrolltx, scrollty, xform);
01154 gwin->set_painted();
01155 }
01156
01157
01158
01159
01160
01161 Lightning_effect::~Lightning_effect
01162 (
01163 )
01164 {
01165 if (flashing)
01166 Game_window::get_instance()->get_clock()->set_palette();
01167 }
01168
01169
01170
01171
01172
01173 void Lightning_effect::handle_event
01174 (
01175 unsigned long curtime,
01176 long udata
01177 )
01178 {
01179 Game_window *gwin = Game_window::get_instance();
01180 int r = rand();
01181 int delay = 100;
01182 if (flashing)
01183 {
01184 gclock->set_palette();
01185 flashing = false;
01186 active = false;
01187 if (curtime >= stop_time)
01188 {
01189 eman->remove_effect(this);
01190 return;
01191 }
01192 if (r%5 == 0)
01193 delay = (1 + r%7)*40;
01194 else
01195 delay = (4000 + r%3000);
01196 }
01197 else if (!gwin->is_in_dungeon() && !active)
01198 {
01199
01200 Audio::get_ptr()->play_sound_effect(Audio::game_sfx(62));
01201 active = true;
01202 flashing = true;
01203 gwin->get_pal()->set(PALETTE_LIGHTNING);
01204 delay = (1 + r%2)*25;
01205 }
01206 gwin->get_tqueue()->add(curtime + delay, this, udata);
01207 }
01208
01209
01210
01211
01212
01213 Storm_effect::Storm_effect
01214 (
01215 int duration,
01216 int delay,
01217 Game_object *egg
01218 ) : Weather_effect(duration, delay, 2, egg), start(1)
01219 {
01220 Game_window *gwin = Game_window::get_instance();
01221
01222 int rain_delay = 20 + rand()%1000;
01223 eman->add_effect(new Rain_effect(duration - 1, rain_delay));
01224 int lightning_delay = rain_delay + rand()%500;
01225 eman->add_effect(new Lightning_effect(duration - 1, lightning_delay));
01226 }
01227
01228
01229
01230
01231 void Storm_effect::handle_event
01232 (
01233 unsigned long curtime,
01234 long udata
01235 )
01236 {
01237 Game_window *gwin = Game_window::get_instance();
01238 if (start)
01239 {
01240 start = 0;
01241
01242 gwin->get_clock()->set_storm(true);
01243
01244 gwin->get_tqueue()->add(stop_time, this, udata);
01245 }
01246 else
01247 eman->remove_effect(this);
01248 }
01249
01250
01251
01252
01253
01254 Storm_effect::~Storm_effect
01255 (
01256 )
01257 {
01258 Game_window *gwin = Game_window::get_instance();
01259
01260 gwin->get_clock()->set_storm(false);
01261 }
01262
01263
01264
01265
01266
01267 void Sparkle_effect::handle_event
01268 (
01269 unsigned long curtime,
01270 long udata
01271 )
01272 {
01273 Game_window *gwin = Game_window::get_instance();
01274 if (!gwin->is_main_actor_inside())
01275 {
01276 Image_window8 *win = gwin->get_win();
01277 int w = win->get_width(), h = win->get_height();
01278
01279 Xform_palette& xform = sman->get_xform(8);
01280 int scrolltx = gwin->get_scrolltx(),
01281 scrollty = gwin->get_scrollty();
01282
01283 for (int i = 0; i < num_drops; i++)
01284 drops[i].next_random(win, scrolltx, scrollty,
01285 xform, w, h);
01286 gwin->set_painted();
01287 }
01288 if (curtime < stop_time)
01289 gwin->get_tqueue()->add(curtime + 100, this, udata);
01290 else
01291 {
01292 gwin->set_all_dirty();
01293 eman->remove_effect(this);
01294 }
01295 }
01296
01297
01298
01299
01300
01301 const int CLOUD = 2;
01302
01303 Cloud::Cloud
01304 (
01305 short dx, short dy
01306 ) : cloud(CLOUD, 0, SF_SPRITES_VGA), wx(0), wy(0), deltax(dx), deltay(dy), count(-1)
01307 {
01308 Game_window *gwin = Game_window::get_instance();
01309
01310 int adx = deltax > 0 ? deltax : -deltax;
01311 int ady = deltay > 0 ? deltay : -deltay;
01312 if (adx < ady)
01313 max_count = 2*gwin->get_height()/ady;
01314 else
01315 max_count = 2*gwin->get_width()/adx;
01316 start_time = 0;
01317 }
01318
01319
01320
01321
01322
01323 void Cloud::set_start_pos
01324 (
01325 Shape_frame *shape,
01326 int w, int h,
01327 int& x, int& y
01328 )
01329 {
01330 if (!deltax)
01331 {
01332 x = rand()%w;
01333 y = deltay > 0 ? -shape->get_ybelow() :
01334 h + shape->get_yabove();
01335 return;
01336 }
01337 if (!deltay)
01338 {
01339 y = rand()%h;
01340 x = deltax > 0 ? -shape->get_xright() : w + shape->get_xleft();
01341 return;
01342 }
01343 int halfp = w + h;
01344 int r = rand()%halfp;
01345 if (r > h)
01346 {
01347 x = r - h;
01348 y = deltay > 0 ? -shape->get_ybelow() :
01349 h + shape->get_yabove();
01350 return;
01351 }
01352 y = r;
01353 if (deltax > 0)
01354 x = -shape->get_xright();
01355 else
01356 x = w + shape->get_xleft();
01357 }
01358
01359
01360
01361
01362
01363 inline void Cloud::next
01364 (
01365 Game_window *gwin,
01366 unsigned long curtime,
01367 int w, int h
01368 )
01369 {
01370 if (curtime < start_time)
01371 return;
01372
01373 long scrollx = gwin->get_scrolltx()*c_tilesize;
01374 long scrolly = gwin->get_scrollty()*c_tilesize;
01375 Shape_frame *shape = cloud.get_shape();
01376 gwin->add_dirty(gwin->clip_to_win(gwin->get_shape_rect(
01377 shape, wx - scrollx, wy - scrolly).enlarge(4)));
01378 if (count <= 0)
01379 {
01380
01381 start_time = curtime + 2000*randcnt + rand()%2000;
01382 randcnt = (randcnt + 1)%4;
01383 start_time = Game::get_ticks() + 2000*randcnt + rand()%500;
01384 cout << "Cloud: start_time = " << start_time << endl;
01385 count = max_count;
01386 cloud.set_frame(rand()%cloud.get_num_frames());
01387 int x, y;
01388 set_start_pos(shape, w, h, x, y);
01389 wx = x + scrollx;
01390 wy = y + scrolly;
01391 }
01392 else
01393 {
01394 wx += deltax;
01395 wy += deltay;
01396 count--;
01397 }
01398 gwin->add_dirty(gwin->clip_to_win(gwin->get_shape_rect(
01399 shape, wx - scrollx, wy - scrolly).enlarge(4)));
01400 }
01401
01402
01403
01404
01405
01406 void Cloud::paint
01407 (
01408 )
01409 {
01410 Game_window *gwin = Game_window::get_instance();
01411 if (count > 0)
01412 cloud.paint_shape(wx - gwin->get_scrolltx()*c_tilesize,
01413 wy - gwin->get_scrollty()*c_tilesize);
01414 }
01415
01416
01417
01418
01419
01420 Clouds_effect::Clouds_effect
01421 (
01422 int duration,
01423 int delay,
01424 Game_object *egg
01425 ) : Weather_effect(duration, delay, 6, egg)
01426 {
01427 num_clouds = 2 + rand()%5;
01428 clouds = new Cloud *[num_clouds];
01429
01430 int dx = rand()%5 - 2;
01431 int dy = rand()%5 - 2;
01432 if (!dx && !dy)
01433 {
01434 dx = 1 + rand()%2;
01435 dy = 1 - rand()%3;
01436 }
01437 for (int i = 0; i < num_clouds; i++)
01438 {
01439 int deltax = dx, deltay = dy;
01440 if (rand()%2 == 0)
01441 {
01442 deltax += deltax/2;
01443 deltay += deltay/2;
01444 }
01445 clouds[i] = new Cloud(deltax, deltay);
01446 }
01447 }
01448
01449
01450
01451
01452
01453 void Clouds_effect::handle_event
01454 (
01455 unsigned long curtime,
01456 long udata
01457 )
01458 {
01459 const int delay = 100;
01460 Game_window *gwin = Game_window::get_instance();
01461 if (curtime >= stop_time)
01462 {
01463 eman->remove_effect(this);
01464 gwin->set_all_dirty();
01465 return;
01466 }
01467 int w = gwin->get_width(), h = gwin->get_height();
01468 for (int i = 0; i < num_clouds; i++)
01469 clouds[i]->next(gwin, curtime, w, h);
01470 gwin->get_tqueue()->add(curtime + delay, this, udata);
01471 }
01472
01473
01474
01475
01476
01477 void Clouds_effect::paint
01478 (
01479 )
01480 {
01481 if (!gwin->is_main_actor_inside())
01482 for (int i = 0; i < num_clouds; i++)
01483 clouds[i]->paint();
01484 }
01485
01486
01487
01488
01489
01490 void Earthquake::handle_event
01491 (
01492 unsigned long curtime,
01493 long udata
01494 )
01495 {
01496 static int eqsoundonce;
01497
01498 if(eqsoundonce != 1)
01499 {
01500 eqsoundonce = 1;
01501
01502 Audio::get_ptr()->play_sound_effect(Audio::game_sfx(60));
01503 }
01504
01505 Game_window *gwin = Game_window::get_instance();
01506 Image_window *win = gwin->get_win();
01507 int w = win->get_width(), h = win->get_height();
01508 int sx = 0, sy = 0;
01509 int dx = rand()%9 - 4;
01510 int dy = rand()%9 - 4;
01511 if (dx > 0)
01512 w -= dx;
01513 else
01514 {
01515 w += dx;
01516 sx -= dx;
01517 dx = 0;
01518 }
01519 if (dy > 0)
01520 h -= dy;
01521 else
01522 {
01523 h += dy;
01524 sy -= dy;
01525 dy = 0;
01526 }
01527 win->copy(sx, sy, w, h, dx, dy);
01528 gwin->set_painted();
01529 gwin->show();
01530
01531 win->copy(dx, dy, w, h, sx, sy);
01532 if (++i < len)
01533 gwin->get_tqueue()->add(curtime + 100, this, udata);
01534 else
01535 {
01536 eqsoundonce = 0;
01537 delete this;
01538 }
01539
01540 }
01541
01542
01543
01544
01545
01546 Fire_field_effect::Fire_field_effect
01547 (
01548 Tile_coord t
01549 )
01550 {
01551 field = gmap->create_ireg_object(895, 0);
01552 field->set_flag(Obj_flags::is_temporary);
01553 field->move(t.tx, t.ty, t.tz);
01554 gwin->get_tqueue()->add(Game::get_ticks() + 3000 + rand()%2000, this,
01555 0L);
01556 }
01557
01558
01559
01560
01561
01562 void Fire_field_effect::handle_event
01563 (
01564 unsigned long curtime,
01565 long udata
01566 )
01567 {
01568 int frnum = field->get_framenum();
01569 if (frnum == 0)
01570 {
01571 field->remove_this();
01572 eman->remove_effect(this);
01573 }
01574 else
01575 {
01576 if (frnum > 3)
01577 {
01578 ((Animated_egg_object *) field)->stop_animation();
01579 frnum = 3;
01580 }
01581 else
01582 frnum--;
01583 gwin->add_dirty(field);
01584 field->set_frame(frnum);
01585 gwin->get_tqueue()->add(curtime + gwin->get_std_delay(),
01586 this, udata);
01587 }
01588 }
01589