00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #ifdef HAVE_CONFIG_H
00020 # include <config.h>
00021 #endif
00022
00023 #include "ucinternal.h"
00024 #include "useval.h"
00025 #include "ucsched.h"
00026 #include "Audio.h"
00027 #include "barge.h"
00028 #include "game.h"
00029 #include "frameseq.h"
00030 #include "gamewin.h"
00031 #include "gameclk.h"
00032 #include "egg.h"
00033 #include "actors.h"
00034 #include "ucscriptop.h"
00035
00036 #include <iostream>
00037 #include <iomanip>
00038
00039 using std::cout;
00040 using std::endl;
00041 using std::hex;
00042 using std::setfill;
00043 using std::setw;
00044
00045 using namespace Ucscript;
00046
00047 int Usecode_script::count = 0;
00048 Usecode_script *Usecode_script::first = 0;
00049
00050
00051
00052
00053
00054 Usecode_script::Usecode_script
00055 (
00056 Game_object *item,
00057 Usecode_value *cd,
00058 int findex,
00059 int nhalt,
00060 int del
00061 ) : obj(item), code(cd), i(0), frame_index(findex),
00062 no_halt(nhalt != 0), must_finish(false), delay(del)
00063 {
00064 cnt = code->get_array_size();
00065 }
00066
00067
00068
00069
00070
00071 Usecode_script::Usecode_script
00072 (
00073 Game_object *o,
00074 Usecode_value *cd
00075 ) : obj(o), code(cd), cnt(0), i(0), frame_index(0), no_halt(false),
00076 must_finish(false), delay(0)
00077 {
00078 if (!code)
00079 code = new Usecode_value(0, 0);
00080 else
00081 {
00082 cnt = code->get_array_size();
00083 if (!cnt)
00084 {
00085 code = new Usecode_value(1, code);
00086 cnt = 1;
00087 }
00088 }
00089 }
00090
00091
00092
00093
00094
00095 Usecode_script::~Usecode_script()
00096 {
00097 delete code;
00098 count--;
00099 if (next)
00100 next->prev = prev;
00101 if (prev)
00102 prev->next = next;
00103 else
00104 first = next;
00105 }
00106
00107
00108
00109
00110
00111
00112 void Usecode_script::start
00113 (
00114 long d
00115 )
00116 {
00117 Game_window *gwin = Game_window::get_instance();
00118 int cnt = code->get_array_size();
00119 for (int i = 0; i < cnt; i++)
00120 {
00121 int opval0 = code->get_elem(i).get_int_value();
00122 if (opval0 == Ucscript::dont_halt)
00123 no_halt = true;
00124 else if (opval0 == Ucscript::finish)
00125 must_finish = true;
00126 else
00127 break;
00128 }
00129 if (!is_no_halt())
00130
00131
00132 Usecode_script::terminate(obj);
00133 count++;
00134 next = first;
00135 prev = 0;
00136 if (first)
00137 first->prev = this;
00138 first = this;
00139
00140
00141 gwin->get_tqueue()->add(d + SDL_GetTicks(), this,
00142 (long) gwin->get_usecode());
00143 }
00144
00145
00146
00147
00148
00149 void Usecode_script::halt
00150 (
00151 )
00152 {
00153 if (!no_halt)
00154 i = cnt;
00155 }
00156
00157
00158
00159
00160 void Usecode_script::add(int v1)
00161 {
00162 code->append(&v1, 1);
00163 cnt++;
00164 }
00165 void Usecode_script::add(int v1, int v2)
00166 {
00167 int vals[2];
00168 vals[0] = v1;
00169 vals[1] = v2;
00170 code->append(vals, 2);
00171 cnt += 2;
00172 }
00173 void Usecode_script::add(int v1, const char *str)
00174 {
00175 int sz = code->get_array_size();
00176 code->resize(sz + 2);
00177 (*code)[sz] = v1;
00178 (*code)[sz + 1] = str;
00179 cnt += 2;
00180 }
00181 void Usecode_script::add(int *vals, int c)
00182 {
00183 code->append(vals, cnt);
00184 cnt += c;
00185 }
00186
00187
00188
00189
00190
00191
00192
00193 Usecode_script *Usecode_script::find
00194 (
00195 Game_object *srch,
00196 Usecode_script *last_found
00197 )
00198 {
00199 Usecode_script *start = last_found ? last_found->next : first;
00200 for (Usecode_script *each = start; each; each = each->next)
00201 if (each->obj == srch)
00202 return each;
00203 return (0);
00204 }
00205
00206
00207
00208
00209
00210 void Usecode_script::terminate
00211 (
00212 Game_object *obj
00213 )
00214 {
00215 Usecode_script *next = 0;
00216 for (Usecode_script *each = first; each; each = next)
00217 {
00218 next = each->next;
00219 if (each->obj == obj)
00220 each->halt();
00221 }
00222 }
00223
00224
00225
00226
00227
00228
00229 void Usecode_script::clear
00230 (
00231 )
00232 {
00233 while (first)
00234 delete first;
00235 }
00236
00237
00238
00239
00240
00241
00242 void Usecode_script::purge
00243 (
00244 Tile_coord spot,
00245 int dist
00246 )
00247 {
00248 Usecode_script *next = 0;
00249 Game_window *gwin = Game_window::get_instance();
00250 Usecode_internal *usecode = static_cast<Usecode_internal*>(
00251 gwin->get_usecode());
00252 for (Usecode_script *each = first; each; each = next)
00253 {
00254 next = each->next;
00255
00256 if (each->obj && !each->i &&
00257 each->obj->get_outermost()->get_tile().distance(
00258 spot) > dist)
00259 {
00260 each->no_halt = false;
00261 if (each->must_finish)
00262 {
00263 cout << "MUST finish this script" << endl;
00264 each->exec(usecode, true);
00265 }
00266 each->halt();
00267 }
00268 }
00269 }
00270
00271 inline void Usecode_script::activate_egg(Usecode_internal *usecode,
00272 Game_object *e)
00273 {
00274 if (!e || !e->is_egg())
00275 return;
00276 int type = ((Egg_object *) e)->get_type();
00277
00278 if (type == Egg_object::monster || type == Egg_object::button ||
00279 type == Egg_object::missile)
00280 ((Egg_object *) e)->activate(
00281 usecode->gwin->get_main_actor(), true);
00282 }
00283
00284
00285
00286
00287
00288
00289 void Usecode_script::handle_event
00290 (
00291 unsigned long curtime,
00292 long udata
00293 )
00294 {
00295 Usecode_internal *usecode = (Usecode_internal *) udata;
00296 int delay = exec(usecode, false);
00297 if (i < cnt)
00298 {
00299 usecode->gwin->get_tqueue()->add(curtime + delay, this, udata);
00300 return;
00301 }
00302 #if 0
00303 if (count == 1 &&
00304 objpos.tx != -1)
00305 {
00306 usecode->activate_cached(objpos);
00307 }
00308 #endif
00309 delete this;
00310 }
00311
00312
00313
00314
00315
00316
00317
00318 int Usecode_script::exec
00319 (
00320 Usecode_internal *usecode,
00321 bool finish
00322 )
00323 {
00324 Game_window *gwin = usecode->gwin;
00325 int delay = gwin->get_std_delay();
00326 bool do_another = true;
00327 int opcode;
00328
00329 for (; i < cnt && ((opcode = code->get_elem(i).get_int_value())
00330 == 0x1 || do_another); i++)
00331 {
00332 do_another = finish;
00333 switch (opcode)
00334 {
00335 case cont:
00336 do_another = true;
00337 gwin->set_painted();
00338 break;
00339 case repeat:
00340 {
00341 Usecode_value& cntval = code->get_elem(i + 2);
00342 int cnt = cntval.get_int_value();
00343 if (cnt <= 0)
00344
00345 i += 2;
00346 else
00347 {
00348 cntval = Usecode_value(cnt - 1);
00349 Usecode_value& offval = code->get_elem(i + 1);
00350 i += offval.get_int_value() - 1;
00351 if (i < -1)
00352 i = -1;
00353 do_another = true;
00354 }
00355 break;
00356 }
00357 case repeat2:
00358 {
00359
00360
00361
00362
00363
00364
00365 do_another = true;
00366 Usecode_value& cntval = code->get_elem(i + 3);
00367 Usecode_value& origval = code->get_elem(i + 2);
00368 int cnt = cntval.get_int_value();
00369 int orig = origval.get_int_value();
00370 if (cnt > orig) {
00371 cntval = origval;
00372 cnt = orig;
00373 }
00374 if (cnt <= 0) {
00375
00376 i += 3;
00377 cntval = origval;
00378 } else
00379 {
00380 cntval = Usecode_value(cnt - 1);
00381 Usecode_value& offval = code->get_elem(i + 1);
00382 i += offval.get_int_value() - 1;
00383 }
00384 break;
00385 }
00386 case nop:
00387 break;
00388 case Ucscript::finish:
00389 must_finish = true;
00390 do_another = true;
00391 break;
00392 case dont_halt:
00393
00394
00395 no_halt = true;
00396 do_another = true;
00397 break;
00398 case delay_ticks:
00399 {
00400 Usecode_value& delayval = code->get_elem(++i);
00401
00402 delay = gwin->get_std_delay()*delayval.get_int_value();
00403 break;
00404 }
00405 case delay_hours:
00406 {
00407 Usecode_value& delayval = code->get_elem(++i);
00408 delay = delayval.get_int_value();
00409
00410 delay = (delay*3600)/time_factor;
00411 delay *= 1000;
00412 break;
00413 }
00414 #if 0
00415 case finish:
00416
00417
00418 break;
00419 #endif
00420 case Ucscript::remove:
00421 usecode->remove_item(obj);
00422 break;
00423 case rise:
00424 {
00425 Tile_coord t = obj->get_tile();
00426 if (t.tz < 10)
00427 t.tz++;
00428 obj->move(t);
00429 break;
00430 }
00431 case descend:
00432 {
00433 Tile_coord t = obj->get_tile();
00434 if (t.tz > 0)
00435 t.tz--;
00436 obj->move(t);
00437 break;
00438 }
00439 case frame:
00440 usecode->set_item_frame(obj,
00441 code->get_elem(++i).get_int_value());
00442 break;
00443 case egg:
00444 activate_egg(usecode, obj);
00445 break;
00446 case next_frame_max:
00447 {
00448 int nframes = obj->get_num_frames();
00449 if (obj->get_framenum() < nframes - 1)
00450 usecode->set_item_frame(obj,
00451 1+obj->get_framenum());
00452 break;
00453 }
00454 case next_frame:
00455 {
00456 int nframes = obj->get_num_frames();
00457 usecode->set_item_frame(obj,
00458 (1 + obj->get_framenum())%nframes);
00459 break;
00460 }
00461 case prev_frame_min:
00462 if (obj->get_framenum() > 0)
00463 usecode->set_item_frame(obj,
00464 obj->get_framenum() - 1);
00465 break;
00466 case prev_frame:
00467 {
00468 int nframes = obj->get_num_frames();
00469 int pframe = obj->get_framenum() - 1;
00470 usecode->set_item_frame(obj,
00471 (pframe + nframes)%nframes);
00472 break;
00473 }
00474 case say:
00475 {
00476 Usecode_value& strval = code->get_elem(++i);
00477 Usecode_value objval(obj);
00478 usecode->item_say(objval, strval);
00479 break;
00480 }
00481 case Ucscript::step:
00482 {
00483
00484 Usecode_value& val = code->get_elem(++i);
00485
00486 step(usecode, val.get_int_value()&7);
00487
00488
00489 break;
00490 }
00491 case music:
00492 {
00493 Usecode_value& val = code->get_elem(++i);
00494 Audio::get_ptr()->start_music(val.get_int_value(),
00495 false);
00496 break;
00497 }
00498 case Ucscript::usecode:
00499 {
00500 Usecode_value& val = code->get_elem(++i);
00501 int fun = val.get_int_value();
00502
00503 Usecode_internal::Usecode_events ev =
00504 Usecode_internal::internal_exec;
00505 if (obj && obj->is_egg()
00506 #if 0
00507
00508 && ((Egg_object *)obj)->get_type() == Egg_object::usecode
00509 #endif
00510 )
00511 ev = Usecode_internal::egg_proximity;
00512
00513 else if (fun == usecode->telekenesis_fun)
00514 {
00515 ev = Usecode_internal::double_click;
00516 usecode->telekenesis_fun = -1;
00517 }
00518 usecode->call_usecode(fun, obj, ev);
00519 break;
00520 }
00521 case Ucscript::usecode2:
00522 {
00523 Usecode_value& val = code->get_elem(++i);
00524 int evid = code->get_elem(++i).get_int_value();
00525 usecode->call_usecode(val.get_int_value(), obj,
00526 (Usecode_internal::Usecode_events) evid);
00527 break;
00528 }
00529 case speech:
00530 {
00531 Usecode_value& val = code->get_elem(++i);
00532 int track = val.get_int_value();
00533 if (track >= 0)
00534 Audio::get_ptr()->start_speech(track);
00535 }
00536 case sfx:
00537 {
00538 Usecode_value& val = code->get_elem(++i);
00539 Audio::get_ptr()->play_sound_effect(
00540 val.get_int_value());
00541 break;
00542 }
00543 case face_dir:
00544 {
00545
00546 Usecode_value& val = code->get_elem(++i);
00547
00548 int dir = val.get_int_value()&7;
00549 Actor *npc = obj->as_actor();
00550 if (npc)
00551 npc->set_usecode_dir(dir);
00552 usecode->set_item_frame(obj, obj->get_dir_framenum(
00553 dir, obj->get_framenum()), 1, 1);
00554 frame_index = 0;
00555 break;
00556 }
00557 case hit:
00558 {
00559 Usecode_value hps = code->get_elem(++i);
00560 Usecode_value unk = code->get_elem(++i);
00561 Actor *act = usecode->as_actor(obj);
00562 if (act)
00563 act->reduce_health(hps.get_int_value());
00564 break;
00565 }
00566 case resurrect:
00567 {
00568 Dead_body *body = (Dead_body *) obj;
00569 Actor *act = gwin->get_npc(body->get_live_npc_num());
00570 if (act)
00571 act->resurrect(body);
00572 break;
00573 }
00574 default:
00575
00576 if (opcode >= 0x61 && opcode <= 0x70)
00577 {
00578 Actor *npc = obj->as_actor();
00579 npc->clear_rest_time();
00580 int v = obj->get_dir_framenum(
00581 npc ? npc->get_usecode_dir() : 0,
00582 opcode - 0x61);
00583 usecode->set_item_frame(obj, v, 1, 1);
00584 }
00585 else if (opcode >= 0x30 && opcode < 0x38)
00586 {
00587 step(usecode, opcode&7);
00588 do_another = true;
00589 }
00590 else
00591 {
00592 cout << "Und sched. opcode " << hex <<
00593 "0x" << setfill((char)0x30) << setw(2)
00594 << opcode << std::dec << endl;
00595 do_another = true;
00596 }
00597 break;
00598 }
00599 }
00600 return delay;
00601 }
00602
00603
00604
00605
00606
00607 void Usecode_script::step
00608 (
00609 Usecode_internal *usecode,
00610 int dir
00611 )
00612 {
00613 int frame = obj->get_framenum();
00614 Barge_object *barge;
00615 Actor *act = usecode->as_actor(obj);
00616 if (act)
00617 {
00618 Frames_sequence *frames = act->get_frames(dir);
00619
00620 frame = frames->get_next(frame_index);
00621 Tile_coord tile = obj->get_tile().get_neighbor(dir);
00622 obj->step(tile, frame);
00623 }
00624 else if ((barge = obj->as_barge()) != 0)
00625 {
00626 for (int i = 0; i < 4; i++)
00627 {
00628 Tile_coord t = obj->get_tile().get_neighbor(
00629 dir);
00630 obj->step(t, 0);
00631 }
00632 }
00633 }
00634
00635
00636
00637
00638
00639
00640
00641 int Usecode_script::save
00642 (
00643 unsigned char *buf,
00644 int buflen
00645 )
00646 {
00647
00648 long when = Game_window::get_instance()->get_tqueue()->find_delay(
00649 this, SDL_GetTicks());
00650 if (when < 0)
00651 return -1;
00652 uint8 *ptr = buf;
00653 Write2(ptr, cnt);
00654 Write2(ptr, i);
00655 for (int j = 0; j < cnt; j++)
00656 {
00657 Usecode_value& val = code->get_elem(j);
00658 int len = val.save(ptr, buflen - (ptr - buf));
00659 if (len < 0)
00660 return -1;
00661 ptr += len;
00662 }
00663 if (buflen - (ptr - buf) < 8)
00664 return -1;
00665 Write2(ptr, frame_index);
00666 Write2(ptr, no_halt ? 1 : 0);
00667 Write4(ptr, when);
00668 return (ptr - buf);
00669 }
00670
00671
00672
00673
00674
00675
00676
00677
00678 Usecode_script *Usecode_script::restore
00679 (
00680 Game_object *item,
00681 unsigned char *buf,
00682 int buflen
00683 )
00684 {
00685 uint8 *ptr = buf;
00686 int cnt = Read2(ptr);
00687 int curindex = Read2(ptr);
00688
00689 Usecode_value *code = new Usecode_value(cnt, 0);
00690 for (int i = 0; i < cnt; i++)
00691 {
00692 Usecode_value& val = code->get_elem(i);
00693 if (!val.restore(ptr, buflen - (ptr - buf)))
00694 {
00695 delete code;
00696 return 0;
00697 }
00698 }
00699 if (buflen - (ptr - buf) < 8)
00700 {
00701 delete code;
00702 return 0;
00703 }
00704 int frame_index = Read2(ptr);
00705 int no_halt = Read2(ptr);
00706 int delay = Read4(ptr);
00707 Usecode_script *scr =
00708 new Usecode_script(item, code, frame_index, no_halt, delay);
00709 scr->i = curindex;
00710 return scr;
00711 }
00712
00713
00714
00715
00716
00717 void Usecode_script::print
00718 (
00719 std::ostream& out
00720 )
00721 {
00722 out << hex << "Obj = 0x" << setfill((char)0x30) << setw(2)
00723 << (void *) obj << ": " "(";
00724 for (int i = 0; i < cnt; i++)
00725 {
00726 if (i > 0)
00727 out << ", ";
00728 code->get_elem(i).print(out);
00729 }
00730 out <<") = ";
00731 out << std::dec;
00732 }