00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifdef HAVE_CONFIG_H
00021 # include <config.h>
00022 #endif
00023
00024 #include "Audio.h"
00025 #include "monsters.h"
00026 #include "cheat.h"
00027 #include "chunks.h"
00028 #include "animate.h"
00029 #include "effects.h"
00030 #include "egg.h"
00031 #include "exult.h"
00032 #include "game.h"
00033 #include "gameclk.h"
00034 #include "gamewin.h"
00035 #include "gamemap.h"
00036 #include "npctime.h"
00037 #include "paths.h"
00038 #include "ucmachine.h"
00039 #include "ucscriptop.h"
00040 #include "ucsched.h"
00041 #include "Gump_manager.h"
00042
00043 #ifdef USE_EXULTSTUDIO
00044 #include "server.h"
00045 #include "objserial.h"
00046 #include "mouse.h"
00047 #include "servemsg.h"
00048 #endif
00049
00050 #ifndef UNDER_CE
00051 using std::cout;
00052 using std::endl;
00053 using std::rand;
00054 using std::ostream;
00055 #endif
00056
00057 Egg_object *Egg_object::editing = 0;
00058
00059
00060
00061
00062 class Missile_launcher : public Time_sensitive, public Game_singletons
00063 {
00064 Egg_object *egg;
00065 int weapon;
00066 int shapenum;
00067 int dir;
00068 int delay;
00069 public:
00070 Missile_launcher(Egg_object *e, int weap, int shnum, int di, int del)
00071 : egg(e), weapon(weap), shapenum(shnum), dir(di), delay(del)
00072 { }
00073 virtual void handle_event(unsigned long curtime, long udata);
00074 };
00075
00076
00077
00078
00079
00080 void Missile_launcher::handle_event
00081 (
00082 unsigned long curtime,
00083 long udata
00084 )
00085 {
00086 Tile_coord src = egg->get_tile();
00087
00088 if (!gwin->get_win_tile_rect().has_point(src.tx, src.ty))
00089 return;
00090 Projectile_effect *proj = 0;
00091 if (dir < 8)
00092 {
00093 Tile_coord adj = src.get_neighbor(dir%8);
00094
00095 int dx = adj.tx - src.tx, dy = adj.ty - src.ty;
00096 Tile_coord dest = src;
00097 dest.tx += 20*dx;
00098 dest.ty += 20*dy;
00099 proj = new Projectile_effect(src, dest, shapenum, weapon);
00100 }
00101 else
00102 {
00103 Actor *party[9];
00104 int psize = gwin->get_party(party, 1);
00105 int cnt = psize;
00106 int n = rand()%psize;
00107
00108 for (int i = n; !proj && cnt; cnt--, i = (i + 1)%psize)
00109 if (Fast_pathfinder_client::is_straight_path(src,
00110 party[i]->get_tile()))
00111 proj = new Projectile_effect(
00112 src, party[i], shapenum, weapon);
00113 }
00114 if (proj)
00115 eman->add_effect(proj);
00116
00117 gwin->get_tqueue()->add(curtime + (delay > 0 ? delay : 1), this, udata);
00118 }
00119
00120
00121
00122
00123
00124 void Egglike_game_object::paint
00125 (
00126 )
00127 {
00128 if(gwin->paint_eggs)
00129 Game_object::paint();
00130 }
00131
00132
00133
00134
00135
00136 int Egglike_game_object::is_findable
00137 (
00138 )
00139 {
00140 return gwin->paint_eggs && Ireg_game_object::is_findable();
00141 }
00142
00143
00144
00145
00146
00147 Egg_object::Egg_object
00148 (
00149 int shapenum, int framenum,
00150 unsigned int tilex, unsigned int tiley,
00151 unsigned int lft,
00152 unsigned short itype,
00153 unsigned char prob,
00154 short d1, short d2
00155 ) : Egglike_game_object(shapenum, framenum, tilex, tiley, lft),
00156 probability(prob), data1(d1), data2(d2),
00157 area(Rectangle(0, 0, 0, 0)), launcher(0)
00158 {
00159 type = itype&0xf;
00160
00161 if (type == teleport && framenum == 6 && shapenum == 275)
00162 type = path;
00163 criteria = (itype & (7<<4)) >> 4;
00164 distance = (itype >> 10) & 0x1f;
00165 unsigned char noct = (itype >> 7) & 1;
00166 unsigned char do_once = (itype >> 8) & 1;
00167
00168 unsigned char htch = (type == missile) ? 0 : ((itype >> 9) & 1);
00169 solid_area = (criteria == something_on || criteria == cached_in ||
00170
00171 type == teleport) ? 1 : 0;
00172 unsigned char ar = (itype >> 15) & 1;
00173 flags = (noct << nocturnal) + (do_once << once) +
00174 (htch << hatched) + (ar << auto_reset);
00175 if (type == usecode || type == teleport || type == path)
00176 set_quality(data1&0xff);
00177
00178
00179 if (criteria == party_near && (flags&(1<<auto_reset)))
00180 criteria = avatar_near;
00181 }
00182
00183
00184
00185
00186
00187 inline void Egg_object::init_field
00188 (
00189 unsigned char ty
00190 )
00191 {
00192 type = ty;
00193 probability = 100;
00194 data1 = data2 = 0;
00195 launcher = 0;
00196 area = Rectangle(0, 0, 0, 0);
00197 criteria = party_footpad;
00198 distance = 0;
00199 solid_area = 0;
00200 flags = (1 << auto_reset);
00201 }
00202
00203
00204
00205
00206
00207 Egg_object::Egg_object
00208 (
00209 int shapenum,
00210 int framenum,
00211 unsigned int tilex, unsigned int tiley,
00212 unsigned int lft,
00213 unsigned char ty
00214 ) : Egglike_game_object(shapenum, framenum, tilex, tiley, lft)
00215 {
00216 init_field(ty);
00217 }
00218
00219
00220
00221
00222
00223 Egg_object::~Egg_object
00224 (
00225 )
00226 {
00227 if (launcher)
00228 {
00229 gwin->get_tqueue()->remove(launcher);
00230 delete launcher;
00231 }
00232 }
00233
00234
00235
00236
00237
00238 void Egg_object::set_area
00239 (
00240 )
00241 {
00242 if (!probability || type == path)
00243 {
00244 area = Rectangle(0, 0, 0, 0);
00245 return;
00246 }
00247 Tile_coord t = get_tile();
00248 switch (criteria)
00249 {
00250 case cached_in:
00251 area = Rectangle(t.tx - 32, t.ty - 32, 64, 64);
00252 break;
00253 case avatar_footpad:
00254 case party_footpad:
00255 {
00256 Shape_info& info = get_info();
00257 int xtiles = info.get_3d_xtiles(),
00258 ytiles = info.get_3d_ytiles();
00259 area = Rectangle(t.tx - xtiles + 1, t.ty - ytiles + 1,
00260 xtiles, ytiles);
00261 break;
00262 }
00263 case avatar_far:
00264 area = Rectangle(t.tx - distance - 1, t.ty - distance - 1,
00265 2*distance + 3, 2*distance + 3);
00266 break;
00267 default:
00268 {
00269 int width = 2*distance;
00270 width++;
00271 if (distance <= 1)
00272 {
00273
00274 if (criteria == external_criteria)
00275 width += 2;
00276 }
00277 area = Rectangle(t.tx - distance, t.ty - distance,
00278 width, width);
00279 break;
00280 }
00281 }
00282
00283 Rectangle world(0, 0, c_num_chunks*c_tiles_per_chunk,
00284 c_num_chunks*c_tiles_per_chunk);
00285 area = area.intersect(world);
00286 }
00287
00288
00289
00290
00291
00292
00293 int Egg_object::is_active
00294 (
00295 Game_object *obj,
00296 int tx, int ty, int tz,
00297 int from_tx, int from_ty
00298 )
00299 {
00300 if ((flags & (1 << (int) hatched)) &&
00301 !(flags & (1 << (int) auto_reset)))
00302 return (0);
00303 if (flags & (1 << (int) nocturnal))
00304 {
00305 int hour = gclock->get_hour();
00306 if (!(hour >= 9 || hour <= 5))
00307 return (0);
00308 }
00309 if (cheat.in_map_editor())
00310 return 0;
00311 Egg_criteria cri = (Egg_criteria) get_criteria();
00312
00313 int deltaz = tz - get_lift();
00314 int absdeltaz = deltaz < 0 ? -deltaz : deltaz;
00315 switch (cri)
00316 {
00317 case cached_in:
00318 {
00319 if (obj != gwin->get_main_actor() || !area.has_point(tx, ty))
00320 return 0;
00321 if (!(flags & (1 << (int) hatched)))
00322 return 1;
00323
00324
00325 return !area.has_point(from_tx, from_ty);
00326 }
00327 case avatar_near:
00328 if (obj != gwin->get_main_actor())
00329 return 0;
00330 #ifdef DEBUG
00331 print_debug();
00332 #endif
00333
00334 case party_near:
00335 if (!obj->get_flag(Obj_flags::in_party))
00336 return 0;
00337 if (type == teleport)
00338 return absdeltaz == 0 && area.has_point(tx, ty);
00339 if (!((absdeltaz <= 1 ||
00340
00341 (Game::get_game_type() == SERPENT_ISLE &&
00342 type != missile) ||
00343 (type == missile && tz/5 == get_lift()/5)) &&
00344
00345 area.has_point(tx, ty) &&
00346 !area.has_point(from_tx, from_ty)))
00347 return 0;
00348 return 1;
00349 case avatar_far:
00350 {
00351 if (obj != gwin->get_main_actor() || !area.has_point(tx, ty))
00352 return (0);
00353 Rectangle inside(area.x + 1, area.y + 1,
00354 area.w - 2, area.h - 2);
00355 return inside.has_point(from_tx, from_ty) &&
00356 !inside.has_point(tx, ty);
00357 }
00358 case avatar_footpad:
00359 return obj == gwin->get_main_actor() && deltaz == 0 &&
00360 area.has_point(tx, ty);
00361 case party_footpad:
00362 return area.has_point(tx, ty) && deltaz == 0 &&
00363 obj->get_flag(Obj_flags::in_party);
00364 case something_on:
00365 return
00366 deltaz >= -1 && deltaz <= 3 &&
00367 area.has_point(tx, ty) && !obj->as_actor();
00368 case external_criteria:
00369 default:
00370 return 0;
00371 }
00372 }
00373
00374
00375
00376
00377
00378 void Egg_object::paint
00379 (
00380 )
00381 {
00382 Egglike_game_object::paint();
00383
00384 if (launcher && !launcher->in_queue())
00385 gwin->get_tqueue()->add(0L, launcher, 0);
00386 }
00387
00388
00389
00390
00391
00392 void Egg_object::activate
00393 (
00394 int
00395 )
00396 {
00397 if (!edit())
00398 activate(0, 0);
00399 }
00400
00401
00402
00403
00404
00405
00406
00407 bool Egg_object::edit
00408 (
00409 )
00410 {
00411 #ifdef USE_EXULTSTUDIO
00412 if (client_socket >= 0 &&
00413 cheat.in_map_editor())
00414 {
00415 editing = 0;
00416 Tile_coord t = get_tile();
00417 unsigned long addr = (unsigned long) this;
00418 if (Egg_object_out(client_socket, addr, t.tx, t.ty, t.tz,
00419 get_shapenum(), get_framenum(),
00420 type, criteria, probability, distance,
00421 (flags>>nocturnal)&1, (flags>>once)&1,
00422 (flags>>hatched)&1, (flags>>auto_reset)&1,
00423 data1, data2) != -1)
00424 {
00425 cout << "Sent egg data to ExultStudio" << endl;
00426 editing = this;
00427 }
00428 else
00429 cout << "Error sending egg data to ExultStudio" <<endl;
00430 return true;
00431 }
00432 #endif
00433 return false;
00434 }
00435
00436
00437
00438
00439
00440
00441 void Egg_object::update_from_studio
00442 (
00443 unsigned char *data,
00444 int datalen
00445 )
00446 {
00447 #ifdef USE_EXULTSTUDIO
00448 unsigned long addr;
00449 int tx, ty, tz;
00450 int shape, frame;
00451 int type;
00452 int criteria;
00453 int probability;
00454 int distance;
00455 bool nocturnal, once, hatched, auto_reset;
00456 int data1, data2;
00457 if (!Egg_object_in(data, datalen, addr, tx, ty, tz, shape, frame,
00458 type, criteria, probability, distance,
00459 nocturnal, once, hatched, auto_reset,
00460 data1, data2))
00461 {
00462 cout << "Error decoding egg" << endl;
00463 return;
00464 }
00465 Egg_object *egg = (Egg_object *) addr;
00466 if (egg && egg != editing)
00467 {
00468 cout << "Egg from ExultStudio is not being edited" << endl;
00469 return;
00470 }
00471 editing = 0;
00472 if (!egg)
00473 {
00474 int x, y;
00475 if (!Get_click(x, y, Mouse::hand, 0))
00476 {
00477 if (client_socket >= 0)
00478 Exult_server::Send_data(client_socket, Exult_server::cancel);
00479 return;
00480 }
00481 if (shape == -1)
00482 shape = 275;
00483
00484 egg = new Egg_object(shape, 0, 0, 0, 0, 0, 0, 0, 0);
00485 int lift;
00486 for (lift = 0; lift < 12; lift++)
00487 if (gwin->drop_at_lift(egg, x, y, lift))
00488 break;
00489 if (lift == 12)
00490 {
00491 if (client_socket >= 0)
00492 Exult_server::Send_data(client_socket,
00493 Exult_server::cancel);
00494 delete egg;
00495 return;
00496 }
00497 if (client_socket >= 0)
00498 Exult_server::Send_data(client_socket,
00499 Exult_server::user_responded);
00500 }
00501 egg->type = type;
00502 if (shape != -1)
00503 egg->set_shape(shape);
00504 if (frame == -1)
00505 switch (type)
00506 {
00507 case monster: frame = 0; break;
00508 case jukebox: frame = 2; break;
00509 case soundsfx:frame = 1; break;
00510 case voice: frame = 3; break;
00511 case weather: frame = 4; break;
00512 case teleport:frame = 5; break;
00513 case path: frame = 6; break;
00514 case missile:
00515 egg->set_shape(200);
00516 if ((data2 & 0xFF) < 8)
00517 frame = 2 + ((data2 & 0xFF) / 2);
00518 else
00519 frame = 1;
00520 break;
00521 default: frame = 7; break;
00522 }
00523 if (frame != -1)
00524 egg->set_frame(frame);
00525 gwin->add_dirty(egg);
00526 egg->criteria = criteria&7;
00527 egg->distance = distance&31;
00528 egg->probability = probability;
00529 egg->flags = ((nocturnal?1:0)<<Egg_object::nocturnal) +
00530 ((once?1:0)<<Egg_object::once) +
00531 ((hatched?1:0)<<Egg_object::hatched) +
00532 ((auto_reset?1:0)<<Egg_object::auto_reset);
00533 egg->data1 = data1;
00534 egg->data2 = data2;
00535 if (type == usecode || type == teleport || type == path)
00536 egg->set_quality(data1&0xff);
00537 Map_chunk *chunk =
00538 gmap->get_chunk_safely(egg->get_cx(), egg->get_cy());
00539 chunk->remove_egg(egg);
00540 chunk->add_egg(egg);
00541 cout << "Egg updated" << endl;
00542 #endif
00543 }
00544
00545
00546
00547
00548
00549 static void Create_monster
00550 (
00551 Game_window *gwin,
00552 Egg_object *egg,
00553 int shnum,
00554 Monster_info *inf,
00555 int sched,
00556 int align
00557 )
00558 {
00559 Tile_coord dest = Map_chunk::find_spot(
00560 egg->get_tile(), 5, shnum, 0, 1);
00561 if (dest.tx != -1)
00562 {
00563 Monster_actor *monster = Monster_actor::create(shnum, dest,
00564 sched, align);
00565 gwin->add_dirty(monster);
00566 gwin->add_nearby_npc(monster);
00567 }
00568 }
00569
00570
00571
00572
00573
00574 void Egg_object::activate_teleport
00575 (
00576 Game_object *obj
00577 )
00578 {
00579 Tile_coord pos(-1, -1, -1);
00580 int qual = get_quality();
00581 if (qual == 255)
00582 {
00583 int schunk = data1 >> 8;
00584 pos = Tile_coord(
00585 (schunk%12)*c_tiles_per_schunk + (data2&0xff),
00586 (schunk/12)*c_tiles_per_schunk + (data2>>8), 0);
00587 }
00588 else
00589 {
00590 Egg_vector vec;
00591 if (find_nearby_eggs(vec, 275, 256, qual, 6))
00592 {
00593 Egg_object *path = vec[0];
00594 pos = path->get_tile();
00595 }
00596 }
00597 cout << "Should teleport to (" << pos.tx << ", " <<
00598 pos.ty << ')' << endl;
00599 if (pos.tx != -1 && obj && obj->get_flag(Obj_flags::in_party))
00600
00601 gwin->teleport_party(pos);
00602 }
00603
00604
00605
00606
00607
00608 void Egg_object::activate
00609 (
00610 Game_object *obj,
00611 bool must
00612
00613 )
00614 {
00615 #ifdef DEBUG
00616 print_debug();
00617 #endif
00618
00619 flags |= (1 << (int) hatched);
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631 Tile_coord eggpos = get_tile();
00632 if (GAME_SI && eggpos.tx == 1287 && eggpos.ty == 2568 && eggpos.tz == 0) {
00633 flags &= ~(1 << (int) hatched);
00634 }
00635
00636
00637
00638 int roll = must ? 0 : 1 + rand()%100;
00639 if (roll > probability)
00640 return;
00641 switch(type)
00642 {
00643 case jukebox:
00644 #ifdef DEBUG
00645 cout << "Audio parameters might be: " << (data1&0xff) << " and " << ((data1>>8)&0x01) << endl;
00646 #endif
00647 Audio::get_ptr()->start_music((data1)&0xff,(data1>>8)&0x01);
00648 break;
00649 case soundsfx:
00650 {
00651 int dir = 0;
00652 if (obj)
00653 {
00654 Tile_coord epos = get_tile(), opos = obj->get_tile();
00655 dir = Get_direction16(opos.ty - epos.ty,
00656 epos.tx - opos.tx);
00657 }
00658 Audio::get_ptr()->play_sound_effect(
00659 Audio::game_sfx(data1&0xff), SDL_MIX_MAXVOLUME, dir,
00660 (data1>>8)&1);
00661 break;
00662 }
00663 case voice:
00664 ucmachine->do_speech(data1&0xff);
00665 break;
00666 case monster:
00667 {
00668 int shnum = data2&1023;
00669 int frnum = data2>>10;
00670 Monster_info *inf =
00671 ShapeID::get_info(shnum).get_monster_info();
00672 if (inf)
00673 {
00674 if (gwin->armageddon)
00675 break;
00676 int sched = data1>>8;
00677 int align = data1&3;
00678 int cnt = (data1&0xff)>>2;
00679 if (cnt > 1)
00680 cnt = 1 + (rand()%cnt);
00681 while (cnt--)
00682 Create_monster(gwin, this, shnum, inf,
00683 sched, align);
00684 }
00685 else
00686 {
00687 Shape_info& info = ShapeID::get_info(shnum);
00688 Game_object *nobj =gmap->create_ireg_object(info,
00689 shnum, frnum, get_tx(), get_ty(), get_lift());
00690 Map_chunk *chunk =
00691 gmap->get_chunk(get_cx(), get_cy());
00692 if (nobj->is_egg())
00693 chunk->add_egg((Egg_object *) nobj);
00694 else
00695 chunk->add(nobj);
00696 gwin->add_dirty(nobj);
00697 nobj->set_flag(Obj_flags::okay_to_take);
00698
00699 nobj->set_flag(Obj_flags::is_temporary);
00700 }
00701 break;
00702 }
00703 case usecode:
00704 {
00705 if (must)
00706 ucmachine->call_usecode(data2, this,
00707 Usecode_machine::egg_proximity);
00708 else
00709 {
00710 Usecode_script *scr = new Usecode_script(this);
00711 scr->add(Ucscript::usecode, data2);
00712 if (flags & (1<<(int)once))
00713 {
00714 scr->add(Ucscript::remove);
00715 flags &= ~(1<<(int)once);
00716 }
00717 scr->start(gwin->get_std_delay());
00718 }
00719 break;
00720 }
00721 case missile:
00722 {
00723
00724 int weapon = data1, dir = data2&0xff, delay = data2>>8;
00725 Shape_info& info = ShapeID::get_info(weapon);
00726 Weapon_info *winf = info.get_weapon_info();
00727 int proj;
00728 if (winf && winf->get_projectile())
00729 proj = winf->get_projectile();
00730 else
00731 proj = 856;
00732 if (!launcher)
00733 launcher = new Missile_launcher(this, weapon,
00734 proj, dir, gwin->get_std_delay()*delay);
00735 if (!launcher->in_queue())
00736 gwin->get_tqueue()->add(0L, launcher, 0);
00737 break;
00738 }
00739 case teleport:
00740 activate_teleport(obj);
00741 break;
00742 case weather:
00743 {
00744 set_weather(data1&0xff, data1>>8, this);
00745 break;
00746 }
00747 case button:
00748 {
00749 int dist = data1&0xff;
00750 Egg_vector eggs;
00751 find_nearby_eggs(eggs, 275, dist);
00752 for (Egg_vector::const_iterator it = eggs.begin();
00753 it != eggs.end(); ++it)
00754 {
00755 Egg_object *egg = *it;
00756 if (egg != this &&
00757 egg->criteria == external_criteria &&
00758 !(egg->flags & (1 << (int) hatched)))
00759 egg->activate(obj, 0);
00760 }
00761 break;
00762 }
00763 default:
00764 cout << "Egg not actioned" << endl;
00765 }
00766 if (flags & (1 << (int) once))
00767 remove_this(0);
00768 }
00769
00770
00771
00772
00773
00774 void Egg_object::print_debug
00775 (
00776 )
00777 {
00778 cout << "Egg type is " << (int) type << ", prob = " <<
00779 (int) probability <<
00780 ", distance = " << (int) distance << ", crit = " <<
00781 (int) criteria << ", once = " <<
00782 ((flags & (1<<(int)once)) != 0) << ", hatched = " <<
00783 ((flags & (1<<(int)hatched)) != 0) <<
00784 ", areset = " <<
00785 ((flags & (1<<(int)auto_reset)) != 0) << ", data1 = " << data1
00786 << ", data2 = " << data2 << endl;
00787 }
00788
00789
00790
00791
00792
00793 void Egg_object::set_weather
00794 (
00795 int weather,
00796 int len,
00797 Game_object *egg
00798 )
00799 {
00800 if (!len)
00801 len = 120;
00802 int cur = eman->get_weather();
00803 cout << "Current weather is " << cur << "; setting " << weather
00804 << endl;
00805 switch (weather)
00806 {
00807 case 0:
00808 eman->remove_weather_effects();
00809 break;
00810 case 1:
00811 case 2:
00812 if (cur != weather)
00813 eman->add_effect(new Storm_effect(len, 0, egg));
00814 break;
00815 case 3:
00816 eman->remove_weather_effects();
00817 eman->add_effect(new Sparkle_effect(len, 0, egg));
00818 break;
00819 case 6:
00820 eman->add_effect(new Clouds_effect(len, 0, egg));
00821 break;
00822 default:
00823 break;
00824 }
00825 }
00826
00827
00828
00829
00830
00831
00832 void Egg_object::move
00833 (
00834 int newtx,
00835 int newty,
00836 int newlift
00837 )
00838 {
00839
00840 int newcx = newtx/c_tiles_per_chunk, newcy = newty/c_tiles_per_chunk;
00841 Map_chunk *newchunk = gmap->get_chunk_safely(newcx, newcy);
00842 if (!newchunk)
00843 return;
00844 remove_this(1);
00845 set_lift(newlift);
00846 shape_pos = ((newtx%c_tiles_per_chunk) << 4) + newty%c_tiles_per_chunk;
00847 newchunk->add_egg(this);
00848 gwin->add_dirty(this);
00849 }
00850
00851
00852
00853
00854
00855 void Egg_object::remove_this
00856 (
00857 int nodel
00858 )
00859 {
00860 if (get_owner())
00861 get_owner()->remove(this);
00862 else
00863 {
00864 Map_chunk *chunk = gmap->get_chunk_safely(cx, cy);
00865 if (chunk)
00866 {
00867 gwin->add_dirty(this);
00868 chunk->remove_egg(this);
00869 }
00870 }
00871 if (launcher)
00872 {
00873 gwin->get_tqueue()->remove(launcher);
00874 delete launcher;
00875 launcher = 0;
00876 }
00877 if (!nodel)
00878 gwin->delete_object(this);
00879 }
00880
00881
00882
00883
00884
00885 void Egg_object::write_ireg
00886 (
00887 DataSource *out
00888 )
00889 {
00890 unsigned char buf[13];
00891 buf[0] = 12;
00892 uint8 *ptr = &buf[1];
00893 write_common_ireg(ptr);
00894 ptr += 4;
00895 unsigned short tword = type&0xf;
00896 tword |= ((criteria&7)<<4);
00897 tword |= (((flags>>nocturnal)&1)<<7);
00898 tword |= (((flags>>once)&1)<<8);
00899 tword |= (((flags>>hatched)&1)<<9);
00900 tword |= ((distance&0x1f)<<10);
00901 tword |= (((flags>>auto_reset)&1)<<15);
00902 Write2(ptr, tword);
00903 *ptr++ = probability;
00904 Write2(ptr, data1);
00905 *ptr++ = (get_lift()&15)<<4;
00906 Write2(ptr, data2);
00907 out->write((char*)buf, sizeof(buf));
00908
00909 Game_map::write_scheduled(out, this);
00910 }
00911
00912
00913 int Egg_object::get_ireg_size()
00914 {
00915
00916 if (gumpman->find_gump(this) || Usecode_script::find(this))
00917 return -1;
00918
00919 return 13;
00920 }
00921
00922
00923
00924
00925 Animated_egg_object::Animated_egg_object
00926 (
00927 int shapenum, int framenum,
00928 unsigned int tilex,
00929 unsigned int tiley, unsigned int lft,
00930 unsigned short itype,
00931 unsigned char prob, short d1, short d2
00932 ) : Egg_object(shapenum, framenum,
00933 tilex, tiley, lft, itype, prob, d1, d2)
00934 {
00935 animator = new Frame_animator(this);
00936 }
00937
00938
00939
00940
00941
00942 Animated_egg_object::Animated_egg_object
00943 (
00944 int shapenum, int framenum, unsigned int tilex,
00945 unsigned int tiley, unsigned int lft,
00946 unsigned char ty
00947 ) : Egg_object(shapenum, framenum, tilex, tiley, lft, ty)
00948 {
00949 int recycle = 0;
00950 switch (type)
00951 {
00952 case poison_field:
00953 recycle = 6; break;
00954 case sleep_field:
00955 recycle = 1; break;
00956 case fire_field:
00957 recycle = 8; break;
00958 case caltrops_field:
00959 animator = 0; return;
00960 }
00961 animator = new Field_frame_animator(this, recycle);
00962 }
00963
00964
00965
00966
00967 Animated_egg_object::~Animated_egg_object()
00968 {
00969 delete animator;
00970 }
00971
00972
00973
00974
00975
00976 void Animated_egg_object::paint
00977 (
00978 )
00979 {
00980 if (animator)
00981 animator->want_animation();
00982 Ireg_game_object::paint();
00983 }
00984
00985
00986
00987
00988
00989 void Animated_egg_object::activate
00990 (
00991 int event
00992 )
00993 {
00994 Egg_object::activate(event);
00995 flags &= ~(1 << (int) hatched);
00996 }
00997
00998
00999
01000
01001
01002 void Animated_egg_object::stop_animation
01003 (
01004 )
01005 {
01006 delete animator;
01007 animator = 0;
01008 }
01009
01010
01011
01012
01013
01014
01015
01016 bool Field_object::field_effect
01017 (
01018 Actor *actor
01019 )
01020 {
01021 bool del = false;
01022 switch (type)
01023 {
01024 case poison_field:
01025 if (rand()%2)
01026 {
01027 actor->set_flag(Obj_flags::poisoned);
01028 del = true;
01029 }
01030 break;
01031 case sleep_field:
01032 if (rand()%2)
01033 {
01034 actor->set_flag(Obj_flags::asleep);
01035 del = true;
01036 }
01037 break;
01038 case fire_field:
01039
01040 if (get_shapenum() == 561)
01041 {
01042 actor->reduce_health(5 + rand()%4);
01043 }
01044 else if (rand()%2)
01045 {
01046 actor->reduce_health(1);
01047 }
01048
01049 actor->clear_flag(Obj_flags::asleep);
01050 break;
01051 case caltrops_field:
01052 if (actor->get_property(Actor::intelligence)*
01053 (actor->get_flag(Obj_flags::might) ? 2 : 1) < rand()%40)
01054 {
01055 actor->reduce_health(2 + rand()%3);
01056 }
01057 return false;
01058 }
01059 if (!del)
01060 ((Field_frame_animator *) animator)->activated = true;
01061 return del;
01062 }
01063
01064
01065
01066
01067
01068
01069 void Field_object::activate
01070 (
01071 int event
01072 )
01073 {
01074
01075
01076 if (event != Usecode_machine::npc_proximity)
01077 {
01078 Ireg_game_object::activate(event);
01079 return;
01080 }
01081 Actor_queue npcs;
01082 gwin->get_nearby_npcs(npcs);
01083 npcs.push(gwin->get_main_actor());
01084 Rectangle eggfoot = get_footprint();
01085
01086 ((Field_frame_animator *) animator)->activated = false;
01087 for (Actor_queue::const_iterator it = npcs.begin();
01088 it != npcs.end(); ++it)
01089 {
01090 Actor *actor = *it;
01091 if (actor->is_dead() || Game_object::distance(actor) > 4)
01092 continue;
01093 if (actor->get_footprint().intersects(eggfoot))
01094 Field_object::activate(actor);
01095 }
01096 }
01097
01098
01099
01100
01101
01102 void Field_object::activate
01103 (
01104 Game_object *obj,
01105 bool
01106 )
01107 {
01108 if (field_effect((Actor *) obj))
01109 remove_this(0);
01110 }
01111
01112
01113
01114
01115
01116 void Field_object::write_ireg
01117 (
01118 DataSource *out
01119 )
01120 {
01121 Ireg_game_object::write_ireg(out);
01122 }
01123
01124
01125 int Field_object::get_ireg_size()
01126 {
01127 return Ireg_game_object::get_ireg_size();
01128 }
01129
01130
01131
01132
01133
01134
01135 Mirror_object::Mirror_object(int shapenum, int framenum, unsigned int tilex,
01136 unsigned int tiley, unsigned int lft) :
01137 Egg_object(shapenum, framenum, tilex, tiley, lft, Egg_object::mirror_object)
01138 {
01139 solid_area = 1;
01140 }
01141
01142 void Mirror_object::activate(int event)
01143 {
01144 Ireg_game_object::activate(event);
01145 }
01146
01147 void Mirror_object::activate(Game_object *obj, bool must)
01148 {
01149
01150 if ((get_framenum()%3) == 2) return;
01151
01152 int wanted_frame = get_framenum()/3;
01153 wanted_frame *= 3;
01154
01155
01156 Tile_coord t = get_tile();
01157
01158
01159 if (get_shapenum()==268)
01160 {
01161 t.tx++;
01162 t.ty--;
01163 }
01164 else
01165 {
01166 t.tx--;
01167 t.ty++;
01168 }
01169
01170
01171 int nl = 0;
01172 if (Map_chunk::is_blocked(1, t.tz, t.tx, t.ty, 2, 2, nl, MOVE_WALK, 0))
01173 {
01174 wanted_frame++;
01175 }
01176
01177
01178 if (get_framenum()!=wanted_frame)
01179 change_frame(wanted_frame);
01180 }
01181
01182
01183 int Mirror_object::is_active(Game_object *obj, int tx, int ty, int tz, int from_tx, int from_ty)
01184 {
01185
01186 int frnum = get_framenum();
01187 if (frnum%3 == 2) return 0;
01188 if (frnum >= 3 && GAME_BG)
01189 return 0;
01190
01191 return 1;
01192 }
01193
01194
01195 void Mirror_object::set_area()
01196 {
01197
01198 if ((get_framenum()%3) == 2) area = Rectangle(0, 0, 0, 0);
01199
01200 Tile_coord t = get_tile();
01201
01202
01203 if (get_shapenum()==268) area = Rectangle(t.tx-1, t.ty-3, 6, 6);
01204 else area = Rectangle(t.tx-3 , t.ty-1, 6, 6);
01205 }
01206
01207 void Mirror_object::paint()
01208 {
01209 Ireg_game_object::paint();
01210 }
01211
01212
01213
01214
01215
01216 void Mirror_object::write_ireg(DataSource *out)
01217 {
01218 Ireg_game_object::write_ireg(out);
01219 }
01220
01221
01222 int Mirror_object::get_ireg_size()
01223 {
01224
01225 return Ireg_game_object::get_ireg_size();
01226 }