00001
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifdef HAVE_CONFIG_H
00024 # include <config.h>
00025 #endif
00026
00027 #include <iostream>
00028 #include <string>
00029 #include "party.h"
00030 #include "actors.h"
00031 #include "gamewin.h"
00032 #include "frameseq.h"
00033 #include "dir.h"
00034
00035 using std::cout;
00036 using std::endl;
00037
00038
00039
00040
00041
00042 Party_manager::Party_manager
00043 (
00044 ) : party_count(0), dead_party_count(0), validcnt(0)
00045 {
00046
00047 std::memset((char *) &party[0], 0, sizeof(party));
00048 std::memset((char *) &dead_party[0], 0, sizeof(dead_party));
00049 }
00050
00051
00052
00053
00054
00055
00056
00057 bool Party_manager::add_to_party
00058 (
00059 Actor *npc
00060 )
00061 {
00062 const int maxparty = sizeof(party)/sizeof(party[0]);
00063 if (!npc || party_count == maxparty || npc->is_in_party())
00064 return false;
00065 remove_from_dead_party(npc);
00066 npc->set_party_id(party_count);
00067 npc->set_flag (Obj_flags::in_party);
00068
00069 npc->set_flag_recursively(Obj_flags::okay_to_take);
00070 party[party_count++] = npc->get_npc_num();
00071 return true;
00072 }
00073
00074
00075
00076
00077
00078
00079
00080 bool Party_manager::remove_from_party
00081 (
00082 Actor *npc
00083 )
00084 {
00085 if (!npc)
00086 return false;
00087 int id = npc->get_party_id();
00088 if (id == -1)
00089 return false;
00090 int npc_num = npc->get_npc_num();
00091 if (party[id] != npc_num)
00092 {
00093 cout << "Party mismatch!!" << endl;
00094 return false;
00095 }
00096
00097 for (int i = id + 1; i < party_count; i++)
00098 {
00099 Actor *npc2 = gwin->get_npc(party[i]);
00100 if (npc2)
00101 npc2->set_party_id(i - 1);
00102 party[i - 1] = party[i];
00103 }
00104 npc->clear_flag (Obj_flags::in_party);
00105 party_count--;
00106 party[party_count] = 0;
00107 npc->set_party_id(-1);
00108 return true;
00109 }
00110
00111
00112
00113
00114
00115
00116
00117 int Party_manager::in_dead_party
00118 (
00119 Actor *npc
00120 )
00121 {
00122 int num = npc->get_npc_num();
00123 for (int i = 0; i < dead_party_count; i++)
00124 if (dead_party[i] == num)
00125 return i;
00126 return -1;
00127 }
00128
00129
00130
00131
00132
00133
00134
00135 bool Party_manager::add_to_dead_party
00136 (
00137 Actor *npc
00138 )
00139 {
00140 const int maxparty = sizeof(dead_party)/sizeof(dead_party[0]);
00141 if (!npc || dead_party_count == maxparty || in_dead_party(npc) >= 0)
00142 return false;
00143 dead_party[dead_party_count++] = npc->get_npc_num();
00144 return true;
00145 }
00146
00147
00148
00149
00150
00151
00152
00153 bool Party_manager::remove_from_dead_party
00154 (
00155 Actor *npc
00156 )
00157 {
00158 if (!npc)
00159 return false;
00160 int id = in_dead_party(npc);
00161 if (id == -1)
00162 return false;
00163 int npc_num = npc->get_npc_num();
00164
00165 for (int i = id + 1; i < dead_party_count; i++)
00166 dead_party[i - 1] = dead_party[i];
00167 dead_party_count--;
00168 dead_party[dead_party_count] = 0;
00169 return true;
00170 }
00171
00172
00173
00174
00175
00176 void Party_manager::update_party_status
00177 (
00178 Actor *npc
00179 )
00180 {
00181 if (npc->is_dead())
00182 {
00183
00184 if (remove_from_party(npc))
00185 add_to_dead_party(npc);
00186 }
00187 else
00188 {
00189 if (remove_from_dead_party(npc))
00190 add_to_party(npc);
00191 }
00192 }
00193
00194
00195
00196
00197
00198
00199 void Party_manager::link_party
00200 (
00201 )
00202 {
00203
00204 gwin->get_main_actor()->set_flag(Obj_flags::in_party);
00205
00206 gwin->get_main_actor()->set_flag_recursively(Obj_flags::okay_to_take);
00207 const int maxparty = sizeof(party)/sizeof(party[0]);
00208 int tmp_party[maxparty];
00209 int tmp_party_count = party_count;
00210 int i;
00211 for (i = 0; i < maxparty; i++)
00212 tmp_party[i] = party[i];
00213 party_count = dead_party_count = 0;
00214
00215 for (i = 0; i < tmp_party_count; i++)
00216 {
00217 if (party[i] <= 0)
00218 continue;
00219 Actor *npc = gwin->get_npc(party[i]);
00220 int oldid;
00221 if (!npc ||
00222
00223 ((oldid = npc->get_party_id()) >= 0 &&
00224 oldid < party_count))
00225 continue;
00226 int npc_num = npc->get_npc_num();
00227 if (npc->is_dead())
00228 {
00229 npc->set_party_id(-1);
00230 if (dead_party_count >=
00231 sizeof(dead_party)/sizeof(dead_party[0]))
00232 continue;
00233 dead_party[dead_party_count++] = npc_num;
00234 continue;
00235 }
00236 npc->set_party_id(party_count);
00237 party[party_count++] = npc_num;
00238
00239
00240
00241 npc->set_flag_recursively(Obj_flags::okay_to_take);
00242 npc->set_flag (Obj_flags::in_party);
00243 }
00244 }
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254 static int followers[EXULT_PARTY_MAX + 1][2] = {
00255 {0, 1},
00256 {2, 3},
00257 {-1, 4},
00258 {7, -1},
00259 {5, 6},
00260 {-1, 8},
00261 {-1, -1}, {-1, -1}, {-1, -1}};
00262
00263
00264
00265
00266
00267 static int left_offsets[4][2] = {
00268 {-2, 2},
00269 {-2, -2},
00270 {2, -2},
00271 {2, 2} };
00272 static int right_offsets[4][2] = {
00273 {2, 2},
00274 {-2, 2},
00275 {-2, -2},
00276 {2, -2} };
00277
00278
00279
00280
00281
00282
00283 void Party_manager::get_followers
00284 (
00285 int dir
00286 )
00287 {
00288 validcnt = 0;
00289 for (int i = 0; i < party_count; i++)
00290 {
00291 Actor *npc = gwin->get_npc(party[i]);
00292 if (!npc || npc->get_flag(Obj_flags::asleep) ||
00293 npc->get_flag(Obj_flags::paralyzed) ||
00294 npc->is_dead())
00295 continue;
00296 if (npc->in_queue())
00297 continue;
00298 valid[validcnt++] = npc;
00299 }
00300 if (validcnt)
00301 move_followers(gwin->get_main_actor(), -1, dir);
00302 }
00303
00304
00305
00306
00307
00308
00309 void Party_manager::move_followers
00310 (
00311 Actor *npc,
00312 int vindex,
00313 int dir
00314 )
00315 {
00316 int id = npc->get_party_id();
00317 Tile_coord pos = npc->get_tile();
00318 int lnum = followers[1 + id][0], rnum = followers[1 + id][1];
00319 if (lnum == -1 && rnum == -1)
00320 return;
00321 int dir4 = dir/2;
00322 Actor *lnpc = (lnum == -1 || lnum >= validcnt) ? 0 : valid[lnum];
00323 Actor *rnpc = (rnum == -1 || rnum >= validcnt) ? 0 : valid[rnum];
00324 int ldir = -1, rdir = -1;
00325
00326 if (lnpc)
00327 ldir = step(lnpc, npc, dir, pos + Tile_coord(
00328 left_offsets[dir4][0], left_offsets[dir4][1], 0));
00329 if (rnpc)
00330 rdir = step(rnpc, npc, dir, pos + Tile_coord(
00331 right_offsets[dir4][0], right_offsets[dir4][1], 0));
00332 if (ldir >= 0 && !lnpc->is_dead())
00333 move_followers(lnpc, lnum, ldir);
00334 if (rdir >= 0 && !rnpc->is_dead())
00335 move_followers(rnpc, rnum, rdir);
00336 }
00337
00338
00339
00340
00341
00342
00343 inline Tile_coord Get_step_tile
00344 (
00345 Tile_coord pos,
00346 Tile_coord dest,
00347 int dir
00348 )
00349 {
00350 int dx = dest.tx - pos.tx, dy = dest.ty - pos.ty;
00351 if (dx < -1)
00352 dx = -1;
00353 else if (dx > 1)
00354 dx = 1;
00355 if (dy < -1)
00356 dy = -1;
00357 else if (dy > 1)
00358 dy = 1;
00359 return pos + Tile_coord(dx, dy, 0);
00360 }
00361
00362
00363
00364
00365
00366
00367
00368
00369 static Actor *Find_member_blocking
00370 (
00371 Tile_coord pos,
00372 int first
00373 )
00374 {
00375 Game_window *gwin = Game_window::get_instance();
00376 Party_manager *pman = gwin->get_party_man();
00377 int count = pman->get_count();
00378
00379 for (int i = first; i < count; i++)
00380 {
00381 Actor *npc = gwin->get_npc(pman->get_member(i));
00382 pos.tz = npc->get_lift();
00383
00384 if (npc->blocks(pos))
00385 return npc;
00386 }
00387 return 0;
00388 }
00389
00390
00391
00392
00393
00394 inline int Get_dir_from
00395 (
00396 Actor *npc,
00397 Tile_coord& from
00398 )
00399 {
00400 Tile_coord pos = npc->get_tile();
00401 return Get_direction(from.ty - pos.ty, pos.tx - from.tx);
00402 }
00403
00404
00405
00406
00407
00408 inline bool Clear_to_leader
00409 (
00410 Actor *npc,
00411 Actor *leader,
00412 Tile_coord from
00413 )
00414 {
00415 Tile_coord dest = leader->get_tile();
00416 int dist = dest.distance(from);
00417 if (dist > 4)
00418 return false;
00419 while (--dist)
00420 {
00421 int dir = Get_dir_from(leader, from);
00422 Tile_coord next = from.get_neighbor(dir);
00423 if (npc->is_blocked(next, &from))
00424 {
00425 Actor *bnpc = Find_member_blocking(next, 0);
00426 if (!bnpc)
00427 return false;
00428 next.tz = bnpc->get_lift();
00429 }
00430 from = next;
00431 }
00432 int difftz = from.tz - dest.tz;
00433 return difftz*difftz <= 1;
00434 }
00435
00436
00437
00438
00439
00440
00441
00442 const int max_cost = 10000;
00443
00444 static int Get_cost
00445 (
00446 Actor *npc,
00447 Actor *leader,
00448 Tile_coord to,
00449 Actor **find_blocking = 0
00450 )
00451 {
00452 int cost = 0;
00453 if (find_blocking)
00454 *find_blocking = 0;
00455 if (npc->is_blocked(to))
00456 {
00457 if (find_blocking)
00458 {
00459 *find_blocking = Find_member_blocking(to,
00460 1 + npc->get_party_id());
00461 if (!*find_blocking)
00462 return max_cost;
00463 to.tz = (*find_blocking)->get_lift();
00464 cost += 1;
00465 }
00466 else
00467 return max_cost;
00468 }
00469 Tile_coord lpos = leader->get_tile();
00470 int difftz = to.tz - lpos.tz,
00471 diffty = Tile_coord::delta(to.ty, lpos.ty),
00472 difftx = Tile_coord::delta(to.tx, lpos.tx);
00473
00474 int xydist2 = diffty*diffty + difftx*difftx;
00475 cost += difftz*difftz + xydist2;
00476 if (xydist2 > 2)
00477 {
00478 if (!Clear_to_leader(npc, leader, to))
00479 cost += 16;
00480 }
00481 return cost;
00482 }
00483
00484
00485
00486
00487
00488
00489
00490 static bool Take_best_step
00491 (
00492 Actor *npc,
00493 Actor *leader,
00494 Tile_coord& pos,
00495 int frame,
00496 int dir
00497 )
00498 {
00499 static int deltadir[] = {0, 1, 7, 2, 6, 3, 5};
00500 const int cnt = sizeof(deltadir)/sizeof(deltadir[0]);
00501
00502 int best_cost = max_cost + 8;
00503 Tile_coord best(-1, -1, -1);
00504 Actor *best_in_way = 0;
00505 for (int i = 0; i < cnt; i++)
00506 {
00507 int diri = (dir + deltadir[i])%8;
00508 Tile_coord to = pos.get_neighbor(diri);
00509 Actor *in_way;
00510 int cost = Get_cost(npc, leader, to, &in_way);
00511 if (cost < best_cost)
00512 {
00513 best_cost = cost;
00514 best_in_way = in_way;
00515 best = to;
00516 }
00517 }
00518 if (best_cost >= max_cost)
00519 return false;
00520 if (!best_in_way)
00521 return npc->step(best, frame)!=0;
00522 best = best_in_way->get_tile();
00523 npc->remove_this(true);
00524 best_in_way->remove_this(true);
00525 npc->set_frame(frame);
00526 npc->move(best);
00527 best_in_way->move(pos);
00528 return true;
00529 }
00530
00531
00532
00533
00534
00535 inline bool Is_step_okay
00536 (
00537 Actor *npc,
00538 Actor *leader,
00539 Tile_coord to
00540 )
00541 {
00542 if (npc->is_blocked(to))
00543 return false;
00544 int difftz = to.tz - leader->get_lift();
00545 difftz *= difftz;
00546 if (difftz > 4)
00547 return false;
00548
00549 int dist = to.distance(leader->get_tile());
00550 if (dist == 1)
00551 return (difftz <= 1);
00552 if (!Clear_to_leader(npc, leader, to))
00553 return false;
00554 return true;
00555 }
00556
00557
00558
00559
00560
00561
00562
00563 int Party_manager::step
00564 (
00565 Actor *npc,
00566 Actor *leader,
00567 int dir,
00568 Tile_coord dest
00569 )
00570 {
00571 Tile_coord pos = npc->get_tile();
00572 Tile_coord to = Get_step_tile(pos, dest, dir);
00573 if (to.tx == pos.tx && to.ty == pos.ty)
00574 return dir;
00575
00576 if (npc->in_queue() || npc->is_moving())
00577 cout << npc->get_name() << " shouldn't be stepping!" << endl;
00578 Frames_sequence *frames = npc->get_frames(dir);
00579 int& step_index = npc->get_step_index();
00580 if (!step_index)
00581 step_index = frames->find_unrotated(npc->get_framenum());
00582
00583 int frame = frames->get_next(step_index);
00584
00585 if (Is_step_okay(npc, leader, to) && npc->step(to, frame))
00586 ;
00587
00588
00589 else if (npc->is_dead() ||
00590 !Take_best_step(npc, leader, pos, frame,
00591 npc->get_direction(dest)))
00592 {
00593 cout << npc->get_name() << " failed to take a step" << endl;
00594 frames->decrement(step_index);
00595 return dir;
00596 }
00597 return Get_dir_from(npc, pos);
00598 }
00599