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 #ifndef ALPHA_LINUX_CXX
00026 # include <cstring>
00027 #endif
00028 #include "gamewin.h"
00029 #include "gamemap.h"
00030 #include "game.h"
00031 #include "monsters.h"
00032 #include "utils.h"
00033 #include "egg.h"
00034 #include "chunks.h"
00035 #include "schedule.h"
00036 #include "objiter.h"
00037 #include "databuf.h"
00038 #include "npctime.h"
00039
00040 using std::ios;
00041 using std::cout;
00042 using std::endl;
00043 using std::istream;
00044 using std::ostream;
00045
00046
00047
00048
00049
00050 void Actor::read
00051 (
00052 DataSource* nfile,
00053 int num,
00054 bool has_usecode,
00055 bool& fix_unused
00056
00057
00058 )
00059 {
00060 npc_num = num;
00061
00062
00063
00064
00065 bool fix_first = Game::is_new_game();
00066
00067 init();
00068 unsigned locx = nfile->read1();
00069 unsigned locy = nfile->read1();
00070
00071 unsigned short shnum = nfile->read2();
00072
00073 if (num == 0 && Game::get_game_type() != BLACK_GATE &&
00074 (shnum & 0x3ff) < 12)
00075 set_shape((shnum & 0x3ff) | 0x400);
00076 else
00077 set_shape(shnum & 0x3ff);
00078
00079 set_frame(shnum >> 10);
00080
00081 int iflag1 = nfile->read2();
00082
00083
00084
00085
00086
00087
00088 bool read_sched_usecode = !fix_first && (iflag1&2);
00089 if (!fix_first && (iflag1&4))
00090 usecode_assigned = true;
00091
00092 int schunk = nfile->read1();
00093 nfile->read1();
00094 int usefun = nfile->read2();
00095 set_lift(usefun >> 12);
00096 usecode = usefun & 0xfff;
00097
00098
00099
00100 if (npc_num >= 0 && npc_num < 256)
00101 usecode = 0x400 + npc_num;
00102
00103 else if ((!has_usecode && !usecode_assigned &&
00104 usecode != 0x400 + npc_num) ||
00105 usecode == 0xfff)
00106 usecode = -1;
00107
00108 int health_val = static_cast<int>(static_cast<char>(nfile->read1()));
00109 set_property(static_cast<int>(Actor::health), health_val);
00110 nfile->skip(3);
00111 int iflag2 = nfile->read2();
00112 if (iflag2 == 0 && num >= 0 && !fix_unused)
00113 {
00114 if (num == 0)
00115 fix_unused = true;
00116 else
00117 unused = true;
00118 #ifdef DEBUG
00119 cout << "NPC #" << num << " is unused" << endl;
00120 #endif
00121 }
00122
00123 bool has_contents = fix_first ? (iflag1 && !unused) : (iflag1&1);
00124
00125 const int rflags = nfile->read2();
00126
00127 if ((rflags >> 0x7) & 1) set_flag (Obj_flags::asleep);
00128 if ((rflags >> 0x8) & 1) set_flag (Obj_flags::charmed);
00129 if ((rflags >> 0x9) & 1) set_flag (Obj_flags::cursed);
00130 if ((rflags >> 0xB) & 1) set_flag (Obj_flags::in_party);
00131 if ((rflags >> 0xC) & 1) set_flag (Obj_flags::paralyzed);
00132 if ((rflags >> 0xD) & 1) set_flag (Obj_flags::poisoned);
00133 if ((rflags >> 0xE) & 1) set_flag (Obj_flags::protection);
00134 if (!fix_first && ((rflags >> 0xF) & 1))
00135 set_flag (Obj_flags::dead);
00136
00137
00138 if (((rflags >> 0xA) & 1))
00139 set_flag (Obj_flags::on_moving_barge);
00140 alignment = (rflags >> 3)&3;
00141
00142
00143 if ((rflags >> 0x6) & 1 && !fix_first) set_flag (Obj_flags::is_temporary);
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155 int strength_val = nfile->read1();
00156
00157 if (Game::get_game_type() == BLACK_GATE)
00158 {
00159 set_property(static_cast<int>(Actor::strength), strength_val & 0x3F);
00160
00161 if (num == 0)
00162 {
00163 if (Game::get_avskin() >= 0 && Game::get_avskin() <= 3)
00164 set_skin_color (Game::get_avskin());
00165 else
00166 set_skin_color (((strength_val >> 6)-1) & 0x3);
00167 }
00168 else
00169 set_skin_color (3);
00170 }
00171 else
00172 {
00173 set_property(static_cast<int>(Actor::strength), strength_val & 0x1F);
00174
00175 if (num == 0)
00176 {
00177 if (Game::get_avskin() >= 0 && Game::get_avskin() <= 2)
00178 set_skin_color (Game::get_avskin());
00179 else
00180 set_skin_color ((strength_val >> 5) & 0x3);
00181 }
00182 else
00183 set_skin_color (-1);
00184
00185 if ((strength_val << 7) & 1) set_flag (Obj_flags::freeze);
00186 }
00187
00188 if (is_dying() &&
00189 npc_num > 0)
00190 set_flag(Obj_flags::dead);
00191
00192 set_property(static_cast<int>(Actor::dexterity), nfile->read1());
00193
00194
00195
00196 int intel_val = nfile->read1();
00197
00198 set_property(static_cast<int>(Actor::intelligence), intel_val & 0x1F);
00199 if ((intel_val >> 5) & 1) set_flag (Obj_flags::read);
00200
00201 if ((intel_val >> 6) & 1)
00202 set_flag (Obj_flags::si_tournament);
00203 if ((intel_val >> 7) & 1) set_flag (Obj_flags::polymorph);
00204
00205
00206
00207 int combat_val = nfile->read1();
00208 set_property(static_cast<int>(Actor::combat), combat_val & 0x7F);
00209 if ((combat_val << 7) & 1) set_flag (Obj_flags::petra);
00210
00211 schedule_type = nfile->read1();
00212 int amode = nfile->read1();
00213
00214 combat_protected = (amode&(1<<4)) != 0;
00215 user_set_attack = (amode&(1<<5)) != 0;
00216 attack_mode = (Attack_mode) (amode&0xf);
00217
00218 nfile->skip(3);
00219
00220
00221
00222 int magic_val = nfile->read1();
00223 int mana_val = nfile->read1();
00224
00225 if (num == 0)
00226 {
00227 int magic = magic_val&0x1f, mana = mana_val&0x1f;
00228 set_property(static_cast<int>(Actor::magic), magic);
00229
00230
00231 if (mana < magic)
00232 set_property(static_cast<int>(Actor::mana), mana);
00233 else
00234 set_property(static_cast<int>(Actor::mana), magic);
00235
00236 set_flag (Obj_flags::met);
00237 }
00238 else
00239 {
00240 set_ident(magic_val&0x1F);
00241 if ((mana_val >> 0) & 1) set_flag (Obj_flags::met);
00242 if ((mana_val >> 1) & 1) set_flag(Obj_flags::no_spell_casting);
00243 if ((mana_val >> 2) & 1) set_flag (Obj_flags::si_zombie);
00244 }
00245
00246
00247 set_temperature (((magic_val >> 2) & 0x38) + ((mana_val >> 5) & 7));
00248
00249
00250 face_num = nfile->read1();
00251 if (!face_num && npc_num > 0)
00252 face_num = npc_num;
00253 nfile->skip(2 );
00254
00255 set_property(static_cast<int>(Actor::exp), nfile->read4());
00256 set_property(static_cast<int>(Actor::training), nfile->read1());
00257
00258
00259 nfile->skip (2);
00260 nfile->skip (2);
00261 oppressor = nfile->read2();
00262
00263 nfile->skip (4);
00264
00265 schedule_loc.tx = nfile->read2();
00266 schedule_loc.ty = nfile->read2();
00267
00268
00269 int tflags = nfile->read2();
00270
00271
00272 if (fix_first)
00273 set_type_flags (1 << Actor::tf_walk);
00274 else
00275 set_type_flags (tflags);
00276
00277
00278 if (num == 0 && Game::get_avsex() == 0)
00279 {
00280 clear_type_flag (Actor::tf_sex);
00281 }
00282 else if (num == 0 && Game::get_avsex() == 1)
00283 {
00284 set_type_flag (Actor::tf_sex);
00285 }
00286
00287
00288 nfile->skip (5);
00289
00290 next_schedule = nfile->read1();
00291
00292 nfile->skip (1);
00293 nfile->skip (2);
00294 nfile->skip (2);
00295
00296
00297 shnum = nfile->read2();
00298 if (!fix_first && shnum)
00299 {
00300 if (GAME_BG && !sman->can_use_multiracial() && shnum > 1024 && npc_num == 0)
00301 set_actor_shape();
00302 else
00303 set_shape(shnum);
00304
00305 shnum = (sint16) nfile->read2();
00306 if (get_flag (Obj_flags::polymorph))
00307 {
00308 if (shnum != get_shapenum())
00309 set_polymorph(shnum);
00310 else
00311 clear_flag(Obj_flags::polymorph);
00312 }
00313 }
00314 else
00315 {
00316 nfile->skip (2);
00317 set_polymorph_default();
00318 }
00319
00320
00321 if (!fix_first)
00322 {
00323 uint32 f;
00324
00325
00326 f = nfile->read4();
00327 flags |= f;
00328 if (get_flag(Obj_flags::invisible))
00329 need_timers()->start_invisibility();
00330
00331
00332 f = nfile->read2();
00333 siflags |= f;
00334
00335
00336 bool polym = get_flag(Obj_flags::polymorph)!= false;
00337 f = nfile->read4();
00338 flags2 |= f;
00339 if (!polym && get_flag(Obj_flags::polymorph))
00340 clear_flag(Obj_flags::polymorph);
00341 }
00342 else
00343 {
00344
00345 nfile->skip (4);
00346
00347
00348 nfile->skip (2);
00349
00350
00351 nfile->skip (4);
00352 }
00353
00354
00355 nfile->skip (15);
00356
00357
00358 int food_read = static_cast<int>(static_cast<char>(nfile->read1()));
00359 if (fix_first) food_read = 18;
00360 set_property(static_cast<int>(Actor::food_level), food_read);
00361
00362
00363 nfile->skip(7);
00364
00365 char namebuf[17];
00366 nfile->read(namebuf, 16);
00367
00368 for (int i = 0; i < 16; i++)
00369 if (namebuf[i] == 0)
00370 i = 16;
00371 else if (namebuf[i] < ' ' || namebuf[i] >= 127)
00372 {
00373 namebuf[0] = 0;
00374 break;
00375 }
00376
00377 namebuf[16] = 0;
00378
00379
00380 if (num == 0 && Game::get_avname())
00381 {
00382 name = Game::get_avname();
00383 }
00384 else
00385 name = namebuf;
00386
00387
00388 int scy = 16*(schunk/12);
00389 int scx = 16*(schunk%12);
00390 if (has_contents)
00391 gwin->get_map()->read_ireg_objects(nfile, scx, scy, this);
00392 if (read_sched_usecode)
00393 gwin->get_map()->read_special_ireg(nfile, this);
00394 int cx = locx >> 4;
00395 int cy = locy >> 4;
00396
00397 int tilex = locx & 0xf;
00398 int tiley = locy & 0xf;
00399 set_shape_pos(tilex, tiley);
00400 Map_chunk *olist = gmap->get_chunk_safely(scx + cx, scy + cy);
00401 set_invalid();
00402 if (olist && !is_dead() &&
00403 !unused)
00404 {
00405 move((scx + cx)*c_tiles_per_chunk + tilex,
00406 (scy + cy)*c_tiles_per_chunk + tiley, get_lift());
00407
00408
00409 }
00410
00411
00412 if (Game::get_game_type() == BLACK_GATE && Game::get_avname() && (num == 0 || num == 1))
00413 ready_best_weapon();
00414
00415 #if defined(DEBUG) && 0
00416
00417 cout << get_npc_num() << " Creating ";
00418
00419 if (name.empty()) cout << get_name();
00420 else cout << name;
00421
00422 cout << ", shape = " <<
00423 get_shapenum() <<
00424 ", frame = " << get_framenum() << ", usecode = " <<
00425 usefun << endl;
00426
00427 cout << "Chunk coords are (" << scx + cx << ", " << scy + cy << "), lift is "
00428 << get_lift() << endl;
00429
00430 cout << "Type Flags: ";
00431 if (get_type_flag(tf_fly)) cout << "fly ";
00432 if (get_type_flag(tf_swim)) cout << "swim ";
00433 if (get_type_flag(tf_walk)) cout << "walk ";
00434 if (get_type_flag(tf_ethereal)) cout << "ethereal ";
00435 if (get_type_flag(tf_in_party)) cout << "in party ";
00436 cout << endl;
00437
00438 #endif
00439 }
00440
00441
00442
00443
00444
00445 void Actor::write
00446 (
00447 DataSource* nfile
00448 )
00449 {
00450 int i;
00451 unsigned char buf4[4];
00452
00453 int old_shape = get_shapenum();
00454 set_shape( get_shape_real() );
00455
00456 Game_object::write_common_ireg(buf4);
00457 nfile->write(reinterpret_cast<char*>(buf4), sizeof(buf4));
00458
00459 set_shape( old_shape );
00460
00461
00462
00463
00464
00465
00466
00467 int iflag1 = objects.is_empty() ? 0 : 1;
00468 iflag1 |= 2;
00469 if (usecode_assigned)
00470 iflag1 |= 4;
00471 nfile->write2(iflag1);
00472
00473 nfile->write1((get_cy()/16)*12 + get_cx()/16);
00474 nfile->write1(0);
00475
00476 int usefun = get_usecode() & 0xfff;
00477
00478 usefun |= ((get_lift()&15) << 12);
00479 nfile->write2(usefun);
00480 nfile->write1(get_property(Actor::health));
00481 nfile->write1(0);
00482 nfile->write2(0);
00483 nfile->write2(unused ? 0 : 1);
00484
00485
00486 int iout = 0;
00487
00488 if (get_flag (Obj_flags::asleep)) iout |= 1 << 0x7;
00489 if (get_flag (Obj_flags::charmed)) iout |= 1 << 0x8;
00490 if (get_flag (Obj_flags::cursed)) iout |= 1 << 0x9;
00491 if (get_flag (Obj_flags::in_party)) iout |= 1 << 0xB;
00492 if (get_flag (Obj_flags::paralyzed)) iout |= 1 << 0xC;
00493 if (get_flag (Obj_flags::poisoned)) iout |= 1 << 0xD;
00494 if (get_flag (Obj_flags::protection)) iout |= 1 << 0xE;
00495
00496
00497 if (get_flag (Obj_flags::on_moving_barge)) iout |= 1 << 0xA;
00498
00499
00500
00501 if (get_flag (Obj_flags::is_temporary)) iout |= 1 << 0x6;
00502
00503 iout |= ((alignment&3) << 3);
00504
00505 nfile->write2(iout);
00506
00507
00508 iout = get_property(Actor::strength);
00509 if (Game::get_game_type() != BLACK_GATE && npc_num == 0) iout |= (get_skin_color () & 3) << 5;
00510 else if (npc_num == 0) iout |= ((get_skin_color()+1) & 3) << 6;
00511
00512 if (get_flag (Obj_flags::freeze)) iout |= 1 << 7;
00513 nfile->write1(iout);
00514
00515 nfile->write1(get_property(Actor::dexterity));
00516
00517 iout = get_property(Actor::intelligence);
00518 if (get_flag (Obj_flags::read)) iout |= 1 << 5;
00519
00520 if (get_flag (Obj_flags::si_tournament)) iout |= 1 << 6;
00521 if (get_flag (Obj_flags::polymorph)) iout |= 1 << 7;
00522 nfile->write1(iout);
00523
00524
00525 iout = get_property(Actor::combat);
00526 if (get_flag (Obj_flags::petra)) iout |= 1 << 7;
00527 nfile->write1(iout);
00528
00529 nfile->write1(get_schedule_type());
00530 unsigned char amode = attack_mode |
00531 (combat_protected ? (1<<4) : 0) |
00532 (user_set_attack ? (1<<5) : 0);
00533 nfile->write1(amode);
00534 nfile->write1(0);
00535 nfile->write2(0);
00536
00537
00538 int mana_val = 0;
00539 int magic_val = 0;
00540
00541 if (get_npc_num() == 0)
00542 {
00543 mana_val = get_property(static_cast<int>(Actor::mana));
00544 magic_val = get_property(static_cast<int>(Actor::magic));
00545 }
00546 else
00547 {
00548 magic_val = get_ident() & 0x1F;
00549 if (get_flag (Obj_flags::met)) mana_val |= 1;
00550 if (get_flag (Obj_flags::no_spell_casting)) mana_val |= 1 << 1;
00551 if (get_flag (Obj_flags::si_zombie)) mana_val |= 1 << 2;
00552 }
00553
00554
00555 mana_val |= (get_temperature () & 0x1F) << 5;
00556 magic_val |= (get_temperature () & 0x38) << 2;
00557
00558 nfile->write1 (magic_val);
00559 nfile->write1 (mana_val);
00560
00561 nfile->write1((face_num >= 0 && face_num <= 255) ? face_num : 0);
00562 nfile->write2(0);
00563
00564 nfile->write4(get_property(Actor::exp));
00565 nfile->write1(get_property(Actor::training));
00566
00567
00568 nfile->write2(0);
00569 nfile->write2(0);
00570 nfile->write2(oppressor);
00571
00572 nfile->write4(0);
00573
00574 nfile->write2(schedule_loc.tx);
00575 nfile->write2(schedule_loc.ty);
00576
00577
00578 nfile->write2(get_type_flags());
00579
00580 nfile->write4(0);
00581 nfile->write1(0);
00582
00583 nfile->write1(next_schedule);
00584
00585 nfile->write1(0);
00586 nfile->write2(0);
00587 nfile->write2(0);
00588
00589
00590 if (get_flag (Obj_flags::polymorph))
00591 {
00592 nfile->write2(shape_save);
00593 nfile->write2(get_shapenum());
00594 }
00595 else
00596 {
00597 nfile->write2(get_shapenum());
00598 nfile->write2(0);
00599 }
00600
00601
00602 nfile->write4(flags);
00603
00604
00605 nfile->write2(siflags);
00606
00607
00608 nfile->write4(flags2);
00609
00610
00611 for (i = 0; i < 15; i++)
00612 nfile->write1(0);
00613
00614
00615 nfile->write1(get_property (Actor::food_level));
00616
00617
00618 for (i = 0; i < 7; i++)
00619 nfile->write1(0);
00620
00621 char namebuf[17];
00622 std::memset(namebuf, 0, 16);
00623 if (name.empty()) {
00624 std::string namestr = Game_object::get_name();
00625 std::strncpy(namebuf, namestr.c_str(), 16);
00626 } else
00627 std::strncpy(namebuf, name.c_str(), 16);
00628 nfile->write(namebuf, 16);
00629 write_contents(nfile);
00630 namebuf[16] = 0;
00631
00632 Game_map::write_scheduled(nfile, this, true);
00633 }
00634
00635
00636
00637
00638
00639 void Monster_actor::write
00640 (
00641 DataSource* nfile
00642 )
00643 {
00644 if (Actor::is_dead())
00645 return;
00646 Actor::write(nfile);
00647 }
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657 void Actor::write_contents
00658 (
00659 DataSource* out
00660 )
00661 {
00662 if (!objects.is_empty())
00663 {
00664 const int num_spots = static_cast<int>(sizeof(spots)/sizeof(spots[0]));
00665 sint8 i;
00666
00667 for (i = 0; i < num_spots; ++i)
00668 {
00669
00670 if (spots[i])
00671 {
00672
00673 out->write1(0x02);
00674 out->write2(static_cast<uint8>(i));
00675 spots[i]->write_ireg(out);
00676 }
00677 }
00678
00679 Game_object *obj;
00680 Object_iterator next(objects);
00681
00682 while ((obj = next.get_next()) != 0)
00683 {
00684 for (i = 0; i < num_spots; ++i)
00685 if (spots[i] == obj)
00686 break;
00687
00688 if (i == num_spots)
00689 {
00690
00691 i = -1;
00692 out->write1(0x02);
00693 out->write2(static_cast<uint8>(i));
00694 obj->write_ireg(out);
00695 }
00696 }
00697 out->write1(0x01);
00698 }
00699 }
00700