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 "SDL_timer.h"
00026 #include "schedule.h"
00027 #include "actors.h"
00028 #include "Zombie.h"
00029 #include "gamewin.h"
00030 #include "gameclk.h"
00031 #include "gamemap.h"
00032 #include "actions.h"
00033 #include "dir.h"
00034 #include "items.h"
00035 #include "game.h"
00036 #include "paths.h"
00037 #include "ucmachine.h"
00038 #include "ucsched.h"
00039 #include "ucscriptop.h"
00040 #include "monstinf.h"
00041
00042 #ifndef UNDER_CE
00043 using std::cout;
00044 using std::endl;
00045 using std::rand;
00046 #endif
00047
00048
00049
00050
00051 Schedule::Schedule
00052 (
00053 Actor *n
00054 ) : npc(n), blocked(-1, -1, -1), street_maintenance_failures(0),
00055 street_maintenance_time(0)
00056 {
00057 prev_type = npc ? npc->get_schedule_type() : -1;
00058 }
00059
00060
00061
00062
00063
00064
00065
00066 void Schedule::set_action_sequence
00067 (
00068 Actor *actor,
00069 Tile_coord dest,
00070 Actor_action *when_there,
00071 bool from_off_screen,
00072 int delay
00073 )
00074 {
00075 actor->set_action(Actor_action::create_action_sequence(
00076 actor, dest, when_there, from_off_screen));
00077 actor->start(250, delay);
00078 }
00079
00080
00081
00082
00083
00084
00085
00086 int Schedule::try_street_maintenance
00087 (
00088 )
00089 {
00090
00091 static int night[] = {322, 372, 889};
00092 static int sinight[] = {290, 291, 889};
00093 static int day[] = {290, 291, 526};
00094
00095 long curtime = Game::get_ticks();
00096 if (curtime < street_maintenance_time)
00097 return 0;
00098 if (npc->Actor::get_npc_num() <= 0 ||
00099 npc == gwin->get_camera_actor())
00100 return 0;
00101
00102 street_maintenance_time = curtime + 30000 +
00103 street_maintenance_failures*5000;
00104 int *shapes;
00105 int hour = gclock->get_hour();
00106 bool bg = (Game::get_game_type() == BLACK_GATE);
00107 if (hour >= 9 && hour < 18)
00108 shapes = &day[0];
00109 else if (hour >= 18 || hour < 6)
00110 shapes = bg ? &night[0] : &sinight[0];
00111 else
00112 return 0;
00113 Tile_coord npcpos = npc->get_tile();
00114
00115 Rectangle winrect = gwin->get_win_tile_rect();
00116 winrect.enlarge(winrect.w/4);
00117 if (!winrect.has_point(npcpos.tx, npcpos.ty))
00118 return 0;
00119
00120 Actor_pathfinder_client cost(npc, 1);
00121 Game_object *found = 0;
00122 Actor_action *pact;
00123 for (int i = 0; !found && i < sizeof(night)/sizeof(night[0]); i++)
00124 {
00125 Game_object_vector objs;
00126 int cnt = npc->find_nearby(objs, shapes[i], 20, 0);
00127 int j;
00128 for (j = 0; j < cnt; j++)
00129 {
00130 Game_object *obj = objs[j];
00131 int shnum = obj->get_shapenum();
00132 if (!bg &&
00133 (shnum == 290 || shnum == 291))
00134
00135 if ((shapes == day) !=
00136 (obj->get_framenum() <= 3))
00137 continue;
00138 if ((pact = Path_walking_actor_action::create_path(
00139 npcpos, obj->get_tile(), cost)) != 0)
00140 {
00141 found = obj;
00142 break;
00143 }
00144 street_maintenance_failures++;
00145 }
00146 }
00147 if (!found)
00148 return 0;
00149
00150 npc->set_schedule_type(Schedule::street_maintenance,
00151 new Street_maintenance_schedule(npc, pact, found));
00152 street_maintenance_failures = 0;
00153 return 1;
00154 }
00155
00156
00157
00158
00159
00160 int Schedule::get_actual_type
00161 (
00162 Actor *npc
00163 )
00164 {
00165 return npc->get_schedule_type();
00166 }
00167
00168
00169
00170
00171
00172 Street_maintenance_schedule::Street_maintenance_schedule
00173 (
00174 Actor *n,
00175 Actor_action *p,
00176 Game_object *o
00177 ) : Schedule(n), obj(o), shapenum(o->get_shapenum()),
00178 framenum(o->get_framenum()), paction(p)
00179 {
00180 }
00181
00182
00183
00184
00185
00186 void Street_maintenance_schedule::now_what
00187 (
00188 )
00189 {
00190 if (paction)
00191 {
00192 cout << npc->get_name() <<
00193 " walking for street maintenance" << endl;
00194 npc->set_action(paction);
00195 npc->start(250);
00196 paction = 0;
00197 return;
00198 }
00199 if (npc->distance(obj) == 1 &&
00200 obj->get_shapenum() == shapenum && obj->get_framenum() == framenum)
00201 {
00202 cout << npc->get_name() <<
00203 " about to perform street maintenance" << endl;
00204 int dir = npc->get_direction(obj);
00205 signed char frames[2];
00206 frames[0] = npc->get_dir_framenum(dir, Actor::standing);
00207 frames[1] = npc->get_dir_framenum(dir, 3);
00208 signed char standframe = frames[0];
00209 npc->set_action(new Sequence_actor_action(
00210 new Frames_actor_action(frames, sizeof(frames)),
00211 new Activate_actor_action(obj),
00212 new Frames_actor_action(&standframe, 1)));
00213 npc->start(250);
00214 switch (shapenum)
00215 {
00216 case 322:
00217 case 372:
00218 npc->say(first_close_shutters, last_close_shutters);
00219 break;
00220 case 290:
00221 case 291:
00222 if (Game::get_game_type() == BLACK_GATE)
00223 npc->say(first_open_shutters,
00224 last_open_shutters);
00225 else
00226 if (framenum <= 3)
00227 npc->say(first_open_shutters,
00228 last_open_shutters);
00229 else
00230 npc->say(first_close_shutters,
00231 last_close_shutters);
00232 break;
00233 case 889:
00234 npc->say(first_lamp_on, last_lamp_on);
00235 break;
00236 case 526:
00237 npc->say(lamp_off, lamp_off);
00238 break;
00239 }
00240 shapenum = 0;
00241 return;
00242 }
00243 cout << npc->get_name() <<
00244 " done with street maintenance" << endl;
00245
00246 int period = gclock->get_hour()/3;
00247 npc->update_schedule(period, 7, 0);
00248 }
00249
00250
00251
00252
00253
00254 int Street_maintenance_schedule::get_actual_type
00255 (
00256 Actor *
00257 )
00258 {
00259 return prev_type;
00260 }
00261
00262
00263
00264
00265
00266 void Follow_avatar_schedule::now_what
00267 (
00268 )
00269 {
00270 bool is_blocked = blocked.tx != -1;
00271 blocked = Tile_coord(-1, -1, -1);
00272 if (npc->get_flag(Obj_flags::asleep) || npc->is_dead() ||
00273 npc->get_flag(Obj_flags::paralyzed) ||
00274 gwin->main_actor_dont_move())
00275 return;
00276 Actor *av = gwin->get_main_actor();
00277 Tile_coord leaderpos = av->get_tile();
00278 Tile_coord pos = npc->get_tile();
00279 int dist2lead = leaderpos.distance(pos);
00280 if (!av->is_moving() &&
00281 dist2lead <= 6)
00282 return;
00283 uint32 curtime = SDL_GetTicks();
00284 if (!is_blocked)
00285 {
00286 npc->follow(av);
00287 return;
00288 }
00289 if (curtime < next_path_time)
00290 {
00291 npc->start(gwin->get_std_delay(), next_path_time - curtime);
00292 return;
00293 }
00294
00295 Map_chunk::Find_spot_where where = Map_chunk::anywhere;
00296
00297 where = gwin->is_main_actor_inside() ?
00298 Map_chunk::inside : Map_chunk::outside;
00299 Tile_coord goal = Map_chunk::find_spot(leaderpos, 3, npc, 0, where);
00300 if (goal.tx == -1)
00301 {
00302 cout << npc->get_name() << " can't find free spot" << endl;
00303 next_path_time = SDL_GetTicks() + 1000;
00304 return;
00305 }
00306
00307 int speed = av->get_frame_time();
00308 if (!speed)
00309 speed = gwin->get_std_delay();
00310 if (pos.distance(goal) <= 3)
00311 return;
00312 #if 0
00313 #ifdef DEBUG
00314 cout << npc->get_name() << " at distance " << dist2lead
00315 << " trying to catch up." << endl;
00316 #endif
00317 #endif
00318
00319 if (npc->walk_path_to_tile(goal, speed - speed/4, 0, 3, 1))
00320 return;
00321 cout << "... but failed to find path." << endl;
00322
00323 int ok;
00324
00325 Rectangle wrect = gwin->get_win_tile_rect();
00326 if (wrect.has_point(pos.tx - pos.tz/2, pos.ty - pos.tz/2))
00327
00328 ok = npc->walk_path_to_tile(Tile_coord(-1, -1, -1),
00329 speed - speed/4, 0);
00330 else
00331 ok = npc->approach_another(av);
00332 if (!ok)
00333 next_path_time = SDL_GetTicks() + 1000;
00334 }
00335
00336
00337
00338
00339
00340 void Wait_schedule::now_what
00341 (
00342 )
00343 {
00344 }
00345
00346
00347
00348
00349
00350 Pace_schedule *Pace_schedule::create_horiz
00351 (
00352 Actor *n
00353 )
00354 {
00355 Tile_coord t = n->get_tile();
00356 return (new Pace_schedule(n, Tile_coord(t.tx - 4, t.ty, t.tz),
00357 Tile_coord(t.tx + 4, t.ty, t.tz)));
00358 }
00359
00360
00361
00362
00363
00364 Pace_schedule *Pace_schedule::create_vert
00365 (
00366 Actor *n
00367 )
00368 {
00369 Tile_coord t = n->get_tile();
00370 return (new Pace_schedule(n, Tile_coord(t.tx, t.ty - 4, t.tz),
00371 Tile_coord(t.tx, t.ty + 4, t.tz)));
00372 }
00373
00374
00375
00376
00377
00378 void Pace_schedule::now_what
00379 (
00380 )
00381 {
00382 if (rand() % 6 == 0)
00383 if (try_street_maintenance())
00384 return;
00385 which = !which;
00386 int delay = 750;
00387 if (blocked.tx != -1)
00388 {
00389 Game_object *obj = Game_object::find_blocking(blocked);
00390 blocked.tx = -1;
00391 Monster_info *minfo = npc->get_info().get_monster_info();
00392 if (obj && obj->as_actor() != 0 &&
00393 (!minfo || !minfo->cant_yell()))
00394 {
00395 npc->say(first_move_aside, last_move_aside);
00396 delay = 1200;
00397 }
00398 }
00399
00400 npc->walk_to_tile(which ? p1 : p0, gwin->get_std_delay(), delay);
00401 }
00402
00403
00404
00405
00406
00407 void Eat_at_inn_schedule::now_what
00408 (
00409 )
00410 {
00411 int frnum = npc->get_framenum();
00412 if ((frnum&0xf) != Actor::sit_frame)
00413 {
00414 if (!Sit_schedule::set_action(npc))
00415 {
00416 npc->start(250, 5000);
00417 return;
00418 }
00419 }
00420 Game_object_vector foods;
00421 int cnt = npc->find_nearby(foods, 377, 2, 0);
00422 if (cnt)
00423 {
00424 Game_object *food = 0;
00425 int dist = 500;
00426 for (Game_object_vector::const_iterator it = foods.begin();
00427 it != foods.end(); ++it)
00428 {
00429 Game_object *obj = *it;
00430 int odist = obj->distance(npc);
00431 if (odist < dist)
00432 {
00433 dist = odist;
00434 food = obj;
00435 }
00436 }
00437 if (rand()%5 == 0)
00438 {
00439 gwin->add_dirty(food);
00440 food->remove_this();
00441 }
00442 if (rand()%4)
00443 npc->say(first_munch, last_munch);
00444 }
00445 else if (rand()%4)
00446 npc->say(first_more_food, last_more_food);
00447
00448 npc->start(250, 5000 + rand()%12000);
00449 }
00450
00451
00452
00453
00454
00455 Actor *Find_congregant
00456 (
00457 Actor *npc
00458 )
00459 {
00460 Actor_vector vec, vec2;
00461 if (!npc->find_nearby_actors(vec, c_any_shapenum, 16))
00462 return 0;
00463 vec2.reserve(vec.size());
00464 for (Actor_vector::const_iterator it = vec.begin();
00465 it != vec.end(); ++it)
00466 {
00467 Actor *act = *it;
00468 if (act->get_schedule_type() == Schedule::sit &&
00469 !act->is_in_party())
00470 vec2.push_back(act);
00471 }
00472 return vec2.size() ? vec2[rand()%vec2.size()] : 0;
00473 }
00474
00475
00476
00477
00478
00479 void Preach_schedule::now_what
00480 (
00481 )
00482 {
00483 switch (state)
00484 {
00485 case find_podium:
00486 {
00487 Game_object_vector vec;
00488 if (!npc->find_nearby(vec, 697, 17, 0))
00489 {
00490 npc->set_schedule_type(loiter);
00491 return;
00492 }
00493 Game_object *podium = vec[0];
00494 Tile_coord pos = podium->get_tile();
00495 static int deltas[4][2] = {{-1, 0},{1, 0},{0, -2},{0, 1}};
00496 int frnum = podium->get_framenum()%4;
00497 pos.tx += deltas[frnum][0];
00498 pos.ty += deltas[frnum][1];
00499 Actor_pathfinder_client cost(npc, 0);
00500 Actor_action *pact = Path_walking_actor_action::create_path(
00501 npc->get_tile(), pos, cost);
00502 if (pact)
00503 {
00504 state = at_podium;
00505 npc->set_action(new Sequence_actor_action(pact,
00506 new Face_pos_actor_action(podium, 200)));
00507 npc->start(gwin->get_std_delay());
00508 return;
00509 }
00510 npc->start(250, 5000 + rand()%5000);
00511 return;
00512 }
00513 case at_podium:
00514 if (rand()%2)
00515 npc->start(gwin->get_std_delay(), rand()%3000);
00516 else
00517 {
00518 if (rand()%3)
00519 state = exhort;
00520 else if ((GAME_SI) || rand()%3)
00521 state = visit;
00522 else
00523 state = find_icon;
00524 npc->start(gwin->get_std_delay(), 2000 + rand()%2000);
00525 }
00526 return;
00527 case exhort:
00528 {
00529 signed char frames[8];
00530 int cnt = 1 + rand()%(sizeof(frames) - 1);
00531
00532 static char choices[3] = {0, 8, 9};
00533 for (int i = 0; i < cnt - 1; i++)
00534 frames[i] = npc->get_dir_framenum(
00535 choices[rand()%(sizeof(choices))]);
00536
00537 frames[cnt - 1] = npc->get_dir_framenum(Actor::standing);
00538 npc->set_action(new Frames_actor_action(frames, cnt, 250));
00539 npc->start(gwin->get_std_delay());
00540 npc->say(first_preach, last_preach);
00541 state = at_podium;
00542 Actor *member = Find_congregant(npc);
00543 if (member)
00544 {
00545 Usecode_script *scr = new Usecode_script(member);
00546 scr->add(Ucscript::delay_ticks, 3);
00547 scr->add(Ucscript::face_dir, member->get_dir_facing());
00548 scr->add(Ucscript::npc_frame + Actor::standing);
00549 scr->add(Ucscript::say, item_names[first_amen +
00550 rand()%(last_amen - first_amen + 1)]);
00551 scr->add(Ucscript::delay_ticks, 2);
00552 scr->add(Ucscript::npc_frame + Actor::sit_frame);
00553 scr->start();
00554 }
00555 return;
00556 }
00557 case visit:
00558 {
00559 state = find_podium;
00560 npc->start(gwin->get_std_delay(), 1000 + rand()%2000);
00561 Actor *member = Find_congregant(npc);
00562 if (!member)
00563 return;
00564 Tile_coord pos = member->get_tile();
00565 Actor_pathfinder_client cost(npc, 1);
00566 Actor_action *pact = Path_walking_actor_action::create_path(
00567 npc->get_tile(), pos, cost);
00568 if (!pact)
00569 return;
00570 npc->set_action(new Sequence_actor_action(pact,
00571 new Face_pos_actor_action(member, 200)));
00572 state = talk_member;
00573 return;
00574 }
00575 case talk_member:
00576 state = find_podium;
00577 npc->say(first_preach2, last_preach2);
00578 npc->start(250, 2000);
00579 return;
00580 case find_icon:
00581 {
00582 state = find_podium;
00583 npc->start(2*gwin->get_std_delay());
00584 Game_object *icon = npc->find_closest(724);
00585 if (!icon)
00586 return;
00587 Tile_coord pos = icon->get_tile();
00588 pos.tx += 2;
00589 pos.ty -= 1;
00590 Actor_pathfinder_client cost(npc, 0);
00591 Actor_action *pact = Path_walking_actor_action::create_path(
00592 npc->get_tile(), pos, cost);
00593 if (pact)
00594 {
00595 static char f[] = {Actor::standing, Actor::bow_frame,
00596 Actor::kneel_frame, Actor::kneel_frame,
00597 Actor::kneel_frame, Actor::kneel_frame,
00598 Actor::bow_frame, Actor::standing};
00599 npc->set_action(pact);
00600 state = pray;
00601 }
00602 return;
00603 }
00604 case pray:
00605 {
00606 Usecode_script *scr = new Usecode_script(npc);
00607 (*scr) << Ucscript::face_dir << 6
00608 << (Ucscript::npc_frame + Actor::standing)
00609 << (Ucscript::npc_frame + Actor::bow_frame)
00610 << Ucscript::delay_ticks << 3
00611 << (Ucscript::npc_frame + Actor::kneel_frame);
00612 scr->add(Ucscript::say, item_names[first_amen + rand()%2]);
00613 (*scr) << Ucscript::delay_ticks << 5
00614 << (Ucscript::npc_frame + Actor::bow_frame)
00615 << Ucscript::delay_ticks << 3
00616 << (Ucscript::npc_frame + Actor::standing);
00617 scr->start();
00618 state = find_podium;
00619 npc->start(2*gwin->get_std_delay(), 4000);
00620 return;
00621 }
00622 default:
00623 state = find_podium;
00624 npc->start(250);
00625 return;
00626 }
00627 }
00628
00629
00630
00631
00632
00633 void Patrol_schedule::now_what
00634 (
00635 )
00636 {
00637 if (sitting)
00638 {
00639
00640 if ((npc->get_framenum()&0xf) == Actor::sit_frame)
00641 npc->start(250, 5000 + rand()%10000);
00642 else
00643 npc->start(250, rand()%1000);
00644 sitting = false;
00645 find_next = true;
00646 return;
00647 }
00648 if (rand() % 8 == 0)
00649 if (try_street_maintenance())
00650 return;
00651 const int PATH_SHAPE = 607;
00652 Game_object *path;
00653 if (!find_next &&
00654 pathnum >= 0 &&
00655 pathnum < paths.size() && (path = paths[pathnum]) != 0 &&
00656 npc->distance(path) < 2)
00657
00658
00659 switch (path->get_quality()&31)
00660 {
00661 case 0:
00662 break;
00663 case 1:
00664 pathnum = -1;
00665 dir = 1;
00666 break;
00667 case 2:
00668 break;
00669 case 3:
00670 if (Sit_schedule::set_action(npc))
00671 {
00672 sitting = true;
00673 return;
00674 }
00675 break;
00676 case 4:
00677 case 5:
00678 case 6:
00679 break;
00680 case 7:
00681 case 8:
00682 if (pathnum == 0 && dir == -1)
00683 dir = 1;
00684 else if (pathnum > 0 && dir == 1)
00685 dir = -1;
00686
00687 break;
00688 case 9:
00689 case 10:
00690 case 11:
00691 case 12:
00692 case 13:
00693 case 14:
00694 break;
00695 case 15:
00696 {
00697 Usecode_script *scr = new Usecode_script(npc);
00698
00699
00700
00701 (*scr) << Ucscript::dont_halt <<
00702 Ucscript::usecode2 << npc->get_usecode() <<
00703 static_cast<int>(Usecode_machine::npc_proximity);
00704 scr->start();
00705 find_next = true;
00706 npc->start(250, 500);
00707 return;
00708 }
00709 case 16:
00710 case 17:
00711 case 18:
00712 case 19:
00713 case 20:
00714 case 21:
00715 case 22:
00716 case 23:
00717 case 24:
00718 case 25:
00719 case 26:
00720 case 27:
00721 default:
00722 break;
00723 }
00724 pathnum += dir;
00725 find_next = false;
00726
00727 path = pathnum >= 0 && pathnum < paths.size() ? paths[pathnum] : 0;
00728 if (!path)
00729 {
00730 Game_object_vector nearby;
00731 npc->find_nearby(nearby, PATH_SHAPE, 25, 0);
00732 int best_dist = 1000;
00733 for (Game_object_vector::const_iterator it = nearby.begin();
00734 it != nearby.end(); ++it)
00735 {
00736 Game_object *obj = *it;
00737 int framenum = obj->get_framenum();
00738 int dist;
00739 if (framenum == pathnum &&
00740 (dist = obj->distance(npc)) < best_dist)
00741 {
00742 path = obj;
00743 best_dist = dist;
00744 }
00745 }
00746 if (path)
00747 {
00748 failures = 0;
00749 paths.put(pathnum, path);
00750 }
00751 else
00752 {
00753 failures++;
00754 dir = 1;
00755 if (pathnum == 0)
00756 {
00757 if (failures < 4)
00758 {
00759 pathnum = -1;
00760 npc->start(200, 500);
00761 return;
00762 }
00763
00764 }
00765 else
00766 {
00767 pathnum = 0;
00768 path = paths.size() ? paths[0] : 0;
00769 }
00770 }
00771 if (!path)
00772 {
00773
00774 Tile_coord pos = npc->get_tile();
00775 int dist = failures + 2;
00776 Tile_coord delta = Tile_coord(rand()%dist - dist/2,
00777 rand()%dist - dist, 0);
00778 npc->walk_to_tile(pos + delta, gwin->get_std_delay(),
00779 failures*300);
00780 int pathcnt = paths.size();
00781 pathnum = rand()%(pathcnt < 4 ? 4 : pathcnt);
00782 return;
00783 }
00784 }
00785 Tile_coord d = path->get_tile();
00786 if (!npc->walk_path_to_tile(d, gwin->get_std_delay(), rand()%1000))
00787 {
00788
00789 d = Map_chunk::find_spot(d, 1, npc->get_shapenum(),
00790 npc->get_framenum(), 1);
00791 if (d.tx == -1 || !npc->walk_path_to_tile(d,
00792 gwin->get_std_delay(), rand()%1000))
00793 {
00794 npc->start(200, 2000);
00795 return;
00796 }
00797 }
00798 }
00799
00800
00801
00802
00803
00804 void Talk_schedule::now_what
00805 (
00806 )
00807 {
00808
00809
00810 if (phase != 0 && phase != 4 &&
00811 npc->distance(gwin->get_main_actor()) < 8)
00812 phase = 3;
00813
00814 switch (phase)
00815 {
00816 case 0:
00817 {
00818 if (npc->distance(gwin->get_main_actor()) > 50)
00819 {
00820
00821 npc->start(250, 5000);
00822 return;
00823 }
00824
00825 Actor_pathfinder_client cost(npc, 5);
00826 Actor_action *pact = Path_walking_actor_action::create_path(
00827 npc->get_tile(),
00828 gwin->get_main_actor()->get_tile(), cost);
00829 if (!pact)
00830 {
00831 #ifdef DEBUG
00832 cout << "Talk: Failed to find path for " <<
00833 npc->get_name() << endl;
00834 #endif
00835 npc->follow(gwin->get_main_actor());
00836 }
00837 else
00838 {
00839
00840
00841 npc->set_action(pact);
00842 npc->start(400, 250);
00843 }
00844 phase++;
00845 return;
00846 }
00847 case 1:
00848 case 2:
00849 {
00850 int dx = 1 - 2*(rand()%2);
00851 npc->walk_to_tile(npc->get_tile() +
00852 Tile_coord(dx, -dx, 0), 300, 500);
00853
00854
00855
00856 phase = 3;
00857 return;
00858 }
00859 case 3:
00860
00861 if (!Fast_pathfinder_client::is_grabable(
00862 npc->get_tile(),
00863 gwin->get_main_actor()->get_tile()))
00864 {
00865 phase = 0;
00866 npc->start(250, 1000);
00867 return;
00868 }
00869
00870 npc->change_frame(npc->get_dir_framenum(npc->get_direction(
00871 gwin->get_main_actor()), Actor::standing));
00872 phase++;
00873 npc->start(250, 250);
00874 break;
00875 case 4:
00876 npc->stop();
00877
00878 if (Game::get_game_type() == SERPENT_ISLE)
00879 npc->activate(9);
00880 else
00881 npc->activate(1);
00882
00883
00884 gwin->paint();
00885 return;
00886 default:
00887 break;
00888 }
00889 }
00890
00891
00892
00893
00894
00895 Loiter_schedule::Loiter_schedule
00896 (
00897 Actor *n,
00898 int d
00899 ) : Schedule(n), center(n->get_tile()), dist(d)
00900 {
00901 }
00902
00903
00904
00905
00906
00907 void Loiter_schedule::now_what
00908 (
00909 )
00910 {
00911 if (rand() % 3 == 0)
00912 if (try_street_maintenance())
00913 return;
00914 int newx = center.tx - dist + rand()%(2*dist);
00915 int newy = center.ty - dist + rand()%(2*dist);
00916
00917 npc->walk_to_tile(newx, newy, center.tz, 2*gwin->get_std_delay(),
00918 rand()%2000);
00919 }
00920
00921
00922
00923
00924
00925 void Kid_games_schedule::now_what
00926 (
00927 )
00928 {
00929 Tile_coord pos = npc->get_tile();
00930 Actor *kid = 0;
00931
00932 while (!kids.empty())
00933 {
00934 kid = kids.pop();
00935 if (npc->distance(kid) < 16)
00936 break;
00937 kid = 0;
00938 }
00939
00940 if (kid)
00941 {
00942 Fast_pathfinder_client cost(1);
00943 Actor_action *pact = Path_walking_actor_action::create_path(
00944 pos, kid->get_tile(), cost);
00945 if (pact)
00946 {
00947 npc->set_action(pact);
00948 npc->start(100, 250);
00949 return;
00950 }
00951 }
00952 else
00953 {
00954 Actor_vector vec;
00955 npc->find_nearby_actors(vec, c_any_shapenum, 16);
00956 for (Actor_vector::const_iterator it = vec.begin();
00957 it != vec.end(); ++it)
00958 {
00959 Actor *act = *it;
00960 if (act->get_schedule_type() == kid_games)
00961 kids.push(act);
00962 }
00963 }
00964 Loiter_schedule::now_what();
00965 }
00966
00967
00968
00969
00970
00971 void Dance_schedule::now_what
00972 (
00973 )
00974 {
00975 Tile_coord dest = center;
00976 dest.tx += -dist + rand()%(2*dist);
00977 dest.ty += -dist + rand()%(2*dist);
00978 Tile_coord cur = npc->get_tile();
00979 int dir = static_cast<int>(Get_direction4(cur.ty - dest.ty, dest.tx - cur.tx));
00980 signed char frames[4];
00981 for (int i = 0; i < 4; i++)
00982
00983 frames[i] = npc->get_dir_framenum((2*(dir + i))%8,
00984 npc->get_shapenum() == 846 ? 15 : 9);
00985
00986 Actor_action *walk = new Path_walking_actor_action(new Zombie());
00987 walk->walk_to_tile(npc, cur, dest);
00988
00989 npc->set_action(new Sequence_actor_action(walk,
00990 new Frames_actor_action(frames, sizeof(frames), 100)));
00991 npc->start(gwin->get_std_delay(), 500);
00992 }
00993
00994
00995
00996
00997
00998 void Tool_schedule::now_what
00999 (
01000 )
01001 {
01002 if (!tool)
01003 {
01004 tool = new Ireg_game_object(toolshape, 0, 0, 0, 0);
01005
01006 Game_object *obj = npc->get_readied(Actor::rhand);
01007 if (obj)
01008 obj->remove_this();
01009 if ((obj = npc->get_readied(Actor::lhand)) != 0)
01010 obj->remove_this();
01011 if (!npc->add_readied(tool, Actor::lrhand))
01012 npc->add_readied(tool, Actor::lhand);
01013 }
01014 if (rand()%4 == 0)
01015 {
01016 Loiter_schedule::now_what();
01017 return;
01018 }
01019 if (rand()%10 == 0)
01020 {
01021 Schedule_types ty = (Schedule_types) npc->get_schedule_type();
01022 if (ty == Schedule::miner)
01023 npc->say(first_miner, last_miner);
01024 else if (ty == Schedule::farm)
01025 npc->say(first_farmer, last_farmer);
01026 }
01027 signed char frames[12];
01028 int cnt = npc->get_attack_frames(toolshape, false, rand()%8, frames);
01029 npc->set_action(new Frames_actor_action(frames, cnt));
01030 npc->start();
01031 }
01032
01033
01034
01035
01036
01037 void Tool_schedule::ending
01038 (
01039 int
01040 )
01041 {
01042 if (tool)
01043 tool->remove_this();
01044 }
01045
01046
01047
01048
01049
01050 void Hound_schedule::now_what
01051 (
01052 )
01053 {
01054 Actor *av = gwin->get_main_actor();
01055 Tile_coord avpos = av->get_tile(),
01056 npcpos = npc->get_tile();
01057
01058 int dist = npcpos.distance(avpos);
01059 if (dist > 20 || dist < 3)
01060 {
01061 npc->start(gwin->get_std_delay(), 500 + rand()%1000);
01062 return;
01063 }
01064 int newdist = 1 + rand()%2;
01065 Fast_pathfinder_client cost(newdist);
01066 avpos.tx += rand()%3 - 1;
01067 avpos.ty += rand()%3 - 1;
01068 Actor_action *pact = Path_walking_actor_action::create_path(npcpos,
01069 avpos, cost);
01070 if (pact)
01071 {
01072 npc->set_action(pact);
01073 npc->start(gwin->get_std_delay(), 50);
01074 }
01075 else
01076 npc->start(gwin->get_std_delay(), 2000 + rand()%3000);
01077 }
01078
01079
01080
01081
01082
01083 void Wander_schedule::now_what
01084 (
01085 )
01086 {
01087 if (rand() % 2)
01088 if (try_street_maintenance())
01089 return;
01090 Tile_coord pos = npc->get_tile();
01091 const int legdist = 32;
01092
01093 pos.tx += -legdist + rand()%(2*legdist);
01094 pos.ty += -legdist + rand()%(2*legdist);
01095
01096 if (pos.tx - center.tx > dist)
01097 pos.tx = center.tx + dist;
01098 else if (center.tx - pos.tx > dist)
01099 pos.tx = center.tx - dist;
01100 if (pos.ty - center.ty > dist)
01101 pos.ty = center.ty + dist;
01102 else if (center.ty - pos.ty > dist)
01103 pos.ty = center.ty - dist;
01104
01105 Tile_coord dest = Map_chunk::find_spot(pos, 4, npc->get_shapenum(), 0,
01106 1);
01107 if (dest.tx == -1 || !npc->walk_path_to_tile(dest,
01108 gwin->get_std_delay(), rand()%2000))
01109
01110 npc->start(250, rand()%3000);
01111 }
01112
01113
01114
01115
01116
01117 static void Stand_up
01118 (
01119 Actor *npc
01120 )
01121 {
01122 if ((npc->get_framenum()&0xf) != Actor::standing)
01123
01124 npc->change_frame(Actor::standing);
01125 }
01126
01127
01128
01129
01130
01131 Sleep_schedule::Sleep_schedule
01132 (
01133 Actor *n
01134 ) : Schedule(n), bed(0), state(0)
01135 {
01136 floorloc.tx = -1;
01137 if (Game::get_game_type() == BLACK_GATE)
01138 {
01139 spread0 = 3;
01140 spread1 = 16;
01141 }
01142 else
01143 {
01144 spread0 = 7;
01145 spread1 = 20;
01146 }
01147 }
01148
01149
01150
01151
01152
01153 void Sleep_schedule::now_what
01154 (
01155 )
01156 {
01157 if (!bed && state == 0)
01158 {
01159 static int bedshapes[2] = {696, 1011};
01160 Stand_up(npc);
01161 bed = npc->find_closest(bedshapes, 2);
01162 if (!bed && GAME_BG)
01163 {
01164 static int gbeds[2] = {363, 312};
01165 bed = npc->find_closest(gbeds, 2);
01166 }
01167 }
01168 int frnum = npc->get_framenum();
01169 if ((frnum&0xf) == Actor::sleep_frame)
01170 return;
01171
01172 switch (state)
01173 {
01174 case 0:
01175 {
01176 if (!bed)
01177 {
01178 int dirbits = npc->get_framenum()&(0x30);
01179 npc->change_frame(Actor::sleep_frame|dirbits);
01180 return;
01181 }
01182 state = 1;
01183 Game_object_vector tops;
01184 bed->find_nearby(tops, bed->get_shapenum(), 1, 0);
01185 for (Game_object_vector::const_iterator it = tops.begin();
01186 it != tops.end(); ++it)
01187 {
01188 Game_object *top = *it;
01189 int frnum = top->get_framenum();
01190 if (frnum >= spread0 && frnum <= spread1)
01191 {
01192 bed = top;
01193 break;
01194 }
01195 }
01196 Tile_coord bloc = bed->get_tile();
01197 bloc.tz -= bloc.tz%5;
01198 Shape_info& info = bed->get_info();
01199 bloc.tx -= info.get_3d_xtiles(bed->get_framenum())/2;
01200 bloc.ty -= info.get_3d_ytiles(bed->get_framenum())/2;
01201
01202 Actor_pathfinder_client cost(npc, 3);
01203 Actor_action *pact = Path_walking_actor_action::create_path(
01204 npc->get_tile(), bloc, cost);
01205 if (pact)
01206 npc->set_action(pact);
01207 npc->start(200);
01208 break;
01209 }
01210 case 1:
01211 {
01212 npc->stop();
01213 int bedshape = bed->get_shapenum();
01214 int dir = (bedshape == 696 || bedshape == 363) ? west : north;
01215 npc->set_frame(npc->get_dir_framenum(dir, Actor::sleep_frame));
01216
01217 Shape_info& info = bed->get_info();
01218 Tile_coord bedloc = bed->get_tile();
01219 floorloc = npc->get_tile();
01220 int bedframe = bed->get_framenum();
01221 if (bedframe >= spread0 && bedframe < spread1 && (bedframe%2))
01222 {
01223 bedframe++;
01224 bed->change_frame(bedframe);
01225 }
01226 int bedspread = (bedframe >= spread0 && !(bedframe%2));
01227
01228 npc->move(bedloc.tx, bedloc.ty, bedloc.tz +
01229 (bedspread ? 0 : info.get_3d_height()));
01230 state = 2;
01231 break;
01232 }
01233 default:
01234 break;
01235 }
01236 }
01237
01238
01239
01240
01241
01242 void Sleep_schedule::ending
01243 (
01244 int new_type
01245 )
01246 {
01247
01248 if (new_type == static_cast<int>(wait) ||
01249
01250 new_type == static_cast<int>(sleep))
01251 return;
01252 if (bed &&
01253 (npc->get_framenum()&0xf) == Actor::sleep_frame &&
01254 npc->distance(bed) < 8)
01255 {
01256 if (floorloc.tx == -1)
01257
01258 floorloc = npc->get_tile();
01259 floorloc.tz -= floorloc.tz%5;
01260 Tile_coord pos = Map_chunk::find_spot(floorloc,
01261 6, npc->get_shapenum(),
01262 static_cast<int>(Actor::standing), 0);
01263 if (pos.tx == -1)
01264 pos = Map_chunk::find_spot(floorloc,
01265 6, npc->get_shapenum(),
01266 static_cast<int>(Actor::standing), 1);
01267 floorloc = pos;
01268
01269 int frnum = bed->get_framenum();
01270 Actor_vector occ;
01271 if (frnum >= spread0 && frnum <= spread1 && !(frnum%2) &&
01272 bed->find_nearby_actors(occ, c_any_shapenum, 0) < 2)
01273 bed->set_frame(frnum - 1);
01274 }
01275 if (floorloc.tx >= 0)
01276 npc->move(floorloc);
01277 npc->set_frame(Actor::standing);
01278 gwin->set_all_dirty();
01279 state = 0;
01280 }
01281
01282
01283
01284
01285
01286 Sit_schedule::Sit_schedule
01287 (
01288 Actor *n,
01289 Game_object *ch
01290 ) : Schedule(n), chair(ch), sat(false), did_barge_usecode(false)
01291 {
01292 }
01293
01294
01295
01296
01297
01298 void Sit_schedule::now_what
01299 (
01300 )
01301 {
01302 int frnum = npc->get_framenum();
01303 if (chair && (frnum&0xf) == Actor::sit_frame &&
01304 npc->distance(chair) <= 1)
01305 {
01306
01307 if (!chair || chair->get_shapenum() != 292)
01308 return;
01309 if (did_barge_usecode)
01310 return;
01311 did_barge_usecode = true;
01312 if (gwin->get_moving_barge())
01313 return;
01314 if (!npc->is_in_party())
01315 return;
01316 Actor *party[9];
01317 int cnt = gwin->get_party(&party[0], 1);
01318 for (int i = 0; i < cnt; i++)
01319 if ((party[i]->get_framenum()&0xf) != Actor::sit_frame)
01320 return;
01321
01322 Game_object *barge = chair->find_closest(961);
01323 if (!barge)
01324 return;
01325 int usefun = 0x634;
01326 did_barge_usecode = true;
01327
01328
01329
01330 ucmachine->call_usecode(usefun, gwin->get_main_actor(),
01331 Usecode_machine::double_click);
01332 return;
01333 }
01334
01335 if (!set_action(npc, chair, sat ? (2000 + rand()%3000) : 0, &chair))
01336 npc->start(200, 5000);
01337 else
01338 sat = true;
01339 }
01340
01341
01342
01343
01344
01345 class Sit_actor_action : public Frames_actor_action, public Game_singletons
01346 {
01347 Game_object *chair;
01348 Tile_coord chairloc;
01349 Tile_coord sitloc;
01350 signed char frames[2];
01351 static short offsets[8];
01352 signed char *init(Game_object *chairobj, Actor *actor)
01353 {
01354
01355 int dir = 2*(chairobj->get_framenum()%4);
01356 frames[0] = actor->get_dir_framenum(dir, Actor::bow_frame);
01357 frames[1] = actor->get_dir_framenum(dir, Actor::sit_frame);
01358 return frames;
01359 }
01360 static bool is_occupied(Tile_coord sitloc, Actor *actor)
01361 {
01362 Game_object_vector occ;
01363 if (Game_object::find_nearby(occ, sitloc,c_any_shapenum, 0, 8))
01364 for (Game_object_vector::const_iterator it =
01365 occ.begin(); it != occ.end(); ++it)
01366 {
01367 Game_object *npc = *it;
01368 if (npc == actor)
01369 continue;
01370 int frnum = npc->get_framenum() & 15;
01371 if (frnum == Actor::sit_frame ||
01372 frnum == Actor::bow_frame)
01373 return true;
01374 }
01375 #if 1
01376 if (actor->get_tile() == sitloc)
01377 return false;
01378
01379 Tile_coord pos = sitloc;
01380 if (Map_chunk::is_blocked(pos,
01381 actor->get_info().get_3d_height(), MOVE_WALK, 0))
01382 return true;
01383 #endif
01384 return false;
01385 }
01386 public:
01387 Sit_actor_action(Game_object *o, Actor *actor) : chair(o),
01388 Frames_actor_action(init(o, actor), 2)
01389 {
01390 sitloc = chairloc = o->get_tile();
01391
01392 int nsew = o->get_framenum()%4;
01393 sitloc.tx += offsets[2*nsew];
01394 sitloc.ty += offsets[2*nsew + 1];
01395 }
01396 Tile_coord get_sitloc() const
01397 { return sitloc; }
01398 static bool is_occupied(Game_object *chair, Actor *actor)
01399 {
01400 int dir = 2*(chair->get_framenum()%4);
01401 return is_occupied(chair->get_tile() +
01402 Tile_coord(offsets[dir], offsets[dir + 1], 0), actor);
01403 }
01404
01405 virtual int handle_event(Actor *actor);
01406 };
01407
01408
01409 short Sit_actor_action::offsets[8] = {0,-1, 1,0, 0,1, -1,0};
01410
01411
01412
01413
01414
01415 int Sit_actor_action::handle_event
01416 (
01417 Actor *actor
01418 )
01419 {
01420 if (get_index() == 0)
01421 {
01422 if (is_occupied(sitloc, actor))
01423 return 0;
01424 if (chair->get_tile() != chairloc)
01425 {
01426 actor->say(first_chair_thief, last_chair_thief);
01427 return 0;
01428 }
01429 }
01430 return Frames_actor_action::handle_event(actor);
01431 }
01432
01433
01434
01435
01436
01437 bool Sit_schedule::is_occupied
01438 (
01439 Game_object *chairobj,
01440 Actor *actor
01441 )
01442 {
01443 return Sit_actor_action::is_occupied(chairobj, actor);
01444 }
01445
01446
01447
01448
01449
01450
01451
01452 bool Sit_schedule::set_action
01453 (
01454 Actor *actor,
01455 Game_object *chairobj,
01456 int delay,
01457 Game_object **chair_found
01458 )
01459 {
01460 static int chairshapes[] = {873,292};
01461 Game_object_vector chairs;
01462 if (chair_found)
01463 *chair_found = 0;
01464 if (!chairobj)
01465 {
01466 actor->find_closest(chairs, chairshapes,
01467 sizeof(chairs)/sizeof(chairs[0]));
01468 for (Game_object_vector::const_iterator it = chairs.begin();
01469 it != chairs.end(); ++it)
01470 if (!Sit_actor_action::is_occupied((*it), actor))
01471 {
01472 chairobj = *it;
01473 break;
01474 }
01475 if (!chairobj)
01476 return false;
01477 }
01478 else if (Sit_actor_action::is_occupied(chairobj, actor))
01479 return false;
01480 Sit_actor_action *act = new Sit_actor_action(chairobj, actor);
01481
01482 set_action_sequence(actor, act->get_sitloc(), act, false, delay);
01483 if (chair_found)
01484 *chair_found = chairobj;
01485 return true;
01486 }
01487
01488
01489
01490
01491
01492 Desk_schedule::Desk_schedule
01493 (
01494 Actor *n
01495 ) : Schedule(n), chair(0)
01496 {
01497 }
01498
01499
01500
01501
01502
01503 void Desk_schedule::now_what
01504 (
01505 )
01506 {
01507 if (!chair)
01508 {
01509 static int desks[2] = {283, 407};
01510 static int chairs[2] = {873,292};
01511 Stand_up(npc);
01512 Game_object *desk = npc->find_closest(desks, 2);
01513 if (desk)
01514 chair = desk->find_closest(chairs, 2);
01515 if (!chair)
01516 {
01517 npc->start(200, 5000);
01518 return;
01519 }
01520 }
01521 int frnum = npc->get_framenum();
01522 if ((frnum&0xf) != Actor::sit_frame)
01523 {
01524 if (!Sit_schedule::set_action(npc, chair, 0))
01525 {
01526 chair = 0;
01527 npc->start(200, 5000);
01528 }
01529 else
01530 npc->start(250, 0);
01531 }
01532 else
01533 {
01534 signed char frames[3];
01535 frames[0] = npc->get_dir_framenum(Actor::standing);
01536 frames[1] = npc->get_dir_framenum(Actor::bow_frame);
01537 frames[2] = npc->get_dir_framenum(Actor::sit_frame);
01538 npc->set_action(new Frames_actor_action(frames,
01539 sizeof(frames)/sizeof(frames[0])));
01540 npc->start(250, 10000 + rand()%5000);
01541 }
01542 }
01543
01544
01545
01546
01547 class Perimeter
01548 {
01549 Rectangle perim;
01550 int sz;
01551 public:
01552 Perimeter(Rectangle &r) : sz(2*r.w + 2*r.h + 4)
01553 {
01554 perim = r;
01555 perim.enlarge(1);
01556 }
01557 int size() { return sz; }
01558
01559 void get(int i, Tile_coord& ptile, Tile_coord& atile);
01560 #if 0
01561 static void test()
01562 {
01563 Rectangle r(10, 10, 3, 4);
01564 Perimeter p(r);
01565 int cnt = p.size();
01566 for (int i = 0; i < cnt; i++)
01567 {
01568 Tile_coord pt, at;
01569 p.get(i, pt, at);
01570 cout << "pt.tx = " << pt.tx << ", pt.ty = " << pt.ty
01571 << ", at.tx = " << at.tx << ", at.ty = " <<
01572 at.ty << endl;
01573 }
01574 }
01575 #endif
01576 };
01577
01578
01579
01580
01581
01582
01583 void Perimeter::get
01584 (
01585 int i,
01586 Tile_coord& ptile,
01587 Tile_coord& atile
01588 )
01589 {
01590 if (i < perim.w - 1)
01591 {
01592 ptile = Tile_coord(perim.x + i, perim.y, 0);
01593 atile = ptile + Tile_coord(!i ? 1 : 0, 1, 0);
01594 return;
01595 }
01596 i -= perim.w - 1;
01597 if (i < perim.h - 1)
01598 {
01599 ptile = Tile_coord(perim.x + perim.w - 1, perim.y + i, 0);
01600 atile = ptile + Tile_coord(-1, !i ? 1 : 0, 0);
01601 return;
01602 }
01603 i -= perim.h - 1;
01604 if (i < perim.w - 1)
01605 {
01606 ptile = Tile_coord(perim.x + perim.w - 1 - i,
01607 perim.y + perim.h - 1, 0);
01608 atile = ptile + Tile_coord(!i ? -1 : 0, -1, 0);
01609 return;
01610 }
01611 i -= perim.w - 1;
01612 {
01613 ptile = Tile_coord(perim.x, perim.y + perim.h - 1 - i, 0);
01614 atile = ptile + Tile_coord(1, !i ? -1 : 0, 0);
01615 return;
01616 }
01617
01618 get(i%sz, ptile, atile);
01619 }
01620
01621
01622
01623
01624
01625 void Lab_schedule::init
01626 (
01627 )
01628 {
01629 chair = book = 0;
01630 cauldron = npc->find_closest(995, 20);
01631
01632 npc->find_nearby(tables, 1003, 20, 0);
01633 npc->find_nearby(tables, 1018, 20, 0);
01634 int cnt = tables.size();
01635 for (int i = 0; (!book || !chair) && i < cnt; i++)
01636 {
01637 static int chairs[2] = {873,292};
01638 Game_object *table = tables[i];
01639 Rectangle foot = table->get_footprint();
01640
01641 if (!book && (book = table->find_closest(642, 4)) != 0)
01642 {
01643 Tile_coord p = book->get_tile();
01644 if (!foot.has_point(p.tx, p.ty))
01645 book = 0;
01646 }
01647 if (!chair)
01648 chair = table->find_closest(chairs, 2, 4);
01649 }
01650 }
01651
01652
01653
01654
01655
01656 Lab_schedule::Lab_schedule
01657 (
01658 Actor *n
01659 ) : Schedule(n), state(start)
01660 {
01661 init();
01662 }
01663
01664
01665
01666
01667
01668 void Lab_schedule::now_what
01669 (
01670 )
01671 {
01672 Tile_coord npcpos = npc->get_tile();
01673 int delay = 100;
01674
01675 Actor_pathfinder_client cost(npc, 1);
01676 switch (state)
01677 {
01678 case start:
01679 default:
01680 {
01681 if (!cauldron)
01682 {
01683 init();
01684 if (!cauldron)
01685 delay = 6000;
01686 break;
01687 }
01688 int r = rand()%5;
01689 if (!r)
01690 state = sit_down;
01691 else
01692 state = r <= 2 ? walk_to_cauldron : walk_to_table;
01693 break;
01694 }
01695 case walk_to_cauldron:
01696 {
01697 state = start;
01698 if (!cauldron)
01699 break;
01700 Actor_action *pact = Path_walking_actor_action::create_path(
01701 npcpos, cauldron->get_tile(), cost);
01702 if (pact)
01703 {
01704 npc->set_action(new Sequence_actor_action(pact,
01705 new Face_pos_actor_action(cauldron, 200)));
01706 state = use_cauldron;
01707 }
01708 break;
01709 }
01710 case use_cauldron:
01711 {
01712 int dir = npc->get_direction(cauldron);
01713
01714 cauldron->change_frame(rand()%(cauldron->get_num_frames() -1));
01715 npc->change_frame(
01716 npc->get_dir_framenum(dir, Actor::bow_frame));
01717 int r = rand()%5;
01718 state = !r ? use_cauldron : (r <= 2 ? sit_down
01719 : walk_to_table);
01720 break;
01721 }
01722 case sit_down:
01723 if (!chair || !Sit_schedule::set_action(npc, chair, 200))
01724 state = start;
01725 else
01726 state = read_book;
01727 break;
01728 case read_book:
01729 {
01730 state = stand_up;
01731 if (!book || npc->distance(book) > 4)
01732 break;
01733
01734 delay = 1000 + 1000*(rand()%5);
01735
01736 int frnum = book->get_framenum();
01737 book->change_frame(frnum - frnum%3);
01738 break;
01739 }
01740 case stand_up:
01741 {
01742 if (book && npc->distance(book) < 4)
01743 {
01744 int frnum = book->get_framenum();
01745 book->change_frame(frnum - frnum%3 + 1);
01746 }
01747 state = start;
01748 break;
01749 }
01750 case walk_to_table:
01751 {
01752 state = start;
01753 int ntables = tables.size();
01754 if (!ntables)
01755 break;
01756 Game_object *table = tables[rand()%ntables];
01757 Rectangle r = table->get_footprint();
01758 Perimeter p(r);
01759 Tile_coord spot;
01760 p.get(rand()%p.size(), spot, spot_on_table);
01761 Actor_pathfinder_client cost0(npc, 0);
01762 Actor_action *pact = Path_walking_actor_action::create_path(
01763 npcpos, spot, cost0);
01764 if (!pact)
01765 break;
01766 Shape_info& info = table->get_info();
01767 spot_on_table.tz += info.get_3d_height();
01768 npc->set_action(new Sequence_actor_action(pact,
01769 new Face_pos_actor_action(spot_on_table, 200)));
01770 state = use_potion;
01771 break;
01772 }
01773 case use_potion:
01774 {
01775 state = start;
01776 Exult_vector<Game_object *> potions;
01777 Game_object::find_nearby(potions, spot_on_table, 340, 0, 0);
01778 if (potions.size())
01779 {
01780 gwin->add_dirty(potions[0]);
01781 potions[0]->remove_this();
01782 }
01783 else
01784 {
01785 Tile_coord t = Map_chunk::find_spot(spot_on_table, 0,
01786 340, 0, 0);
01787 if (t.tx != -1 && t.tz == spot_on_table.tz)
01788 {
01789
01790 int nframes = ShapeID(340, 0).get_num_frames() - 1;
01791 Game_object *p = gmap->create_ireg_object(
01792 ShapeID::get_info(340), 340,
01793 rand()%nframes, 0, 0, 0);
01794 p->move(t);
01795 }
01796 }
01797 signed char frames[2];
01798 int dir = npc->get_direction(spot_on_table);
01799
01800 frames[0] = npc->get_dir_framenum(dir, 1);
01801 frames[1] = npc->get_dir_framenum(dir, Actor::standing);
01802 npc->set_action(new Frames_actor_action(frames, 2));
01803 break;
01804 }
01805 }
01806 npc->start(gwin->get_std_delay(), delay);
01807 }
01808
01809
01810
01811
01812
01813 void Shy_schedule::now_what
01814 (
01815 )
01816 {
01817 Actor *av = gwin->get_main_actor();
01818 Tile_coord avpos = av->get_tile(),
01819 npcpos = npc->get_tile();
01820
01821 int dist = npcpos.distance(avpos);
01822 if (dist > 10)
01823 {
01824 if (rand()%3)
01825 npc->start(250, 1000 + rand()%1000);
01826 else
01827 npc->walk_to_tile(
01828 Tile_coord(npcpos.tx + rand()%6 - 3,
01829 npcpos.ty + rand()%6 - 3, npcpos.tz));
01830 return;
01831 }
01832
01833 int dx = npcpos.tx - avpos.tx, dy = npcpos.ty - avpos.ty;
01834 int adx = dx < 0 ? -dx : dx;
01835 int ady = dy < 0 ? -dy : dy;
01836
01837 int farthest = adx < ady ? ady : adx;
01838 int factor = farthest < 2 ? 9 : farthest < 4 ? 4
01839 : farthest < 7 ? 2 : 1;
01840
01841 Tile_coord dest = npcpos + Tile_coord(dx*factor, dy*factor, 0);
01842 Tile_coord delta = Tile_coord(rand()%3, rand()%3, 0);
01843 dest = dest + delta;
01844 Monster_pathfinder_client cost(npc, dest, 4);
01845 Actor_action *pact = Path_walking_actor_action::create_path(
01846 npcpos, dest, cost);
01847 if (pact)
01848 {
01849 npc->set_action(pact);
01850 npc->start(200, 100 + rand()%200);
01851 }
01852 else
01853 npc->start(250, 500 + rand()%1000);
01854 }
01855
01856
01857
01858
01859
01860
01861 Waiter_schedule::Waiter_schedule
01862 (
01863 Actor *n
01864 ) : Schedule(n), first(1), startpos(n->get_tile()), customer(0)
01865
01866 {
01867 }
01868
01869
01870
01871
01872
01873 void Waiter_schedule::get_customer
01874 (
01875 )
01876 {
01877 if (customers.empty())
01878 {
01879 Actor_vector vec;
01880 npc->find_nearby_actors(vec, c_any_shapenum, 32);
01881 for (Actor_vector::const_iterator it = vec.begin();
01882 it != vec.end(); ++it)
01883 {
01884 Actor *each = (Actor *) *it;
01885 if (each->get_schedule_type() == Schedule::eat_at_inn)
01886 customers.push(each);
01887 }
01888 }
01889
01890 if (!customers.empty())
01891 customer = customers.pop();
01892 npc->say(first_waiter_ask, last_waiter_ask);
01893 if (prep_tables.size())
01894 {
01895 Game_object *table = prep_tables[rand()%prep_tables.size()];
01896 Tile_coord pos = Map_chunk::find_spot(
01897 table->get_tile(), 1, npc);
01898 if (pos.tx != -1 &&
01899 npc->walk_path_to_tile(pos, gwin->get_std_delay(),
01900 1000 + rand()%1000))
01901 return;
01902 }
01903 const int dist = 8;
01904 int newx = startpos.tx - dist + rand()%(2*dist);
01905 int newy = startpos.ty - dist + rand()%(2*dist);
01906 npc->walk_to_tile(newx, newy, startpos.tz, 2*gwin->get_std_delay(),
01907 rand()%2000);
01908 }
01909
01910
01911
01912
01913
01914 void Waiter_schedule::find_tables
01915 (
01916 int shapenum
01917 )
01918 {
01919 Game_object_vector vec;
01920 npc->find_nearby(vec, shapenum, 32, 0);
01921 int floor = npc->get_lift()/5;
01922 for (Game_object_vector::const_iterator it = vec.begin(); it != vec.end();
01923 ++it)
01924 {
01925 Game_object *table = *it;
01926 if (table->get_lift()/5 != floor)
01927 continue;
01928 Game_object_vector chairs;
01929 if (!table->find_nearby(chairs, 873, 3, 0) &&
01930 !table->find_nearby(chairs, 292, 3, 0))
01931 prep_tables.append(table);
01932 else
01933 eating_tables.append(table);
01934 }
01935 }
01936
01937
01938
01939
01940
01941
01942
01943 Game_object *Waiter_schedule::find_serving_spot
01944 (
01945 Tile_coord& spot
01946 )
01947 {
01948 Game_object_vector plates;
01949 Game_object *plate = 0;
01950 int cnt = npc->find_nearby(plates, 717, 1, 0);
01951 if (!cnt)
01952 cnt = npc->find_nearby(plates, 717, 2, 0);
01953 int floor = npc->get_lift()/5;
01954 for (Game_object_vector::const_iterator it = plates.begin();
01955 it != plates.end(); ++it)
01956 {
01957 plate = *it;
01958 if (plate->get_lift()/5 == floor)
01959 {
01960 spot = plate->get_tile();
01961 spot.tz++;
01962 return plate;
01963 }
01964 }
01965 Tile_coord cpos = customer->get_tile();
01966
01967
01968 {
01969
01970
01971 for (Game_object_vector::const_iterator it = eating_tables.begin();
01972 it != eating_tables.end(); ++it)
01973 {
01974 Game_object *table = *it;
01975 Rectangle foot = table->get_footprint();
01976 if (foot.distance(cpos.tx, cpos.ty) > 2)
01977 continue;
01978
01979 spot = cpos;
01980
01981 if (cpos.ty >= foot.y && cpos.ty < foot.y + foot.h)
01982 spot.tx = cpos.tx <= foot.x ? foot.x
01983 : foot.x + foot.w - 1;
01984 else
01985 spot.ty = cpos.ty <= foot.y ? foot.y
01986 : foot.y + foot.h - 1;
01987 if (foot.has_point(spot.tx, spot.ty))
01988 {
01989 Shape_info& info = table->get_info();
01990 spot.tz = table->get_lift() + info.get_3d_height();
01991 plate = gmap->create_ireg_object(717, 0);
01992 plate->move(spot);
01993 spot.tz++;
01994 return plate;
01995 }
01996 }
01997 }
01998 return 0;
01999 }
02000
02001
02002
02003
02004
02005 void Waiter_schedule::now_what
02006 (
02007 )
02008 {
02009 if (rand() % 4 == 0)
02010 if (try_street_maintenance())
02011 return;
02012 if (first)
02013 {
02014 first = 0;
02015 find_tables(971);
02016 find_tables(633);
02017 find_tables(847);
02018 find_tables(1003);
02019 find_tables(1018);
02020 find_tables(890);
02021 find_tables(964);
02022 find_tables(333);
02023 }
02024 int dist = customer ? npc->distance(customer) : 5000;
02025 if (dist > 32)
02026 {
02027 get_customer();
02028 return;
02029 }
02030 if (dist < 3)
02031 {
02032 Game_object_vector foods;
02033 if (customer->find_nearby(foods, 377, 2, 0) > 0)
02034 {
02035 if (rand()%4)
02036 npc->say(first_waiter_banter,
02037 last_waiter_banter);
02038 }
02039 else
02040 {
02041 Game_object *food = npc->get_readied(Actor::lhand);
02042 Tile_coord spot;
02043 if (food && food->get_shapenum() == 377 &&
02044 find_serving_spot(spot))
02045 {
02046 npc->change_frame(npc->get_dir_framenum(
02047 npc->get_direction(customer),
02048 Actor::standing));
02049 npc->remove(food);
02050 food->set_invalid();
02051 food->move(spot);
02052 if (rand()%3)
02053 npc->say(first_waiter_serve,
02054 last_waiter_serve);
02055 }
02056 }
02057 customer = 0;
02058 npc->start(250, rand()%3000);
02059 return;
02060 }
02061
02062 if (!npc->get_readied(Actor::lhand))
02063 {
02064 int nfoods = ShapeID(377, 0).get_num_frames();
02065 int frame = rand()%nfoods;
02066 Game_object *food = new Ireg_game_object(377, frame, 0, 0, 0);
02067 npc->add_readied(food, Actor::lhand);
02068 }
02069 Tile_coord dest = Map_chunk::find_spot(customer->get_tile(),
02070 3, npc);
02071 if (dest.tx != -1 && npc->walk_path_to_tile(dest,
02072 gwin->get_std_delay(), rand()%1000))
02073 return;
02074
02075 npc->start(200, 2000 + rand()%4000);
02076 }
02077
02078
02079
02080
02081
02082 void Waiter_schedule::ending
02083 (
02084 int new_type
02085 )
02086 {
02087
02088 Game_object *obj = npc->get_readied(Actor::lhand);
02089 if (obj)
02090 obj->remove_this();
02091 obj = npc->get_readied(Actor::rhand);
02092 if (obj)
02093 obj->remove_this();
02094 }
02095
02096
02097
02098
02099
02100 Sew_schedule::Sew_schedule
02101 (
02102 Actor *n
02103 ) : Schedule(n), state(get_wool), bale(0), spinwheel(0),
02104 chair(0), spindle(0), loom(0), cloth(0), work_table(0),
02105 wares_table(0), sew_clothes_cnt(0)
02106 {
02107 }
02108
02109
02110
02111
02112
02113 void Sew_schedule::now_what
02114 (
02115 )
02116 {
02117 Tile_coord npcpos = npc->get_tile();
02118
02119 Actor_pathfinder_client cost(npc, 1);
02120 switch (state)
02121 {
02122 case get_wool:
02123 {
02124 if (spindle)
02125 spindle->remove_this();
02126 if (cloth)
02127 cloth->remove_this();
02128 cloth = spindle = 0;
02129 npc->remove_quantity(2, 654, c_any_qual, c_any_framenum);
02130 npc->remove_quantity(2, 851, c_any_qual, c_any_framenum);
02131
02132 bale = npc->find_closest(653);
02133 if (!bale)
02134 {
02135 state = sit_at_wheel;
02136 break;
02137 }
02138 Actor_action *pact = Path_walking_actor_action::create_path(
02139 npcpos, bale->get_tile(), cost);
02140 if (pact)
02141 npc->set_action(new Sequence_actor_action(pact,
02142 new Pickup_actor_action(bale, 250),
02143 new Pickup_actor_action(bale,
02144 bale->get_tile(), 250)));
02145 state = sit_at_wheel;
02146 break;
02147 }
02148 case sit_at_wheel:
02149 chair = npc->find_closest(873);
02150 if (!chair || !Sit_schedule::set_action(npc, chair, 200)) {
02151
02152 npc->start(250, 2500);
02153 return;
02154 }
02155 state = spin_wool;
02156 break;
02157 case spin_wool:
02158 spinwheel = npc->find_closest(651);
02159 if (!spinwheel) {
02160
02161 npc->start(250, 2500);
02162 return;
02163 }
02164 npc->set_action(new Object_animate_actor_action(spinwheel,
02165 8, 200));
02166 state = get_thread;
02167 break;
02168 case get_thread:
02169 {
02170 Tile_coord t = Map_chunk::find_spot(
02171 spinwheel->get_tile(), 1, 654, 0);
02172 if (t.tx != -1)
02173 {
02174 spindle = new Ireg_game_object(654, 0, 0, 0);
02175 spindle->move(t);
02176 gwin->add_dirty(spindle);
02177 npc->set_action(
02178 new Pickup_actor_action(spindle, 250));
02179 }
02180 state = weave_cloth;
02181 break;
02182 }
02183 case weave_cloth:
02184 {
02185 if (spindle)
02186 spindle->remove_this();
02187 spindle = 0;
02188 loom = npc->find_closest(261);
02189 if (!loom)
02190 {
02191 state = get_wool;
02192 break;
02193 }
02194 Tile_coord lpos = loom->get_tile() +
02195 Tile_coord(-1, 0, 0);
02196 Actor_action *pact = Path_walking_actor_action::create_path(
02197 npcpos, lpos, cost);
02198 if (pact)
02199 npc->set_action(new Sequence_actor_action(pact,
02200 new Face_pos_actor_action(loom, 250),
02201 new Object_animate_actor_action(loom,
02202 4, 200)));
02203 state = get_cloth;
02204 break;
02205 }
02206 case get_cloth:
02207 {
02208 Tile_coord t = Map_chunk::find_spot(loom->get_tile(),
02209 1, 851, 0);
02210 if (t.tx != -1)
02211 {
02212 cloth = new Ireg_game_object(851, rand()%2, 0, 0);
02213 cloth->move(t);
02214 gwin->add_dirty(cloth);
02215 npc->set_action(
02216 new Pickup_actor_action(cloth, 250));
02217 }
02218 state = to_work_table;
02219 break;
02220 }
02221 case to_work_table:
02222 {
02223 work_table = npc->find_closest(971);
02224 if (!work_table || !cloth)
02225 {
02226 state = get_wool;
02227 break;
02228 }
02229 Tile_coord tpos = work_table->get_tile() +
02230 Tile_coord(1, -2, 0);
02231 Actor_action *pact = Path_walking_actor_action::create_path(
02232 npcpos, tpos, cost);
02233
02234 Rectangle foot = work_table->get_footprint();
02235 Shape_info& info = work_table->get_info();
02236 Tile_coord cpos(foot.x + foot.w/2, foot.y + foot.h/2,
02237 work_table->get_lift() + info.get_3d_height());
02238 if (pact)
02239 npc->set_action(new Sequence_actor_action(pact,
02240 new Face_pos_actor_action(
02241 work_table, 250),
02242 new Pickup_actor_action(cloth, cpos, 250)));
02243 state = set_to_sew;
02244 break;
02245 }
02246 case set_to_sew:
02247 {
02248 Game_object *shears = npc->get_readied(Actor::lhand);
02249 if (shears && shears->get_shapenum() != 698)
02250 {
02251 shears->remove_this();
02252 shears = 0;
02253 }
02254 if (!shears)
02255 {
02256 Game_object_vector vec;
02257 if (npc->find_nearby(vec, 698, 3, 0))
02258 {
02259 shears = vec[0];
02260 gwin->add_dirty(shears);
02261 shears->remove_this(1);
02262 }
02263 else
02264 shears = new Ireg_game_object(698, 0, 0, 0);
02265 npc->add_readied(shears, Actor::lhand);
02266 }
02267 state = sew_clothes;
02268 sew_clothes_cnt = 0;
02269 break;
02270 }
02271 case sew_clothes:
02272 {
02273 int dir = npc->get_direction(cloth);
02274 signed char frames[5];
02275 int nframes = npc->get_attack_frames(698, false,
02276 dir, frames);
02277 npc->set_action(new Frames_actor_action(frames, nframes));
02278 sew_clothes_cnt++;
02279 if (sew_clothes_cnt > 1 && sew_clothes_cnt < 5)
02280 {
02281 int num_cloth_frames = ShapeID(851, 0).get_num_frames();
02282 cloth->change_frame(rand()%num_cloth_frames);
02283 }
02284 else if (sew_clothes_cnt == 5)
02285 {
02286 gwin->add_dirty(cloth);
02287 Tile_coord pos = cloth->get_tile();
02288 cloth->remove_this(1);
02289
02290 int shnum = GAME_SI ? 403 : (rand()%2 ? 738 : 249);
02291 cloth->set_shape(shnum);
02292 int nframes = ShapeID(shnum, 0).get_num_frames();
02293 cloth->set_frame(rand()%nframes);
02294 cloth->move(pos);
02295 state = get_clothes;
02296 }
02297 break;
02298 }
02299 case get_clothes:
02300 {
02301 Game_object *shears = npc->get_readied(Actor::lhand);
02302 if (shears) {
02303 Tile_coord pos = cloth->get_tile();
02304 npc->set_action(new Sequence_actor_action(
02305 new Pickup_actor_action(cloth, 250),
02306 new Pickup_actor_action(shears, pos, 250)));
02307 } else {
02308
02309
02310 npc->set_action(new Pickup_actor_action(cloth, 250));
02311 }
02312 state = display_clothes;
02313 break;
02314 }
02315 case display_clothes:
02316 {
02317 state = done;
02318 wares_table = npc->find_closest(890);
02319 if (!wares_table)
02320 {
02321 cloth->remove_this();
02322 cloth = 0;
02323 break;
02324 }
02325 Tile_coord tpos = wares_table->get_tile() +
02326 Tile_coord(1, -2, 0);
02327 Actor_action *pact = Path_walking_actor_action::create_path(
02328 npcpos, tpos, cost);
02329
02330 Rectangle foot = wares_table->get_footprint();
02331 Shape_info& info = wares_table->get_info();
02332 Tile_coord cpos(foot.x + rand()%foot.w, foot.y + rand()%foot.h,
02333 wares_table->get_lift() + info.get_3d_height());
02334 if (pact)
02335 npc->set_action(new Sequence_actor_action(pact,
02336 new Pickup_actor_action(cloth, cpos, 250)));
02337 cloth = 0;
02338 break;
02339 }
02340 case done:
02341 {
02342 state = get_wool;
02343 Game_object_vector vec;
02344 int cnt = 0;
02345 if (GAME_SI)
02346 cnt += npc->find_nearby(vec, 403, 4, 0);
02347 else
02348 {
02349 cnt += npc->find_nearby(vec, 738, 4, 0);
02350 cnt += npc->find_nearby(vec, 249, 4, 0);
02351 }
02352 if (cnt > 5)
02353 {
02354 Game_object *obj = vec[rand()%cnt];
02355 gwin->add_dirty(obj);
02356 obj->remove_this();
02357 }
02358 break;
02359 }
02360 default:
02361 state = get_wool;
02362 break;
02363 }
02364 npc->start(250, 100);
02365 }
02366
02367
02368
02369
02370
02371 void Sew_schedule::ending
02372 (
02373 int new_type
02374 )
02375 {
02376
02377 Game_object *obj = npc->get_readied(Actor::lhand);
02378 if (obj)
02379 obj->remove_this();
02380 if (cloth)
02381 {
02382 if (!cloth->get_owner())
02383 gwin->add_dirty(cloth);
02384 cloth->remove_this();
02385 cloth = 0;
02386 }
02387 }
02388
02389
02390
02391
02392
02393
02394
02395
02396 Bake_schedule::Bake_schedule(Actor *n) : Schedule(n),
02397 state(to_flour), oven(0), worktable(0), displaytable(0),
02398 flourbag(0), dough(0), dough_in_oven(0), baked_count(0)
02399 { }
02400
02401 void Bake_schedule::now_what()
02402 {
02403 Tile_coord npcpos = npc->get_tile();
02404 Actor_pathfinder_client cost(npc, 1);
02405 int delay = 100;
02406
02407 switch (state) {
02408 case to_flour:
02409 {
02410 Game_object_vector items;
02411 npc->find_nearby(items, npcpos, 863, -1, 0, c_any_qual, 0);
02412 npc->find_nearby(items, npcpos, 863, -1, 0, c_any_qual, 13);
02413 npc->find_nearby(items, npcpos, 863, -1, 0, c_any_qual, 14);
02414
02415 if (items.empty()) {
02416 state = to_table;
02417 break;
02418 }
02419
02420 int nr = rand()%items.size();
02421 flourbag = items[nr];
02422
02423 Tile_coord tpos = flourbag->get_tile();
02424 Actor_action *pact = Path_walking_actor_action::create_path(
02425 npcpos, tpos, cost);
02426 if (pact) {
02427 npc->set_action(pact);
02428 } else {
02429
02430 state = to_table;
02431 break;
02432 }
02433
02434 state = get_flour;
02435 break;
02436 }
02437 case get_flour:
02438 {
02439 if (!flourbag) {
02440
02441 state = to_flour;
02442 break;
02443 }
02444
02445 int dir = npc->get_direction(flourbag);
02446 npc->change_frame(
02447 npc->get_dir_framenum(dir,Actor::bow_frame));
02448
02449 if (flourbag->get_framenum() != 0)
02450 flourbag->change_frame(0);
02451
02452 delay = 750;
02453 state = to_table;
02454 break;
02455 }
02456 case to_table:
02457 {
02458 Game_object *table1 = npc->find_closest(1003);
02459 Game_object *table2 = npc->find_closest(1018);
02460
02461 if (!table1)
02462 worktable = table2;
02463 else if (!table2)
02464 worktable = table1;
02465 else if (table1->distance(npc) < table2->distance(npc))
02466 worktable = table1;
02467 else
02468 worktable = table2;
02469
02470 if (!worktable)
02471 worktable = npc->find_closest(1018);
02472 if (!worktable) {
02473
02474 delay = 2500;
02475 state = to_flour;
02476 break;
02477 }
02478
02479
02480 Rectangle foot = worktable->get_footprint();
02481 Shape_info& info = worktable->get_info();
02482 Tile_coord cpos(foot.x + rand()%foot.w, foot.y + rand()%foot.h,
02483 worktable->get_lift() + info.get_3d_height());
02484 Tile_coord tablepos = cpos;
02485 cpos.tz = 0;
02486
02487 Actor_action *pact = Path_walking_actor_action::create_path(
02488 npcpos, cpos, cost);
02489 if (pact) {
02490 if (dough) {
02491 dough->remove_this();
02492 dough = 0;
02493 }
02494 if (Game::get_game_type() == SERPENT_ISLE)
02495 dough = new Ireg_game_object(863, 16, 0, 0);
02496 else
02497 dough = new Ireg_game_object(658, 0, 0, 0);
02498 npc->set_action(new Sequence_actor_action(pact,
02499 new Pickup_actor_action(dough,tablepos,250)));
02500 } else {
02501
02502 delay = 2500;
02503 state = to_flour;
02504 break;
02505 }
02506
02507 state = make_dough;
02508 break;
02509 }
02510 case make_dough:
02511 {
02512 if (!dough) {
02513
02514 delay = 2500;
02515 state = to_table;
02516 break;
02517 }
02518
02519 int dir = npc->get_direction(dough);
02520 signed char fr[2];
02521 fr[0] = npc->get_dir_framenum(dir, 3);
02522 fr[1] = npc->get_dir_framenum(dir, 0);
02523
02524 npc->set_action(new Sequence_actor_action(
02525 new Frames_actor_action(fr, 2, 500),
02526 ((Game::get_game_type() == SERPENT_ISLE) ?
02527 new Frames_actor_action((signed char *)"\x11",1,250,dough) :
02528 new Frames_actor_action((signed char *)"\x01",1,250,dough)),
02529 new Frames_actor_action(fr, 2, 500),
02530 ((Game::get_game_type() == SERPENT_ISLE) ?
02531 new Frames_actor_action((signed char *)"\x12",1,250,dough) :
02532 new Frames_actor_action((signed char *)"\x02",1,250,dough))
02533 ));
02534
02535 state = remove_from_oven;
02536 break;
02537 }
02538 case remove_from_oven:
02539 {
02540 if (!dough_in_oven) {
02541
02542 state = get_dough;
02543 break;
02544 }
02545
02546 oven = npc->find_closest(831);
02547 if (!oven) {
02548
02549 dough_in_oven->remove_this();
02550 dough_in_oven = 0;
02551
02552 delay = 2500;
02553 state = to_table;
02554 break;
02555 }
02556
02557 gwin->add_dirty(dough_in_oven);
02558 dough_in_oven->set_shape(377);
02559 dough_in_oven->set_frame(rand()%7);
02560 gwin->add_dirty(dough_in_oven);
02561
02562 Tile_coord tpos = oven->get_tile() +
02563 Tile_coord(1, 1, 0);
02564 Actor_action *pact = Path_walking_actor_action::create_path(
02565 npcpos, tpos, cost);
02566 if (pact) {
02567 npc->set_action(new Sequence_actor_action(
02568 pact,
02569 new Pickup_actor_action(dough_in_oven, 250)));
02570 } else {
02571
02572 npc->set_action(
02573 new Pickup_actor_action(dough_in_oven, 250));
02574 }
02575
02576 state = display_wares;
02577 break;
02578 }
02579 case display_wares:
02580 {
02581 if (!dough_in_oven) {
02582
02583 delay = 2500;
02584 state = to_flour;
02585 break;
02586 }
02587 displaytable = npc->find_closest(633);
02588 if (!displaytable) {
02589
02590 dough_in_oven->remove_this();
02591 dough_in_oven = 0;
02592
02593 delay = 2500;
02594 state = to_flour;
02595 break;
02596 }
02597
02598 baked_count++;
02599
02600 Tile_coord tpos = displaytable->get_tile();
02601 Actor_action *pact = Path_walking_actor_action::create_path(
02602 npcpos, tpos, cost);
02603
02604 Rectangle foot = displaytable->get_footprint();
02605 Shape_info& info = displaytable->get_info();
02606 Tile_coord cpos(foot.x + rand()%foot.w, foot.y + rand()%foot.h,
02607 displaytable->get_lift() + info.get_3d_height());
02608 if (pact) {
02609 if (baked_count <= 5) {
02610 npc->set_action(new Sequence_actor_action(pact,
02611 new Pickup_actor_action(dough_in_oven,
02612 cpos, 250)));
02613 } else {
02614 npc->set_action(pact);
02615 dough_in_oven->remove_this();
02616 }
02617 dough_in_oven = 0;
02618 } else {
02619
02620 dough_in_oven->remove_this();
02621 dough_in_oven = 0;
02622 }
02623
02624 state = get_dough;
02625 break;
02626 }
02627 case get_dough:
02628 {
02629 if (!dough) {
02630
02631 delay = 2500;
02632 state = to_flour;
02633 break;
02634 }
02635
02636 oven = npc->find_closest(831);
02637 if (!oven) {
02638
02639 delay = 2500;
02640 state = to_flour;
02641 break;
02642 }
02643
02644 Tile_coord tpos = dough->get_tile();
02645 Actor_action *pact = Path_walking_actor_action::create_path(
02646 npcpos, tpos, cost);
02647 if (pact) {
02648 npc->set_action(new Sequence_actor_action(
02649 pact,
02650 new Pickup_actor_action(dough, 250)));
02651 } else {
02652
02653 npc->set_action(new Pickup_actor_action(dough, 250));
02654 }
02655
02656 state = put_in_oven;
02657 break;
02658 }
02659 case put_in_oven:
02660 {
02661 if (!dough) {
02662
02663 delay = 2500;
02664 state = to_flour;
02665 break;
02666 }
02667
02668 oven = npc->find_closest(831);
02669 if (!oven) {
02670
02671 dough->remove_this();
02672 dough = 0;
02673
02674 delay = 2500;
02675 state = to_table;
02676 break;
02677 }
02678
02679 Tile_coord tpos = oven->get_tile() +
02680 Tile_coord(1, 1, 0);
02681 Actor_action *pact = Path_walking_actor_action::create_path(
02682 npcpos, tpos, cost);
02683
02684 Rectangle foot = oven->get_footprint();
02685 Shape_info& info = oven->get_info();
02686 Tile_coord cpos(foot.x + 1, foot.y,
02687 oven->get_lift() + info.get_3d_height());
02688
02689 if (pact) {
02690 npc->set_action(new Sequence_actor_action(
02691 pact,
02692 new Pickup_actor_action(dough, cpos, 250)));
02693
02694 dough_in_oven = dough;
02695 dough = 0;
02696 } else {
02697 dough->remove_this();
02698 dough = 0;
02699 }
02700
02701 state = to_flour;
02702 break;
02703 }
02704 }
02705 npc->start(250, delay);
02706 }
02707
02708 void Bake_schedule::ending(int new_type)
02709 {
02710 if (dough) {
02711 dough->remove_this();
02712 dough = 0;
02713 }
02714
02715 if (dough_in_oven) {
02716 dough_in_oven->remove_this();
02717 dough_in_oven = 0;
02718 }
02719 }
02720
02721
02722
02723
02724 void Bake_schedule::notify_object_gone(Game_object *obj)
02725 {
02726 if (obj == dough)
02727 dough = 0;
02728 if (obj == dough_in_oven)
02729 dough_in_oven = 0;
02730 }
02731
02732
02733
02734
02735
02736
02737
02738
02739 Forge_schedule::Forge_schedule(Actor *n) : Schedule(n),
02740 state(put_sword_on_firepit), tongs(0), hammer(0), blank(0),
02741 firepit(0), anvil(0), trough(0), bellows(0)
02742 { }
02743
02744 void Forge_schedule::now_what
02745 (
02746 )
02747 {
02748 Tile_coord npcpos = npc->get_tile();
02749
02750 Actor_pathfinder_client cost(npc, 1);
02751
02752 switch (state) {
02753 case put_sword_on_firepit:
02754 {
02755 if (!blank) {
02756 blank = npc->find_closest(668);
02757
02758
02759 }
02760 if (!blank)
02761 blank = new Ireg_game_object(668, 0, 0, 0);
02762
02763 firepit = npc->find_closest(739);
02764 if (!firepit) {
02765
02766 npc->start(250, 2500);
02767 return;
02768 }
02769
02770 Tile_coord tpos = firepit->get_tile();
02771 Actor_action *pact = Path_walking_actor_action::create_path(
02772 npcpos, tpos, cost);
02773
02774 Rectangle foot = firepit->get_footprint();
02775 Shape_info& info = firepit->get_info();
02776 Tile_coord bpos(foot.x + foot.w/2 + 1, foot.y + foot.h/2,
02777 firepit->get_lift() + info.get_3d_height());
02778 if (pact) {
02779 npc->set_action(new Sequence_actor_action(pact,
02780 new Pickup_actor_action(blank, bpos, 250)));
02781 } else {
02782 npc->set_action(
02783 new Pickup_actor_action(blank, bpos, 250));
02784 }
02785
02786 state = use_bellows;
02787 break;
02788 }
02789 case use_bellows:
02790 {
02791 bellows = npc->find_closest(431);
02792 firepit = npc->find_closest(739);
02793 if (!bellows || !firepit || !blank) {
02794
02795 npc->start(250, 2500);
02796 state = put_sword_on_firepit;
02797 return;
02798 }
02799
02800 Tile_coord tpos = bellows->get_tile() +
02801 Tile_coord(3,0,0);
02802 Actor_action *pact = Path_walking_actor_action::create_path(
02803 npcpos, tpos, cost);
02804
02805 Actor_action **a = new Actor_action*[35];
02806 a[0] = pact;
02807 a[1] = new Face_pos_actor_action(bellows, 250);
02808 a[2] = new Frames_actor_action((signed char *)"\x2b", 1, 0);
02809 a[3] = new Object_animate_actor_action(bellows, 3, 1, 300);
02810 a[4] = new Frames_actor_action((signed char *)"\x20", 1, 0);
02811 a[5] = new Frames_actor_action((signed char *)"\x01", 1, 0, firepit);
02812 a[6] = new Frames_actor_action((signed char *)"\x01", 1, 0, blank);
02813 a[7] = new Frames_actor_action((signed char *)"\x2b", 1, 0);
02814 a[8] = new Object_animate_actor_action(bellows, 3, 1, 300);
02815 a[9] = new Frames_actor_action((signed char *)"\x20", 1, 0);
02816 a[10] = new Frames_actor_action((signed char *)"\x02", 1, 0, blank);
02817 a[11] = new Frames_actor_action((signed char *)"\x2b", 1, 0);
02818 a[12] = new Object_animate_actor_action(bellows, 3, 1, 300);
02819 a[13] = new Frames_actor_action((signed char *)"\x20", 1, 0);
02820 a[14] = new Frames_actor_action((signed char *)"\x02", 1, 0, firepit);
02821 a[15] = new Frames_actor_action((signed char *)"\x03", 1, 0, blank);
02822 a[16] = new Frames_actor_action((signed char *)"\x2b", 1, 0);
02823 a[17] = new Object_animate_actor_action(bellows, 3, 1, 300);
02824 a[18] = new Frames_actor_action((signed char *)"\x20", 1, 0);
02825 a[19] = new Frames_actor_action((signed char *)"\x03", 1, 0, firepit);
02826 a[20] = new Frames_actor_action((signed char *)"\x04", 1, 0, blank);
02827 a[21] = new Frames_actor_action((signed char *)"\x2b", 1, 0);
02828 a[22] = new Object_animate_actor_action(bellows, 3, 1, 300);
02829 a[23] = new Frames_actor_action((signed char *)"\x20", 1, 0);
02830 a[24] = new Frames_actor_action((signed char *)"\x2b", 1, 0);
02831 a[25] = new Object_animate_actor_action(bellows, 3, 1, 300);
02832 a[26] = new Frames_actor_action((signed char *)"\x20", 1, 0);
02833 a[27] = new Frames_actor_action((signed char *)"\x2b", 1, 0);
02834 a[28] = new Object_animate_actor_action(bellows, 3, 1, 300);
02835 a[29] = new Frames_actor_action((signed char *)"\x20", 1, 0);
02836 a[30] = new Frames_actor_action((signed char *)"\x2b", 1, 0);
02837 a[31] = new Object_animate_actor_action(bellows, 3, 1, 300);
02838 a[32] = new Frames_actor_action((signed char *)"\x20", 1, 0);
02839 a[33] = new Frames_actor_action((signed char *)"\x00", 1, 0, bellows);
02840 a[34] = 0;
02841
02842
02843 npc->set_action(new Sequence_actor_action(a));
02844 state = get_tongs;
02845 break;
02846 }
02847 case get_tongs:
02848 {
02849 #if 0
02850 if (!tongs) {
02851 tongs = npc->find_closest(994);
02852
02853 }
02854 #endif
02855 if (!tongs)
02856 tongs = new Ireg_game_object(994, 0, 0, 0);
02857
02858 npc->add_dirty();
02859 npc->add_readied(tongs, Actor::rhand);
02860 npc->add_dirty();
02861
02862 state = sword_on_anvil;
02863 break;
02864 }
02865 case sword_on_anvil:
02866 {
02867 anvil = npc->find_closest(991);
02868 firepit = npc->find_closest(739);
02869 if (!anvil || !firepit || !blank) {
02870
02871 npc->start(250, 2500);
02872 state = put_sword_on_firepit;
02873 return;
02874 }
02875
02876 Tile_coord tpos = firepit->get_tile();
02877 Actor_action *pact = Path_walking_actor_action::create_path(
02878 npcpos, tpos, cost);
02879 Tile_coord tpos2 = anvil->get_tile() +
02880 Tile_coord(0,1,0);
02881 Actor_action *pact2 = Path_walking_actor_action::create_path(
02882 tpos, tpos2, cost);
02883
02884 Rectangle foot = anvil->get_footprint();
02885 Shape_info& info = anvil->get_info();
02886 Tile_coord bpos(foot.x + 2, foot.y,
02887 anvil->get_lift() + info.get_3d_height());
02888 if (pact && pact2) {
02889 npc->set_action(new Sequence_actor_action(pact,
02890 new Pickup_actor_action(blank, 250),
02891 pact2,
02892 new Pickup_actor_action(blank, bpos, 250)));
02893 } else {
02894 npc->set_action(new Sequence_actor_action(
02895 new Pickup_actor_action(blank, 250),
02896 new Pickup_actor_action(blank, bpos, 250)));
02897 }
02898 state = get_hammer;
02899 break;
02900 }
02901 case get_hammer:
02902 {
02903 #if 0
02904 if (!hammer) {
02905 hammer = npc->find_closest(623);
02906
02907 }
02908 #endif
02909
02910 if (!hammer)
02911 hammer = new Ireg_game_object(623, 0, 0, 0);
02912
02913 npc->add_dirty();
02914 if (tongs) {
02915 tongs->remove_this();
02916 tongs = 0;
02917 }
02918 npc->add_readied(hammer, Actor::rhand);
02919 npc->add_dirty();
02920
02921 state = use_hammer;
02922 break;
02923 }
02924 case use_hammer:
02925 {
02926 anvil = npc->find_closest(991);
02927 firepit = npc->find_closest(739);
02928 if (!anvil || !firepit || !blank) {
02929
02930 npc->start(250, 2500);
02931 state = put_sword_on_firepit;
02932 return;
02933 }
02934
02935 signed char frames[12];
02936 int cnt = npc->get_attack_frames(623, false, 0, frames);
02937 npc->set_action(new Frames_actor_action(frames, cnt));
02938
02939 Actor_action **a = new Actor_action*[10];
02940 a[0] = new Frames_actor_action(frames, cnt);
02941 a[1] = new Frames_actor_action((signed char *)"\x03", 1, 0, blank);
02942 a[2] = new Frames_actor_action((signed char *)"\x02", 1, 0, firepit);
02943 a[3] = new Frames_actor_action(frames, cnt);
02944 a[4] = new Frames_actor_action((signed char *)"\x02", 1, 0, blank);
02945 a[5] = new Frames_actor_action((signed char *)"\x01", 1, 0, firepit);
02946 a[6] = new Frames_actor_action(frames, cnt);
02947 a[7] = new Frames_actor_action((signed char *)"\x01", 1, 0, blank);
02948 a[8] = new Frames_actor_action((signed char *)"\x00", 1, 0, firepit);
02949 a[9] = 0;
02950 npc->set_action(new Sequence_actor_action(a));
02951
02952 state = walk_to_trough;
02953 break;
02954 }
02955 case walk_to_trough:
02956 {
02957 npc->add_dirty();
02958 if (hammer) {
02959 hammer->remove_this();
02960 hammer = 0;
02961 }
02962 npc->add_dirty();
02963
02964 trough = npc->find_closest(719);
02965 if (!trough) {
02966
02967 npc->start(250, 2500);
02968 state = put_sword_on_firepit;
02969 return;
02970 }
02971
02972 if (trough->get_framenum() == 0) {
02973 Tile_coord tpos = trough->get_tile() +
02974 Tile_coord(0,2,0);
02975 Actor_action *pact = Path_walking_actor_action::
02976 create_path(npcpos, tpos, cost);
02977 npc->set_action(pact);
02978 state = fill_trough;
02979 break;
02980 }
02981
02982 state = get_tongs2;
02983 break;
02984 }
02985 case fill_trough:
02986 {
02987 trough = npc->find_closest(719);
02988 if (!trough) {
02989
02990 npc->start(250, 2500);
02991 state = put_sword_on_firepit;
02992 return;
02993 }
02994
02995 int dir = npc->get_direction(trough);
02996 trough->change_frame(3);
02997 npc->change_frame(
02998 npc->get_dir_framenum(dir, Actor::bow_frame));
02999
03000 state = get_tongs2;
03001 break;
03002 }
03003 case get_tongs2:
03004 {
03005 #if 0
03006 if (!tongs) {
03007 tongs = npc->find_closest(994);
03008
03009 }
03010 #endif
03011 if (!tongs)
03012 tongs = new Ireg_game_object(994, 0, 0, 0);
03013
03014 npc->add_dirty();
03015 npc->add_readied(tongs, Actor::rhand);
03016 npc->add_dirty();
03017
03018 state = use_trough;
03019 break;
03020 }
03021 case use_trough:
03022 {
03023 trough = npc->find_closest(719);
03024 anvil = npc->find_closest(991);
03025 if (!trough || !anvil || !blank) {
03026
03027 npc->start(250, 2500);
03028 state = put_sword_on_firepit;
03029 return;
03030 }
03031
03032 Tile_coord tpos = anvil->get_tile() +
03033 Tile_coord(0,1,0);
03034 Actor_action *pact = Path_walking_actor_action::
03035 create_path(npcpos, tpos, cost);
03036
03037 Tile_coord tpos2 = trough->get_tile() +
03038 Tile_coord(0,2,0);
03039 Actor_action *pact2 = Path_walking_actor_action::
03040 create_path(tpos, tpos2, cost);
03041
03042 if (pact && pact2) {
03043 signed char troughframe = trough->get_framenum() - 1;
03044 if (troughframe < 0) troughframe = 0;
03045
03046 int dir = npc->get_direction(trough);
03047 signed char npcframe = npc->get_dir_framenum(dir, Actor::bow_frame);
03048
03049 Actor_action **a = new Actor_action*[7];
03050 a[0] = pact;
03051 a[1] = new Pickup_actor_action(blank, 250);
03052 a[2] = pact2;
03053 a[3] = new Frames_actor_action(&npcframe, 1, 250);
03054 a[4] = new Frames_actor_action(&troughframe, 1, 0, trough);
03055 a[5] = new Frames_actor_action((signed char *)"\x00", 1, 0, blank);
03056 a[6] = 0;
03057 npc->set_action(new Sequence_actor_action(a));
03058 } else {
03059
03060 npc->set_action(new Sequence_actor_action(
03061 new Pickup_actor_action(blank, 250),
03062 new Frames_actor_action((signed char *)"\0", 1, 0, blank)));
03063 }
03064
03065 state = done;
03066 break;
03067 }
03068 case done:
03069 {
03070 npc->add_dirty();
03071 if (tongs) {
03072 tongs->remove_this();
03073 tongs = 0;
03074 }
03075 npc->add_dirty();
03076
03077
03078 state = put_sword_on_firepit;
03079 }
03080 }
03081
03082 npc->start(250, 100);
03083 }
03084
03085
03086
03087
03088
03089 void Forge_schedule::ending
03090 (
03091 int new_type
03092 )
03093 {
03094
03095 if (tongs) {
03096 tongs->remove_this();
03097 tongs = 0;
03098 }
03099 if (hammer) {
03100 hammer->remove_this();
03101 hammer = 0;
03102 }
03103
03104 firepit = npc->find_closest(739);
03105 bellows = npc->find_closest(431);
03106
03107 if (firepit && firepit->get_framenum() != 0)
03108 firepit->change_frame(0);
03109 if (bellows && bellows->get_framenum() != 0)
03110 bellows->change_frame(0);
03111 if (blank && blank->get_framenum() != 0)
03112 blank->change_frame(0);
03113
03114 }
03115
03116
03117
03118
03119
03120
03121 void Walk_to_schedule::walk_off_screen
03122 (
03123 Rectangle& screen,
03124
03125 Tile_coord& goal
03126 )
03127 {
03128
03129 if (goal.tx >= screen.x + screen.w)
03130 {
03131 goal.tx = screen.x + screen.w - 1;
03132 goal.ty = -1;
03133 }
03134 else if (goal.tx < screen.x)
03135 {
03136 goal.tx = screen.x;
03137 goal.ty = -1;
03138 }
03139 else if (goal.ty >= screen.y + screen.h)
03140 {
03141 goal.ty = screen.y + screen.h - 1;
03142 goal.tx = -1;
03143 }
03144 else if (goal.ty < screen.y)
03145 {
03146 goal.ty = screen.y;
03147 goal.tx = -1;
03148 }
03149 }
03150
03151
03152
03153
03154
03155 Walk_to_schedule::Walk_to_schedule
03156 (
03157 Actor *n,
03158 Tile_coord d,
03159 int new_sched,
03160 int delay
03161 ) : Schedule(n), dest(d), new_schedule(new_sched), retries(0), legs(0)
03162 {
03163
03164 first_delay = delay >= 0 ? delay : 2*(rand()%10000);
03165 }
03166
03167
03168
03169
03170
03171 void Walk_to_schedule::now_what
03172 (
03173 )
03174 {
03175 if (npc->get_tile().distance(dest) <= 3)
03176 {
03177 npc->set_schedule_type(new_schedule);
03178 return;
03179 }
03180 if (legs >= 40 || retries >= 2)
03181
03182 {
03183 npc->move(dest.tx, dest.ty, dest.tz);
03184 npc->set_schedule_type(new_schedule);
03185 return;
03186 }
03187
03188 Rectangle screen = gwin->get_win_tile_rect();
03189 screen.enlarge(6);
03190
03191 Tile_coord from = npc->get_tile(),
03192 to = dest;
03193
03194 if (!screen.has_point(to.tx, to.ty))
03195 {
03196 if (!screen.has_point(from.tx, from.ty))
03197 {
03198 retries = 100;
03199 npc->start(200, 100);
03200 return;
03201 }
03202
03203
03204
03205 if (from.distance(to) > 80 || legs < 10)
03206
03207 walk_off_screen(screen, to);
03208 }
03209 else if (!screen.has_point(from.tx, from.ty))
03210
03211 walk_off_screen(screen, from);
03212 blocked = Tile_coord(-1, -1, -1);
03213 cout << "Finding path to schedule for " << npc->get_name() << endl;
03214
03215
03216 if (!npc->walk_path_to_tile(from, to, gwin->get_std_delay(),
03217 first_delay + rand()%1000))
03218 {
03219 #ifdef DEBUG
03220 cout << "Failed to find path for " << npc->get_name() << endl;
03221 #endif
03222 npc->walk_to_tile(dest, gwin->get_std_delay(), 1000);
03223 retries++;
03224 }
03225 else
03226 {
03227 legs++;
03228 retries = 0;
03229 }
03230 first_delay = 0;
03231 }
03232
03233
03234
03235
03236
03237 void Walk_to_schedule::im_dormant
03238 (
03239 )
03240 {
03241 Walk_to_schedule::now_what();
03242 }
03243
03244
03245
03246
03247
03248 int Walk_to_schedule::get_actual_type
03249 (
03250 Actor *
03251 )
03252 {
03253 return new_schedule;
03254 }
03255
03256
03257
03258
03259
03260 void Schedule_change::set
03261 (
03262 unsigned char *entry
03263 )
03264 {
03265 time = entry[0]&7;
03266 type = entry[0]>>3;
03267 x = entry[1];
03268 y = entry[2];
03269 superchunk = entry[3];
03270 }
03271
03272
03273
03274
03275
03276 void Schedule_change::get
03277 (
03278 unsigned char *entry
03279 )
03280 {
03281 entry[0] = time&7;
03282 entry[0] |= (type&31) << 3;
03283 entry[1] = x;
03284 entry[2] = y;
03285 entry[3] = superchunk;
03286 }
03287
03288
03289
03290
03291
03292 void Schedule_change::set
03293 (
03294 int ax,
03295 int ay,
03296 unsigned char stype,
03297 unsigned char stime
03298 )
03299 {
03300 time = stime;
03301 type = stype;
03302 x = static_cast<unsigned char>(ax%c_tiles_per_schunk);
03303 y = static_cast<unsigned char>(ay%c_tiles_per_schunk);
03304 superchunk = static_cast<unsigned char>((ay/c_tiles_per_schunk)*12 + (ax/c_tiles_per_schunk));
03305 }
03306
03307
03308
03309
03310
03311 Tile_coord Schedule_change::get_pos() const
03312 {
03313 int cx = 16*(superchunk%12) + x/16,
03314 cy = 16*(superchunk/12) + y/16,
03315 tx = x%16,
03316 ty = y%16;
03317 return Tile_coord(cx*c_tiles_per_chunk + tx, cy*c_tiles_per_chunk + ty, 0);
03318 }
03319
03320
03321