00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifdef HAVE_CONFIG_H
00023 # include <config.h>
00024 #endif
00025
00026 #ifndef ALPHA_LINUX_CXX
00027 # include <cstdio>
00028 # include <fstream>
00029 # include <cstring>
00030 # include <cstdlib>
00031 #endif
00032
00033 #include <iomanip>
00034
00035 #ifdef XWIN
00036 #include <csignal>
00037 #endif
00038 #include <algorithm>
00039
00040 #include "Gump.h"
00041 #include "Gump_manager.h"
00042 #include "Text_gump.h"
00043 #include "Audio.h"
00044 #include "animate.h"
00045 #include "barge.h"
00046 #include "chunks.h"
00047 #include "conversation.h"
00048 #include "exult.h"
00049 #include "game.h"
00050 #include "gamewin.h"
00051 #include "gamemap.h"
00052 #include "keyring.h"
00053 #include "mouse.h"
00054 #include "schedule.h"
00055 #include "tqueue.h"
00056 #include "ucinternal.h"
00057 #include "ucsched.h"
00058 #include "useval.h"
00059 #include "utils.h"
00060 #include "vec.h"
00061 #include "actors.h"
00062 #include "egg.h"
00063 #include "actions.h"
00064 #include "stackframe.h"
00065 #include "ucfunction.h"
00066 #include "effects.h"
00067 #include "party.h"
00068
00069 #if (defined(USE_EXULTSTUDIO) && defined(USECODE_DEBUGGER))
00070 #include "server.h"
00071 #include "servemsg.h"
00072 #include "debugmsg.h"
00073 #include "debugserver.h"
00074 #endif
00075
00076 #ifndef UNDER_CE
00077 using std::cerr;
00078 using std::cout;
00079 using std::endl;
00080 using std::istream;
00081 using std::ifstream;
00082 using std::ofstream;
00083 using std::istream;
00084 using std::ostream;
00085 using std::exit;
00086 using std::ios;
00087 using std::dec;
00088 using std::hex;
00089 using std::memset;
00090 using std::setfill;
00091 using std::setw;
00092 using std::size_t;
00093 using std::string;
00094 using std::strcat;
00095 using std::strchr;
00096 using std::strcmp;
00097 using std::strcpy;
00098 using std::strlen;
00099 using std::vector;
00100 using std::ostream;
00101 #endif
00102
00103
00104
00105 extern bool intrinsic_trace;
00106 extern int usecode_trace;
00107
00108 #if 0 && USECODE_DEBUGGER
00109
00110 extern bool usecode_debugging;
00111 std::vector<int> intrinsic_breakpoints;
00112
00113 void initialise_usecode_debugger(void)
00114 {
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125 }
00126
00127 #endif
00128
00129
00130 void Usecode_internal::stack_trace(ostream& out)
00131 {
00132 if (call_stack.empty())
00133 return;
00134
00135 std::deque<Stack_frame*>::iterator iter = call_stack.begin();
00136
00137 do {
00138 out << *(*iter) << endl;
00139 if ((*iter)->call_depth == 0)
00140 break;
00141 ++iter;
00142 } while (true);
00143 }
00144
00145 bool Usecode_internal::call_function(int funcid,
00146 int eventid,
00147 Game_object *caller,
00148 bool entrypoint, bool orig)
00149 {
00150
00151 vector<Usecode_function*>& slot = funs[funcid/0x100];
00152 size_t index = funcid%0x100;
00153 Usecode_function *fun = index < slot.size() ? slot[index] : 0;
00154 if (!fun)
00155 {
00156 #ifdef DEBUG
00157 cout << "Usecode " << funcid << " not found." << endl;
00158 #endif
00159 return false;
00160 }
00161 if (orig)
00162 if (!(fun = fun->orig))
00163 {
00164 #ifdef DEBUG
00165 cout << "Original usecode " << funcid << " not found."
00166 << endl;
00167 #endif
00168 return false;
00169 }
00170
00171 int depth, oldstack, chain;
00172
00173 if (entrypoint)
00174 {
00175 depth = 0;
00176 oldstack = 0;
00177 chain = Stack_frame::getCallChainID();
00178
00179 } else {
00180 Stack_frame *parent = call_stack.front();
00181
00182
00183 depth = parent->call_depth + 1;
00184
00185
00186 oldstack = sp - parent->save_sp;
00187
00188 chain = parent->call_chain;
00189
00190 if (caller == 0)
00191 caller = parent->caller_item;
00192 }
00193
00194 Stack_frame *frame = new Stack_frame(fun, eventid, caller, chain, depth);
00195
00196 while (frame->num_args > oldstack)
00197 {
00198 pushi(0);
00199 oldstack++;
00200 }
00201
00202
00203 int i;
00204 for (i = 0; i < frame->num_args; i++)
00205 {
00206 Usecode_value val = pop();
00207 frame->locals[frame->num_args - i - 1] = val;
00208 }
00209
00210
00211 frame->save_sp = sp;
00212
00213
00214 call_stack.push_front(frame);
00215
00216
00217 #ifdef DEBUG
00218 cout << "Running usecode " << hex << setfill((char)0x30)
00219 << setw(4) << funcid << dec << setfill(' ') <<
00220 " (";
00221 for (i = 0; i < frame->num_args; i++)
00222 {
00223 if (i)
00224 cout << ", ";
00225 frame->locals[i].print(cout);
00226 }
00227 cout << ") with event " << eventid
00228 << ", depth " << frame->call_depth << endl;
00229 #endif
00230
00231 return true;
00232 }
00233
00234 void Usecode_internal::previous_stack_frame()
00235 {
00236
00237 Stack_frame *frame = call_stack.front();
00238 call_stack.pop_front();
00239
00240
00241 sp = frame->save_sp;
00242
00243 if (frame->call_depth == 0) {
00244
00245
00246
00247
00248 call_stack.push_front(0);
00249 }
00250
00251 delete frame;
00252 }
00253
00254 void Usecode_internal::return_from_function(Usecode_value& retval)
00255 {
00256 #ifdef DEBUG
00257
00258 int oldfunction = call_stack.front()->function->id;
00259 #endif
00260
00261
00262 previous_stack_frame();
00263
00264
00265 push(retval);
00266
00267
00268 #ifdef DEBUG
00269 Stack_frame *parent_frame = call_stack.front();
00270
00271 cout << "Returning (";
00272 retval.print(cout);
00273 cout << ") from usecode " << hex << setw(4) <<
00274 setfill((char)0x30) << oldfunction << dec << setfill(' ')
00275 << endl;
00276
00277
00278 if (parent_frame) {
00279 int newfunction = call_stack.front()->function->id;
00280
00281 cout << "...back into usecode " << hex << setw(4) <<
00282 setfill((char)0x30) << newfunction << dec << setfill(' ') << endl;
00283 }
00284 #endif
00285 }
00286
00287 void Usecode_internal::return_from_procedure()
00288 {
00289 #ifdef DEBUG
00290
00291 int oldfunction = call_stack.front()->function->id;
00292 #endif
00293
00294
00295 previous_stack_frame();
00296
00297
00298 #ifdef DEBUG
00299 Stack_frame *parent_frame = call_stack.front();
00300
00301 cout << "Returning from usecode " << hex << setw(4) <<
00302 setfill((char)0x30) << oldfunction << dec << setfill(' ')
00303 << endl;
00304
00305 if (parent_frame) {
00306 int newfunction = call_stack.front()->function->id;
00307
00308 cout << "...back into usecode " << hex << setw(4) <<
00309 setfill((char)0x30) << newfunction << dec << setfill(' ') << endl;
00310 }
00311 #endif
00312 }
00313
00314 void Usecode_internal::abort_function()
00315 {
00316 #ifdef DEBUG
00317 int functionid = call_stack.front()->function->id;
00318
00319 cout << "Aborting from usecode " << hex << setw(4)
00320 << setfill((char)0x30) << functionid << dec << setfill(' ')
00321 << endl;
00322 #endif
00323
00324
00325 while (call_stack.front() != 0)
00326 previous_stack_frame();
00327 }
00328
00329
00330
00331
00332
00333 void Usecode_internal::append_string
00334 (
00335 const char *str
00336 )
00337 {
00338 if (!str)
00339 return;
00340
00341 int len = String ? strlen(String) : 0;
00342 len += strlen(str);
00343 char *newstr = new char[len + 1];
00344 if (String)
00345 {
00346 strcpy(newstr, String);
00347 delete [] String;
00348 String = strcat(newstr, str);
00349 }
00350 else
00351 String = strcpy(newstr, str);
00352 }
00353
00354
00355 inline void Usecode_internal::push(Usecode_value& val)
00356 {
00357 *sp++ = val;
00358 }
00359
00360 inline Usecode_value Usecode_internal::pop()
00361 {
00362 if (sp <= stack)
00363 {
00364 cerr << "Stack underflow" << endl;
00365 return Usecode_value(0);
00366 }
00367 return *--sp;
00368 }
00369
00370 inline void Usecode_internal::pushref(Game_object *obj)
00371 {
00372 Usecode_value v(obj);
00373 push(v);
00374 }
00375
00376 inline void Usecode_internal::pushi(long val)
00377 {
00378 Usecode_value v(val);
00379 push(v);
00380 }
00381
00382 inline int Usecode_internal::popi()
00383 {
00384 Usecode_value val = pop();
00385 return val.need_int_value();
00386 }
00387
00388
00389 inline void Usecode_internal::pushs(char *s)
00390 {
00391 Usecode_value val(s);
00392 push(val);
00393 }
00394
00395
00396
00397
00398
00399
00400
00401
00402 Game_object *Usecode_internal::get_item
00403 (
00404 Usecode_value& itemref
00405 )
00406 {
00407
00408 Usecode_value& elemval = itemref.get_elem0();
00409
00410 if (elemval.is_ptr())
00411 return elemval.get_ptr_value();
00412
00413 long val = elemval.get_int_value();
00414 if (!val)
00415 return NULL;
00416 Game_object *obj = NULL;
00417 if (val == -356)
00418 return gwin->get_main_actor();
00419 if (val < 0 && val > -356)
00420 obj = gwin->get_npc(-val);
00421 else if (val >= 0 && val < gwin->get_num_npcs()) {
00422 obj = gwin->get_npc(val);
00423 CERR("Warning: interpreting positive integer as NPCnum");
00424
00425 } else if (val >= 0 && val < 0x400)
00426 {
00427 if (!itemref.is_array() &&
00428 caller_item && val == caller_item->get_shapenum())
00429 obj = caller_item;
00430 else
00431 return 0;
00432 }
00433 return obj;
00434 }
00435
00436
00437
00438
00439
00440 Actor *Usecode_internal::as_actor
00441 (
00442 Game_object *obj
00443 )
00444 {
00445 if (!obj)
00446 return 0;
00447 return (obj->as_actor());
00448 }
00449
00450
00451
00452
00453
00454 Tile_coord Usecode_internal::get_position
00455 (
00456 Usecode_value& itemval
00457 )
00458 {
00459 Game_object *obj;
00460 if ((itemval.get_array_size() == 1 || !itemval.get_array_size()) &&
00461 (obj = get_item(itemval)))
00462 return obj->get_outermost()->get_tile();
00463 else if (itemval.get_array_size() == 3)
00464
00465 return Tile_coord(itemval.get_elem(0).get_int_value(),
00466 itemval.get_elem(1).get_int_value(),
00467 itemval.get_elem(2).get_int_value());
00468 else if (itemval.get_array_size() == 4)
00469
00470
00471 return Tile_coord(itemval.get_elem(1).get_int_value(),
00472 itemval.get_elem(2).get_int_value(),
00473 itemval.get_elem(3).get_int_value());
00474 else
00475 return caller_item->get_tile();
00476 }
00477
00478
00479
00480
00481
00482 void Usecode_internal::show_pending_text
00483 (
00484 )
00485 {
00486 if (book)
00487 {
00488 int x, y;
00489 while (book->show_next_page() &&
00490 Get_click(x, y, Mouse::hand, 0, false, book))
00491 ;
00492 gwin->paint();
00493 }
00494
00495 else if (conv->is_npc_text_pending())
00496 click_to_continue();
00497 }
00498
00499
00500
00501
00502
00503 void Usecode_internal::show_book
00504 (
00505 )
00506 {
00507 char *str = String;
00508 book->add_text(str);
00509 delete [] String;
00510 String = 0;
00511 }
00512
00513
00514
00515
00516
00517 void Usecode_internal::say_string
00518 (
00519 )
00520 {
00521
00522 if (!String)
00523 return;
00524 if (book)
00525 {
00526 show_book();
00527 return;
00528 }
00529 show_pending_text();
00530 char *str = String;
00531 while (*str)
00532 {
00533 if (*str == '*')
00534 {
00535 click_to_continue();
00536 str++;
00537 continue;
00538 }
00539 char *eol = strchr(str, '~');
00540 if (!eol)
00541 {
00542 conv->show_npc_message(str);
00543 break;
00544 }
00545 *eol = 0;
00546 conv->show_npc_message(str);
00547 click_to_continue();
00548 str = eol + 1;
00549 if (*str == '~')
00550 str++;
00551 }
00552 delete [] String;
00553 String = 0;
00554 }
00555
00556
00557
00558
00559
00560 void Usecode_internal::stack_error
00561 (
00562 int under
00563 )
00564 {
00565 if (under)
00566 cerr << "Stack underflow." << endl;
00567 else
00568 cerr << "Stack overflow." << endl;
00569 exit(1);
00570 }
00571
00572
00573
00574
00575
00576 void Usecode_internal::show_npc_face
00577 (
00578 Usecode_value& arg1,
00579 Usecode_value& arg2,
00580 int slot
00581 )
00582 {
00583 show_pending_text();
00584 Actor *npc = as_actor(get_item(arg1));
00585 if (!npc)
00586 return;
00587 int shape = npc->get_face_shapenum();
00588 int frame = arg2.get_int_value();
00589 if (Game::get_game_type() == BLACK_GATE)
00590 {
00591 if (npc->get_npc_num() != -1)
00592 npc->set_flag (Obj_flags::met);
00593 }
00594 else if (Game::get_game_type() == SERPENT_ISLE)
00595 {
00596 if (npc->get_npc_num() == 296)
00597 shape = -1;
00598 }
00599 if (!conv->get_num_faces_on_screen())
00600 gwin->get_effects()->remove_text_effects();
00601
00602 if (gumpman->showing_gumps(true))
00603 {
00604 gumpman->close_all_gumps();
00605 gwin->set_all_dirty();
00606 init_conversation();
00607 }
00608 gwin->paint_dirty();
00609 conv->show_face(shape, frame, slot);
00610
00611
00612
00613 }
00614
00615
00616
00617
00618
00619 void Usecode_internal::remove_npc_face
00620 (
00621 Usecode_value& arg1
00622 )
00623 {
00624 show_pending_text();
00625 Actor *npc = as_actor(get_item(arg1));
00626 if (!npc)
00627 return;
00628 int shape = npc->get_face_shapenum();
00629 conv->remove_face(shape);
00630 }
00631
00632
00633
00634
00635
00636 void Usecode_internal::set_item_shape
00637 (
00638 Usecode_value& item_arg,
00639 Usecode_value& shape_arg
00640 )
00641 {
00642 int shape = shape_arg.get_int_value();
00643 Game_object *item = get_item(item_arg);
00644 if (!item)
00645 return;
00646
00647 int light_changed = item->get_info().is_light_source() !=
00648 ShapeID::get_info(shape).is_light_source();
00649 if (item->get_owner())
00650 {
00651 item->get_owner()->change_member_shape(item, shape);
00652 if (light_changed)
00653 gwin->paint();
00654 else
00655 {
00656 Gump *gump = gumpman->find_gump(item);
00657 if (gump)
00658 gump->paint();
00659 }
00660 return;
00661 }
00662
00663
00664 gwin->add_dirty(item);
00665
00666 Map_chunk *chunk = item->get_chunk();
00667 chunk->remove(item);
00668 item->set_shape(shape);
00669 chunk->add(item);
00670 gwin->add_dirty(item);
00671
00672
00673
00674 if (light_changed)
00675 gwin->paint();
00676
00677
00678
00679 }
00680
00681
00682
00683
00684
00685 void Usecode_internal::set_item_frame
00686 (
00687 Game_object *item,
00688 int frame,
00689 int check_empty,
00690 int set_rotated
00691 )
00692 {
00693 if (!item)
00694 return;
00695
00696 if (!set_rotated)
00697 frame = (item->get_framenum()&32)|(frame&31);
00698 if (frame == item->get_framenum())
00699 return;
00700
00701 ShapeID sid(item->get_shapenum(), frame, item->get_shapefile());
00702 Shape_frame *shape = sid.get_shape();
00703 if (!shape || (check_empty && shape->is_empty()))
00704 return;
00705
00706
00707
00708 if ((frame&0xf) < item->get_num_frames())
00709 {
00710 if (item->get_owner())
00711 {
00712 item->set_frame(frame);
00713 Gump *gump = gumpman->find_gump(item);
00714 if (gump)
00715 gwin->set_all_dirty();
00716 }
00717 else
00718 item->change_frame(frame);
00719 }
00720 gwin->set_painted();
00721 }
00722
00723
00724
00725
00726
00727 void Usecode_internal::add_dirty
00728 (
00729 Game_object *obj
00730 )
00731 {
00732 if (obj->get_owner())
00733 {
00734 Gump *gump = gumpman->find_gump(obj);
00735 if (gump)
00736 gwin->add_dirty(gump->get_shape_rect(obj));
00737 }
00738 else
00739 gwin->add_dirty(obj);
00740 }
00741
00742
00743
00744
00745
00746 void Usecode_internal::remove_item
00747 (
00748 Game_object *obj
00749 )
00750 {
00751 if (!obj)
00752 return;
00753 if (!last_created.empty() && obj == last_created.back())
00754 last_created.pop_back();
00755 add_dirty(obj);
00756 obj->remove_this();
00757 }
00758
00759
00760
00761
00762
00763 Usecode_value Usecode_internal::get_party
00764 (
00765 )
00766 {
00767 int cnt = partyman->get_count();
00768 Usecode_value arr(1 + cnt, 0);
00769
00770 Usecode_value aval(gwin->get_main_actor());
00771 arr.put_elem(0, aval);
00772 int num_added = 1;
00773 for (int i = 0; i < cnt; i++)
00774 {
00775 Game_object *obj = gwin->get_npc(partyman->get_member(i));
00776 if (!obj)
00777 continue;
00778 Usecode_value val(obj);
00779 arr.put_elem(num_added++, val);
00780 }
00781
00782 return arr;
00783 }
00784
00785
00786
00787
00788
00789 void Usecode_internal::item_say
00790 (
00791 Usecode_value& objval,
00792 Usecode_value& strval
00793 )
00794 {
00795 Game_object *obj = get_item(objval);
00796 const char *str = strval.get_str_value();
00797 if (obj && str && *str)
00798 {
00799 Effects_manager *eman = gwin->get_effects();
00800
00801 eman->remove_text_effect(obj);
00802 eman->add_text(str, obj);
00803 }
00804 }
00805
00806
00807
00808
00809
00810 void Usecode_internal::activate_cached
00811 (
00812 Tile_coord pos
00813 )
00814 {
00815 if (Game::get_game_type() != BLACK_GATE)
00816 return;
00817 const int dist = 16;
00818 Egg_vector vec;
00819 Game_object::find_nearby(vec, pos, 275, dist, 16, c_any_qual, 7);
00820 for (Egg_vector::const_iterator it = vec.begin(); it != vec.end();
00821 ++it)
00822 {
00823 Egg_object *egg = *it;
00824 if (egg->get_criteria() == Egg_object::cached_in)
00825 egg->activate();
00826 }
00827 }
00828
00829
00830
00831
00832 class Object_reverse_sorter
00833 {
00834 public:
00835 bool operator()(const Game_object *o1, const Game_object *o2)
00836 {
00837 Tile_coord t1 = o1->get_tile(),
00838 t2 = o2->get_tile();
00839 if (t1.ty > t2.ty)
00840 return true;
00841 else if (t1.ty == t2.ty)
00842 {
00843 if (t1.tx > t2.tx)
00844 return true;
00845 else
00846 return t1.tx == t2.tx && t1.tz > t2.tz;
00847 }
00848 else
00849 return false;
00850 }
00851 };
00852
00853
00854
00855
00856
00857 Usecode_value Usecode_internal::find_nearby
00858 (
00859 Usecode_value& objval,
00860 Usecode_value& shapeval,
00861
00862 Usecode_value& distval,
00863 Usecode_value& mval
00864
00865
00866
00867
00868 )
00869 {
00870 Game_object_vector vec;
00871
00872 int shapenum;
00873
00874 if (shapeval.is_array()) {
00875
00876 shapenum = shapeval.get_elem(0).get_int_value();
00877 if (shapeval.get_array_size() > 1)
00878 cerr << "Calling find_nearby with an array > 1 !!!!"
00879 << endl;
00880 } else
00881 shapenum = shapeval.get_int_value();
00882
00883
00884
00885 int arraysize = objval.get_array_size();
00886 if (arraysize == 4)
00887 {
00888 Game_object::find_nearby(vec,
00889 Tile_coord(objval.get_elem(1).get_int_value(),
00890 objval.get_elem(2).get_int_value(),
00891 objval.get_elem(3).get_int_value()),
00892 shapenum,
00893 distval.get_int_value(), mval.get_int_value());
00894 }
00895 else if (arraysize == 3 || arraysize == 5)
00896 {
00897
00898 int qual = arraysize == 5 ? objval.get_elem(3).get_int_value()
00899 : c_any_qual;
00900
00901 int frnum = arraysize == 5 ? objval.get_elem(4).get_int_value()
00902 : c_any_framenum;
00903 Game_object::find_nearby(vec,
00904 Tile_coord(objval.get_elem(0).get_int_value(),
00905 objval.get_elem(1).get_int_value(),
00906 objval.get_elem(2).get_int_value()),
00907 shapenum,
00908 distval.get_int_value(), mval.get_int_value(),
00909 qual, frnum);
00910 }
00911 else
00912 {
00913 Game_object *obj = get_item(objval);
00914 if (!obj)
00915 return Usecode_value(0, 0);
00916 obj = obj->get_outermost();
00917 obj->find_nearby(vec, shapenum,
00918 distval.get_int_value(), mval.get_int_value());
00919 }
00920 if (vec.size() > 1)
00921
00922 std::sort(vec.begin(), vec.end(), Object_reverse_sorter());
00923 Usecode_value nearby(vec.size(), 0);
00924 int i = 0;
00925 for (Game_object_vector::const_iterator it = vec.begin();
00926 it != vec.end(); ++it)
00927 {
00928 Game_object *each = *it;
00929 Usecode_value val(each);
00930 nearby.put_elem(i++, val);
00931 }
00932 return (nearby);
00933 }
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943 Barge_object *Get_barge
00944 (
00945 Game_object *obj
00946 )
00947 {
00948
00949 Barge_object *barge = obj->as_barge();
00950 if (barge)
00951 return barge;
00952 Game_object_vector vec;
00953 obj->find_nearby(vec, 961, 20, 0x10);
00954 if (vec.size() > 1)
00955 std::sort(vec.begin(), vec.end(), Object_reverse_sorter());
00956
00957 Tile_coord pos = obj->get_tile();
00958 Barge_object *best = 0;
00959 for (Game_object_vector::const_iterator it = vec.begin();
00960 it != vec.end(); it++)
00961 {
00962 barge = (*it)->as_barge();
00963 if (barge && barge->get_tile_footprint().has_point(
00964 pos.tx, pos.ty))
00965 {
00966 int lift = barge->get_lift();
00967 if (!best ||
00968
00969 (best->get_lift() > pos.tz && lift <= pos.tz) ||
00970
00971 (lift <= pos.tz && lift > best->get_lift()))
00972 best = barge;
00973 }
00974 }
00975 return best;
00976 }
00977
00978
00979
00980
00981
00982 Usecode_value Usecode_internal::find_nearest
00983 (
00984 Usecode_value& objval,
00985 Usecode_value& shapeval,
00986 Usecode_value& distval
00987 )
00988 {
00989 Game_object *obj = get_item(objval);
00990 if (!obj)
00991 return Usecode_value((Game_object*) NULL);
00992 Game_object_vector vec;
00993 obj = obj->get_outermost();
00994 int dist = distval.get_int_value();
00995 int shnum = shapeval.get_int_value();
00996
00997 if (frame->function->id == 0x70a && shnum == 0x9a && dist == 0)
00998 dist = 16;
00999 obj->find_nearby(vec, shnum, dist, 0);
01000 Game_object *closest = 0;
01001 uint32 bestdist = 100000;
01002 Tile_coord t1 = obj->get_tile();
01003 for (Game_object_vector::const_iterator it = vec.begin();
01004 it != vec.end(); ++it)
01005 {
01006 Game_object *each = *it;
01007 Tile_coord t2 = each->get_tile();
01008 int dx = t1.tx - t2.tx, dy = t1.ty - t2.ty, dz = t1.tz - t2.tz;
01009 uint32 dist = dx*dx + dy*dy + dz*dz;
01010 if (dist < bestdist)
01011 {
01012 bestdist = dist;
01013 closest = each;
01014 }
01015 }
01016 return Usecode_value(closest);
01017 }
01018
01019
01020
01021
01022
01023 Usecode_value Usecode_internal::find_direction
01024 (
01025 Usecode_value& from,
01026 Usecode_value& to
01027 )
01028 {
01029 unsigned angle;
01030 Tile_coord t1 = get_position(from);
01031 Tile_coord t2 = get_position(to);
01032
01033 angle = (int) Get_direction(t1.ty - t2.ty, t2.tx - t1.tx);
01034 return Usecode_value(angle);
01035 }
01036
01037
01038
01039
01040
01041 Usecode_value Usecode_internal::count_objects
01042 (
01043 Usecode_value& objval,
01044 Usecode_value& shapeval,
01045 Usecode_value& qualval,
01046 Usecode_value& frameval
01047 )
01048 {
01049 long oval = objval.get_int_value();
01050 int shapenum = shapeval.get_int_value();
01051 int qualnum = qualval.get_int_value();
01052 int framenum = frameval.get_int_value();
01053 if (oval != -357)
01054 {
01055 Game_object *obj = get_item(objval);
01056 return (!obj ? 0 : obj->count_objects(
01057 shapenum, qualnum, framenum));
01058 }
01059
01060 Usecode_value party = get_party();
01061 int cnt = party.get_array_size();
01062 int total = 0;
01063 for (int i = 0; i < cnt; i++)
01064 {
01065 Game_object *obj = get_item(party.get_elem(i));
01066 if (obj)
01067 total += obj->count_objects(shapenum, qualnum,
01068 framenum);
01069 }
01070 return (total);
01071 }
01072
01073
01074
01075
01076
01077 Usecode_value Usecode_internal::get_objects
01078 (
01079 Usecode_value& objval,
01080 Usecode_value& shapeval,
01081 Usecode_value& qualval,
01082 Usecode_value& frameval
01083 )
01084 {
01085 Game_object *obj = get_item(objval);
01086 if (!obj)
01087 return Usecode_value((Game_object*) NULL);
01088 int shapenum = shapeval.get_int_value();
01089 int framenum = frameval.get_int_value();
01090 int qual = qualval.get_int_value();
01091 Game_object_vector vec;
01092 obj->get_objects(vec, shapenum, qual, framenum);
01093
01094
01095 Usecode_value within(vec.size(), 0);
01096 int i = 0;
01097 for (Game_object_vector::const_iterator it = vec.begin(); it != vec.end(); ++it)
01098 {
01099 Game_object *each = *it;
01100 Usecode_value val(each);
01101 within.put_elem(i++, val);
01102 }
01103 return (within);
01104 }
01105
01106
01107
01108
01109
01110
01111
01112 Usecode_value Usecode_internal::remove_party_items
01113 (
01114 Usecode_value& quantval,
01115 Usecode_value& shapeval,
01116 Usecode_value& qualval,
01117 Usecode_value& frameval,
01118 Usecode_value& flagval
01119 )
01120 {
01121 int quantity = quantval.need_int_value();
01122 int shapenum = shapeval.get_int_value();
01123 int framenum = frameval.get_int_value();
01124 int quality = qualval.get_int_value();
01125 Usecode_value party = get_party();
01126 int cnt = party.get_array_size();
01127 if (quantity == -359 && Game::get_game_type() == SERPENT_ISLE)
01128 {
01129 Game_object *obj = 0;
01130 for (int i = 0; i < cnt && !obj; i++)
01131 {
01132 Game_object *actor = get_item(party.get_elem(i));
01133 if (actor)
01134 obj = actor->find_item(shapenum, quality,
01135 framenum);
01136 }
01137 if (!obj)
01138 return Usecode_value(0);
01139
01140
01141
01142
01143
01144
01145 temp_to_be_deleted = obj;
01146 obj->remove_this(1);
01147 return Usecode_value(obj);
01148 }
01149 Usecode_value all(-357);
01150 Usecode_value avail = count_objects(all, shapeval, qualval, frameval);
01151 if (avail.get_int_value() < quantity)
01152 return Usecode_value(0);
01153
01154 for (int i = 0; i < cnt && quantity > 0; i++)
01155 {
01156 Game_object *obj = get_item(party.get_elem(i));
01157 if (obj)
01158 quantity = obj->remove_quantity(quantity, shapenum,
01159 quality, framenum);
01160 }
01161 return Usecode_value(quantity == 0);
01162 }
01163
01164
01165
01166
01167
01168
01169
01170 Usecode_value Usecode_internal::add_party_items
01171 (
01172 Usecode_value& quantval,
01173 Usecode_value& shapeval,
01174 Usecode_value& qualval,
01175 Usecode_value& frameval,
01176 Usecode_value& flagval
01177 )
01178 {
01179 int quantity = quantval.get_int_value();
01180
01181 int shapenum = shapeval.get_int_value();
01182 int framenum = frameval.get_int_value();
01183 unsigned int quality = (unsigned int) qualval.get_int_value();
01184
01185 Usecode_value party = get_party();
01186 int cnt = party.get_array_size();
01187 Usecode_value result(0, 0);
01188 for (int i = 0; i < cnt && quantity > 0; i++)
01189 {
01190 Game_object *obj = get_item(party.get_elem(i));
01191 if (!obj)
01192 continue;
01193 int prev = quantity;
01194 quantity = obj->add_quantity(quantity, shapenum,
01195 quality, framenum);
01196 if (quantity < prev)
01197 result.concat(party.get_elem(i));
01198 }
01199 if (GAME_BG)
01200 return result;
01201 int todo = quantity;
01202 if (framenum == c_any_framenum)
01203 framenum = 0;
01204 while (todo > 0)
01205 {
01206 Tile_coord pos = Map_chunk::find_spot(
01207 gwin->get_main_actor()->get_tile(), 3,
01208 shapenum, framenum, 2);
01209 if (pos.tx == -1)
01210 break;
01211 Shape_info& info = ShapeID::get_info(shapenum);
01212
01213 Game_object *newobj = gmap->create_ireg_object(
01214 info, shapenum, framenum, 0, 0, 0);
01215 if (quality != c_any_qual)
01216 newobj->set_quality(quality);
01217 newobj->set_flag(Obj_flags::okay_to_take);
01218 newobj->move(pos);
01219 todo--;
01220 if (todo > 0)
01221 todo = newobj->modify_quantity(todo);
01222 }
01223
01224 Usecode_value ground(quantity - todo);
01225 result.concat(ground);
01226 return result;
01227 }
01228
01229
01230
01231
01232
01233
01234
01235 Usecode_value Usecode_internal::add_cont_items
01236 (
01237 Usecode_value& container,
01238 Usecode_value& quantval,
01239 Usecode_value& shapeval,
01240 Usecode_value& qualval,
01241 Usecode_value& frameval,
01242 Usecode_value& flagval
01243 )
01244 {
01245 int quantity = quantval.get_int_value();
01246 int shapenum = shapeval.get_int_value();
01247 int framenum = frameval.get_int_value();
01248 unsigned int quality = (unsigned int) qualval.get_int_value();
01249
01250 Game_object *obj = get_item(container);
01251 if (obj) return Usecode_value (obj->add_quantity(quantity, shapenum, quality, framenum));
01252 return Usecode_value(0);
01253 }
01254
01255
01256
01257
01258
01259
01260
01261 Usecode_value Usecode_internal::remove_cont_items
01262 (
01263 Usecode_value& container,
01264 Usecode_value& quantval,
01265 Usecode_value& shapeval,
01266 Usecode_value& qualval,
01267 Usecode_value& frameval,
01268 Usecode_value& flagval
01269 )
01270 {
01271 int quantity = quantval.get_int_value();
01272 int shapenum = shapeval.get_int_value();
01273 int framenum = frameval.get_int_value();
01274 unsigned int quality = (unsigned int) qualval.get_int_value();
01275
01276 Game_object *obj = get_item(container);
01277 if (obj) return Usecode_value (quantity - obj->remove_quantity(quantity, shapenum, quality, framenum));
01278 return Usecode_value(0);
01279 }
01280
01281
01282
01283
01284
01285
01286
01287
01288 int Usecode_internal::path_run_usecode
01289 (
01290 Usecode_value& npcval,
01291 Usecode_value& locval,
01292 Usecode_value& useval,
01293 Usecode_value& itemval,
01294 Usecode_value& eventval,
01295 int find_free,
01296 int always
01297 )
01298 {
01299 Actor *npc = as_actor(get_item(npcval));
01300 if (!npc)
01301 return 0;
01302 path_npc = npc;
01303 int usefun = useval.get_elem0().get_int_value();
01304 Game_object *obj = get_item(itemval);
01305 int sz = locval.get_array_size();
01306 if (!npc || sz < 2)
01307 {
01308 CERR("Path_run_usecode: bad inputs");
01309 return 0;
01310 }
01311 Tile_coord src = npc->get_tile();
01312 Tile_coord dest(locval.get_elem(0).get_int_value(),
01313 locval.get_elem(1).get_int_value(),
01314 sz == 3 ? locval.get_elem(2).get_int_value() : 0);
01315 if (dest.tz < 0)
01316 dest.tz = 0;
01317 if (find_free)
01318 {
01319
01320
01321 Tile_coord d = Map_chunk::find_spot(dest, 3, npc, 3);
01322 if (d.tx == -1)
01323 d = Map_chunk::find_spot(
01324 Tile_coord(dest.tx, dest.ty, src.tz), 3, npc,
01325 0);
01326 if (d.tx != -1)
01327 dest = d;
01328 if (usefun == 0x60a &&
01329 src.distance(dest) <= 1)
01330 return 1;
01331 }
01332 if (!obj)
01333 return npc->walk_path_to_tile(dest, gwin->get_std_delay(), 0);
01334
01335 If_else_path_actor_action *action =
01336 new If_else_path_actor_action(npc, dest,
01337 new Usecode_actor_action(usefun, obj,
01338 eventval.get_int_value()));
01339 if (always)
01340 action->set_failure(
01341 new Usecode_actor_action(usefun, obj,
01342 eventval.get_int_value()));
01343 npc->set_action(action);
01344 npc->start(gwin->get_std_delay(), 0);
01345 return !action->done_and_failed();
01346 }
01347
01348
01349
01350
01351
01352 void Usecode_internal::create_script
01353 (
01354 Usecode_value& objval,
01355 Usecode_value& codeval,
01356 long delay
01357 )
01358 {
01359 Game_object *obj = get_item(objval);
01360
01361 if (objval.get_array_size() == 2 &&
01362 Game::get_game_type() == SERPENT_ISLE &&
01363 obj && obj->get_shapenum() == 470 && obj->get_lift() == 0)
01364 {
01365 Usecode_value v2 = objval.get_elem(1);
01366 Game_object *o2 = get_item(v2);
01367 if (o2->get_shapenum() == obj->get_shapenum() &&
01368 o2->get_lift() == 2)
01369 {
01370 objval = v2;
01371 obj = o2;
01372 }
01373 }
01374 if (!obj)
01375 {
01376 cerr << "Can't create script for NULL object" << endl;
01377 return;
01378 }
01379
01380
01381 Usecode_value *code = new Usecode_value(codeval);
01382 Usecode_script *script = new Usecode_script(obj, code);
01383 script->start(delay);
01384 }
01385
01386
01387
01388
01389
01390 static void Usecode_Trace
01391 (
01392 const char *name,
01393 int intrinsic,
01394 int num_parms,
01395 Usecode_value parms[12]
01396 )
01397 {
01398 cout << hex << " [0x" << setfill((char)0x30) << setw(2)
01399 << intrinsic << "]: " << name << "(";
01400 for (int i = 0; i < num_parms; i++)
01401 {
01402 parms[i].print(cout);
01403 if(i!=num_parms-1)
01404 cout << ", ";
01405 }
01406 cout <<") = ";
01407 cout << dec;
01408 }
01409
01410 static void Usecode_TraceReturn(Usecode_value &v)
01411 {
01412 v.print(cout);
01413 cout << dec << endl;
01414 }
01415
01416 #if 0
01417 static void Unhandled
01418 (
01419 int intrinsic,
01420 int num_parms,
01421 Usecode_value parms[12]
01422 )
01423 {
01424 Usecode_Trace("UNKNOWN",intrinsic,num_parms,parms);
01425 }
01426 #endif
01427
01428 Usecode_value no_ret;
01429
01430 Usecode_value Usecode_internal::Execute_Intrinsic(UsecodeIntrinsicFn func,const char *name,int event,int intrinsic,int num_parms,Usecode_value parms[12])
01431 {
01432 #ifdef XWIN
01433 #if 0 && USECODE_DEBUGGER
01434 if(usecode_debugging)
01435 {
01436
01437 if(std::find(intrinsic_breakpoints.begin(),intrinsic_breakpoints.end(),intrinsic)!=intrinsic_breakpoints.end())
01438 {
01439 raise(SIGIO);
01440 }
01441 }
01442 #endif
01443 #endif
01444 #ifdef DEBUG
01445 if(intrinsic_trace)
01446 {
01447 Usecode_Trace(name,intrinsic,num_parms,parms);
01448 cout.flush();
01449 Usecode_value u=((*this).*func)(event,intrinsic,num_parms,parms);
01450 Usecode_TraceReturn(u);
01451 return (u);
01452 }
01453 else
01454 #endif
01455 return ((*this).*func)(event,intrinsic,num_parms,parms);
01456 }
01457
01458
01459 typedef Usecode_value (Usecode_internal::*UsecodeIntrinsicFn)(int event,int intrinsic,int num_parms,Usecode_value parms[12]);
01460
01461
01462 #ifndef __STRING
01463 #if defined __STDC__ && __STDC__
01464 #define __STRING(x) #x
01465 #else
01466 #define __STRING(x) "x"
01467 #endif
01468 #endif
01469
01470 #define USECODE_INTRINSIC_PTR(NAME) { &Usecode_internal::UI_ ## NAME, __STRING(NAME) }
01471
01472 struct Usecode_internal::IntrinsicTableEntry
01473 Usecode_internal::intrinsic_table[]=
01474 {
01475 #include "bgintrinsics.h"
01476 };
01477
01478
01479
01480 struct Usecode_internal::IntrinsicTableEntry
01481 Usecode_internal::serpent_table[]=
01482 {
01483 #include "siintrinsics.h"
01484 };
01485
01486
01487 int max_bundled_intrinsics=0xff;
01488
01489
01490
01491
01492 Usecode_value Usecode_internal::call_intrinsic
01493 (
01494 int event,
01495 int intrinsic,
01496 int num_parms
01497 )
01498 {
01499 Usecode_value parms[12];
01500 for (int i = 0; i < num_parms; i++)
01501 {
01502 Usecode_value val = pop();
01503 parms[i] = val;
01504 }
01505 if (intrinsic<=max_bundled_intrinsics)
01506 {
01507 struct Usecode_internal::IntrinsicTableEntry *table_entry;
01508
01509 if (Game::get_game_type() == SERPENT_ISLE)
01510 table_entry = serpent_table+intrinsic;
01511 else
01512 table_entry = intrinsic_table+intrinsic;
01513 UsecodeIntrinsicFn func=(*table_entry).func;
01514 const char *name=(*table_entry).name;
01515 return Execute_Intrinsic(func,name,event,intrinsic,
01516 num_parms,parms);
01517 }
01518 return(no_ret);
01519 }
01520
01521
01522
01523
01524
01525 void Usecode_internal::click_to_continue
01526 (
01527 )
01528 {
01529 int xx, yy;
01530 char c;
01531 if (!gwin->get_pal()->is_faded_out())
01532 {
01533 gwin->paint();
01534 Get_click(xx, yy, Mouse::hand, &c, false, conv);
01535 }
01536 conv->clear_text_pending();
01537
01538 }
01539
01540
01541
01542
01543
01544 void Usecode_internal::set_book
01545 (
01546 Text_gump *b
01547 )
01548 {
01549 delete book;
01550 book = b;
01551 }
01552
01553
01554
01555
01556
01557
01558
01559
01560 const char *Usecode_internal::get_user_choice
01561 (
01562 )
01563 {
01564 if (!conv->get_num_answers())
01565 return (0);
01566
01567
01568
01569
01570 get_user_choice_num();
01571 return (user_choice);
01572 }
01573
01574
01575
01576
01577
01578
01579
01580
01581 int Usecode_internal::get_user_choice_num
01582 (
01583 )
01584 {
01585 user_choice = 0;
01586 conv->show_avatar_choices();
01587 int x, y;
01588 int choice_num;
01589 do
01590 {
01591 char chr;
01592 gwin->paint();
01593 int result=Get_click(x, y, Mouse::hand, &chr, false, conv);
01594 if (result<=0) {
01595 choice_num = conv->locate_answer("bye");
01596 } else if (chr) {
01597 if (chr>='1' && chr <='0'+conv->get_num_answers()) {
01598 choice_num = chr - '1';
01599 } else
01600 choice_num = -1;
01601 } else
01602 choice_num = conv->conversation_choice(x, y);
01603 }
01604
01605 while (choice_num < 0 || choice_num >= conv->get_num_answers());
01606
01607 conv->clear_avatar_choices();
01608
01609 user_choice = conv->get_answer(choice_num);
01610 return (choice_num);
01611 }
01612
01613
01614
01615
01616
01617 Usecode_machine *Usecode_machine::create
01618 (
01619 )
01620 {
01621 return new Usecode_internal();
01622 }
01623
01624
01625
01626
01627
01628 Usecode_internal::Usecode_internal
01629 (
01630 ) : Usecode_machine(),
01631 book(0), caller_item(0),
01632 path_npc(0), user_choice(0),
01633 saved_pos(-1, -1, -1),
01634 String(0), stack(new Usecode_value[1024]), intercept_item(0),
01635 temp_to_be_deleted(0), telekenesis_fun(-1),
01636 modified_map(false)
01637 #ifdef USECODE_DEBUGGER
01638 , on_breakpoint(false)
01639 #endif
01640 {
01641
01642 memset((char *) &timers[0], 0, sizeof(timers));
01643 sp = stack;
01644 ifstream file;
01645 try
01646 {
01647 U7open(file, USECODE);
01648 read_usecode(file);
01649 file.close();
01650 }
01651 catch(const file_exception & f)
01652 {
01653 if (!Game::is_editing())
01654 throw f;
01655 std::cerr << "Warning (map-editing): Couldn't open '" <<
01656 USECODE << "'" << endl;
01657 }
01658
01659
01660 if (is_system_path_defined("<PATCH>") && U7exists(PATCH_USECODE))
01661 {
01662 U7open(file, PATCH_USECODE);
01663 read_usecode(file, true);
01664 file.close();
01665 }
01666
01667
01668 }
01669
01670
01671
01672
01673
01674
01675 void Usecode_internal::read_usecode
01676 (
01677 istream &file,
01678 bool patch
01679 )
01680 {
01681 file.seekg(0, ios::end);
01682 int size = file.tellg();
01683 file.seekg(0);
01684
01685 while (file.tellg() < size)
01686 {
01687 Usecode_function *fun = new Usecode_function(file);
01688 Exult_vector<Usecode_function *> & vec = funs[fun->id/0x100];
01689 int i = fun->id%0x100;
01690 if (i < vec.size() && vec[i])
01691 {
01692 if (patch)
01693 {
01694 if (vec[i]->orig)
01695 {
01696 fun->orig = vec[i]->orig;
01697 delete vec[i];
01698 }
01699 else
01700 fun->orig = vec[i];
01701 }
01702 else
01703 {
01704 delete vec[i]->orig;
01705 delete vec[i];
01706 }
01707 }
01708 vec.put(i, fun);
01709 }
01710 }
01711
01712
01713
01714
01715
01716 Usecode_internal::~Usecode_internal
01717 (
01718 )
01719 {
01720 delete [] stack;
01721 delete [] String;
01722 int num_slots = sizeof(funs)/sizeof(funs[0]);
01723 for (int i = 0; i < num_slots; i++)
01724 {
01725 vector<Usecode_function*>& slot = funs[i];
01726 int cnt = slot.size();
01727 for (int j = 0; j < cnt; j++)
01728 delete slot[j];
01729 }
01730 delete book;
01731 }
01732
01733 #ifdef DEBUG
01734 int debug = 2;
01735 static int ucbp_fun = -1, ucbp_ip = -1;
01736 void Setbreak(int fun, int ip)
01737 { ucbp_fun = fun; ucbp_ip = ip; }
01738 void Clearbreak()
01739 { ucbp_fun = ucbp_ip = -1; }
01740 #endif
01741
01742
01743 #define CERR_CURRENT_IP()\
01744 cerr << " (at function = " << hex << setw(4) << setfill('0')\
01745 << frame->function->id << ", ip = " \
01746 << current_IP << dec << setfill(' ') << ")" << endl
01747
01748 #define LOCAL_VAR_ERROR(x)\
01749 cerr << "Local variable #" << (x) << " out of range!";\
01750 CERR_CURRENT_IP()
01751
01752 #define DATA_SEGMENT_ERROR()\
01753 cerr << "Data pointer out of range!";\
01754 CERR_CURRENT_IP()
01755
01756 #define EXTERN_ERROR()\
01757 cerr << "Extern offset out of range!";\
01758 CERR_CURRENT_IP()
01759
01760 #define FLAG_ERROR(x)\
01761 cerr << "Global flag #" << (x) << " out of range!";\
01762 CERR_CURRENT_IP()
01763
01764
01765
01766
01767
01768
01769
01770 int Usecode_internal::run()
01771 {
01772 bool aborted = false;
01773 bool initializing_loop = false;
01774
01775 while (frame = call_stack.front())
01776 {
01777 int num_locals = frame->num_vars + frame->num_args;
01778 int offset;
01779 int sval;
01780
01781 bool frame_changed = false;
01782
01783
01784 caller_item = frame->caller_item;
01785
01786
01787
01788
01789 while (!frame_changed)
01790 {
01791
01792
01793 if ((frame->ip >= frame->endp) ||
01794 (frame->ip < frame->code))
01795 {
01796 cerr << "Usecode: jumped outside of code segment of "
01797 << "function " << hex << setw(4) << setfill('0')
01798 << frame->function->id << dec << setfill(' ')
01799 << " ! Aborting." << endl;
01800
01801 abort_function();
01802 frame_changed = true;
01803 continue;
01804 }
01805
01806 int current_IP = frame->ip - frame->code;
01807
01808 int opcode = *(frame->ip);
01809
01810 if (frame->ip + get_opcode_length(opcode) > frame->endp) {
01811 cerr << "Operands lie outside of code segment. ";
01812 CERR_CURRENT_IP();
01813 continue;
01814 }
01815
01816
01817 #ifdef DEBUG
01818 if (usecode_trace == 2) {
01819 uc_trace_disasm(frame);
01820 }
01821 #endif
01822
01823 #ifdef USECODE_DEBUGGER
01824
01825
01826 int bp = breakpoints.check(frame);
01827 if (bp != -1)
01828 {
01829
01830
01831
01832 on_breakpoint = true;
01833
01834 cout << "On breakpoint" << endl;
01835
01836
01837 unsigned char c=(unsigned char)Exult_server::dbg_on_breakpoint;
01838 if (client_socket >= 0)
01839 Exult_server::Send_data(client_socket,
01840 Exult_server::usecode_debugging,
01841 &c, 1);
01842
01843 #ifdef XWIN
01844 raise(SIGUSR1);
01845 #endif
01846
01847
01848 #if 0
01849
01850 bool done = false;
01851 while (!done) {
01852 char userinput;
01853 cout << "s=step into, o=step over, f=finish, c=continue, "
01854 << "b=stacktrace: ";
01855 cin >> userinput;
01856
01857 if (userinput == 's') {
01858 breakpoints.add(new AnywhereBreakpoint());
01859 cout << "Stepping into..." << endl;
01860 done = true;
01861 } else if (userinput == 'o') {
01862 breakpoints.add(new StepoverBreakpoint(frame));
01863 cout << "Stepping over..." << endl;
01864 done = true;
01865 } else if (userinput == 'f') {
01866 breakpoints.add(new FinishBreakpoint(frame));
01867 cout << "Finishing function..." << endl;
01868 done = true;
01869 } else if (userinput == 'c') {
01870 done = true;
01871 } else if (userinput == 'b') {
01872 stack_trace(cout);
01873 }
01874 }
01875 #elif (defined(USE_EXULTSTUDIO))
01876 breakpoint_action = -1;
01877 while (breakpoint_action == -1) {
01878 SDL_Delay(20);
01879 Server_delay(Handle_client_debug_message);
01880 }
01881 #endif
01882
01883
01884 c = (unsigned char)Exult_server::dbg_continuing;
01885 if (client_socket >= 0)
01886 Exult_server::Send_data(client_socket,
01887 Exult_server::usecode_debugging,
01888 &c, 1);
01889
01890 on_breakpoint = false;
01891 }
01892
01893 #endif
01894
01895
01896 frame->ip++;
01897
01898 switch (opcode)
01899 {
01900 case 0x04:
01901 case 0x84:
01902 {
01903 if (opcode < 0x80)
01904 offset = (short) Read2(frame->ip);
01905 else
01906 offset = (sint32) Read4(frame->ip);
01907
01908 found_answer = false;
01909 if (!get_user_choice())
01910 frame->ip += offset;
01911 break;
01912 }
01913 case 0x05:
01914 {
01915 offset = (short) Read2(frame->ip);
01916 Usecode_value val = pop();
01917 if (val.is_false())
01918 frame->ip += offset;
01919 break;
01920 }
01921 case 0x85:
01922 {
01923 offset = (sint32) Read4(frame->ip);
01924 Usecode_value val = pop();
01925 if (val.is_false())
01926 frame->ip += offset;
01927 break;
01928 }
01929 case 0x06:
01930 offset = (short) Read2(frame->ip);
01931 frame->ip += offset;
01932 break;
01933 case 0x86:
01934 offset = (sint32) Read4(frame->ip);
01935 frame->ip += offset;
01936 break;
01937 case 0x07:
01938 case 0x87:
01939 {
01940 int cnt = Read2(frame->ip);
01941 if (opcode < 0x80)
01942 offset = (short) Read2(frame->ip);
01943 else
01944 offset = (sint32) Read4(frame->ip);
01945
01946 bool matched = false;
01947
01948
01949 while (!matched && !found_answer && cnt-- > 0) {
01950 Usecode_value s = pop();
01951 const char *str = s.get_str_value();
01952 if (str && strcmp(str, user_choice) == 0) {
01953 matched = true;
01954 found_answer = true;
01955 }
01956 }
01957 while (cnt-- > 0)
01958 pop();
01959 if (!matched)
01960 frame->ip += offset;
01961 }
01962 break;
01963 case 0x09:
01964 {
01965 Usecode_value v2 = pop();
01966 Usecode_value v1 = pop();
01967 Usecode_value sum = v1 + v2;
01968 push(sum);
01969 break;
01970 }
01971 case 0x0a:
01972 sval = popi();
01973 pushi(popi() - sval);
01974 break;
01975 case 0x0b:
01976 sval = popi();
01977 pushi(popi()/sval);
01978 break;
01979 case 0x0c:
01980 pushi(popi()*popi());
01981 break;
01982 case 0x0d:
01983 sval = popi();
01984 pushi(popi() % sval);
01985 break;
01986 case 0x0e:
01987 {
01988 Usecode_value v1 = pop();
01989 Usecode_value v2 = pop();
01990 int result = v1.is_true() && v2.is_true();
01991 pushi(result);
01992 break;
01993 }
01994 case 0x0f:
01995 {
01996 Usecode_value v1 = pop();
01997 Usecode_value v2 = pop();
01998 int result = v1.is_true() || v2.is_true();
01999 pushi(result);
02000 break;
02001 }
02002 case 0x10:
02003 pushi(!pop().is_true());
02004 break;
02005 case 0x12:
02006 {
02007 offset = Read2(frame->ip);
02008
02009 Usecode_value val = pop();
02010 if (offset < 0 || offset >= num_locals) {
02011 LOCAL_VAR_ERROR(offset);
02012 } else {
02013 frame->locals[offset] = val;
02014 }
02015 }
02016 break;
02017 case 0x13:
02018 pushi(1);
02019 break;
02020 case 0x14:
02021 pushi(0);
02022 break;
02023 case 0x16:
02024 sval = popi();
02025 pushi(popi() > sval);
02026 break;
02027 case 0x17:
02028 sval = popi();
02029 pushi(popi() < sval);
02030 break;
02031 case 0x18:
02032 sval = popi();
02033 pushi(popi() >= sval);
02034 break;
02035 case 0x19:
02036 sval = popi();
02037 pushi(popi() <= sval);
02038 break;
02039 case 0x1a:
02040 {
02041 Usecode_value val1 = pop();
02042 Usecode_value val2 = pop();
02043 pushi(!(val1 == val2));
02044 break;
02045 }
02046 case 0x1c:
02047 offset = Read2(frame->ip);
02048 if (offset < 0 || frame->data + offset >= frame->externs-6) {
02049 DATA_SEGMENT_ERROR();
02050 break;
02051 }
02052 append_string((char*)(frame->data + offset));
02053 break;
02054 case 0x9c:
02055 offset = (sint32)Read4(frame->ip);
02056 if (offset < 0 || frame->data + offset >= frame->externs-6) {
02057 DATA_SEGMENT_ERROR();
02058 break;
02059 }
02060 append_string((char*)(frame->data + offset));
02061 break;
02062 case 0x1d:
02063 offset = Read2(frame->ip);
02064 if (offset < 0 || frame->data + offset >= frame->externs-6) {
02065 DATA_SEGMENT_ERROR();
02066 break;
02067 }
02068 pushs((char*)(frame->data + offset));
02069 break;
02070 case 0x9d:
02071 offset = (sint32)Read4(frame->ip);
02072 if (offset < 0 || frame->data + offset >= frame->externs-6) {
02073 DATA_SEGMENT_ERROR();
02074 break;
02075 }
02076 pushs((char*)(frame->data + offset));
02077 break;
02078 case 0x1e:
02079 {
02080 int num = Read2(frame->ip);
02081 int cnt = num;
02082 Usecode_value arr(num, 0);
02083 int to = 0;
02084 while (cnt--)
02085 {
02086 Usecode_value val = pop();
02087 to += arr.add_values(to, val);
02088 }
02089 if (to < num)
02090 arr.resize(to);
02091 push(arr);
02092 }
02093 break;
02094 case 0x1f:
02095 {
02096 short ival = Read2(frame->ip);
02097 pushi(ival);
02098 break;
02099 }
02100 case 0x9f:
02101 {
02102 int ival = (sint32)Read4(frame->ip);
02103 pushi(ival);
02104 break;
02105 }
02106 case 0x21:
02107 offset = Read2(frame->ip);
02108 if (offset < 0 || offset >= num_locals) {
02109 LOCAL_VAR_ERROR(offset);
02110 pushi(0);
02111 }
02112 else {
02113 push(frame->locals[offset]);
02114 }
02115 break;
02116 case 0x22:
02117 {
02118 Usecode_value val1 = pop();
02119 Usecode_value val2 = pop();
02120 pushi(val1 == val2);
02121 break;
02122 }
02123 case 0x24:
02124 {
02125 offset = Read2(frame->ip);
02126 if (offset < 0 || offset >= frame->num_externs) {
02127 EXTERN_ERROR();
02128 break;
02129 }
02130
02131 uint8 *tempptr = frame->externs + 2*offset;
02132 int funcid = Read2(tempptr);
02133
02134 call_function(funcid, frame->eventid);
02135 frame_changed = true;
02136 break;
02137 }
02138 case 0x25:
02139 case 0x2C:
02140 show_pending_text();
02141
02142 return_from_procedure();
02143 frame_changed = true;
02144 break;
02145 case 0x26:
02146 {
02147 sval = popi();
02148 sval--;
02149
02150 offset = Read2(frame->ip);
02151 if (offset < 0 || offset >= num_locals) {
02152 LOCAL_VAR_ERROR(offset);
02153 pushi(0);
02154 break;
02155 }
02156 if (sval < 0) {
02157 cerr << "AIDX: Negative array index: " << sval << endl;
02158 pushi(0);
02159 break;
02160 }
02161 Usecode_value& val = frame->locals[offset];
02162
02163 if (val.is_array()) {
02164 push(val.get_elem(sval));
02165 } else if (sval == 0) {
02166 push(val);
02167 } else {
02168 pushi(0);
02169 }
02170 break;
02171 }
02172 case 0x2d:
02173 {
02174 Usecode_value r = pop();
02175
02176 return_from_function(r);
02177 frame_changed = true;
02178 break;
02179 }
02180 case 0x2e:
02181 case 0xae:
02182 {
02183 int nextopcode = *(frame->ip);
02184 if ((opcode == 0x2e && nextopcode != 0x02) ||
02185 (opcode == 0xae && nextopcode != 0x82)) {
02186 cerr << "2nd byte in loop isn't a 0x02 (or 0x82)!"<<endl;
02187 break;
02188 } else {
02189 initializing_loop = true;
02190 }
02191 break;
02192 }
02193 case 0x02:
02194 case 0x82:
02195 {
02196
02197 int local1 = Read2(frame->ip);
02198
02199 int local2 = Read2(frame->ip);
02200
02201 int local3 = Read2(frame->ip);
02202
02203 int local4 = Read2(frame->ip);
02204
02205 if (opcode < 0x80)
02206 offset = (short) Read2(frame->ip);
02207 else
02208 offset = (sint32) Read4(frame->ip);
02209
02210 if (local1 < 0 || local1 >= num_locals) {
02211 LOCAL_VAR_ERROR(local1);
02212 break;
02213 }
02214 if (local2 < 0 || local2 >= num_locals) {
02215 LOCAL_VAR_ERROR(local1);
02216 break;
02217 }
02218 if (local3 < 0 || local3 >= num_locals) {
02219 LOCAL_VAR_ERROR(local1);
02220 break;
02221 }
02222 if (local4 < 0 || local4 >= num_locals) {
02223 LOCAL_VAR_ERROR(local1);
02224 break;
02225 }
02226
02227
02228 Usecode_value& arr = frame->locals[local4];
02229
02230 int next = frame->locals[local1].get_int_value();
02231
02232 if (initializing_loop)
02233 {
02234 initializing_loop = false;
02235 int cnt = arr.is_array() ?
02236 arr.get_array_size() : 1;
02237 frame->locals[local2] = Usecode_value(cnt);
02238 frame->locals[local1] = Usecode_value(0);
02239
02240 next = 0;
02241 }
02242 else if (GAME_SI)
02243 {
02244
02245
02246
02247
02248
02249
02250 int cnt = arr.is_array() ? arr.get_array_size() : 1;
02251
02252 if (cnt != frame->locals[local2].get_int_value()) {
02253
02254
02255 frame->locals[local2] = Usecode_value(cnt);
02256
02257 if (std::abs(cnt-frame->locals[local2].get_int_value())==1)
02258 {
02259
02260 Usecode_value& curval = arr.is_array() ?
02261 arr.get_elem(next - 1) : arr;
02262
02263 if (curval != frame->locals[local3]) {
02264 if (cnt>frame->locals[local2].get_int_value()){
02265
02266
02267 next++;
02268 } else {
02269
02270
02271 next--;
02272 }
02273 } else {
02274
02275
02276 }
02277 }
02278 else
02279 {
02280
02281
02282
02283 }
02284 }
02285
02286 if (cnt != frame->locals[local2].get_int_value()) {
02287
02288
02289 frame->locals[local2] = Usecode_value(cnt);
02290
02291 Usecode_value& curval = arr.is_array() ?
02292 arr.get_elem(next - 1) : arr;
02293
02294 if (curval != frame->locals[local3]) {
02295 if (cnt > frame->locals[local2].get_int_value()) {
02296
02297
02298 next++;
02299 } else {
02300
02301
02302 next--;
02303 }
02304 } else {
02305
02306
02307 }
02308 }
02309 }
02310
02311
02312 if (next >= frame->locals[local2].get_int_value()) {
02313 frame->ip += offset;
02314 } else
02315 {
02316 frame->locals[local3] = arr.is_array() ?
02317 arr.get_elem(next) : arr;
02318 frame->locals[local1] = Usecode_value(next + 1);
02319 }
02320 break;
02321 }
02322 case 0x2f:
02323 {
02324 offset = Read2(frame->ip);
02325 if (offset < 0 || offset >= num_locals) {
02326 LOCAL_VAR_ERROR(offset);
02327 break;
02328 }
02329
02330 const char *str = frame->locals[offset].get_str_value();
02331 if (str)
02332 append_string(str);
02333 else
02334 {
02335
02336
02337 if (frame->locals[offset].get_int_value() >= 0) {
02338 char buf[20];
02339 snprintf(buf, 20, "%ld",
02340 frame->locals[offset].get_int_value());
02341 append_string(buf);
02342 }
02343 }
02344 break;
02345 }
02346 case 0x30:
02347 {
02348 Usecode_value arr = pop();
02349
02350 Usecode_value val = pop().get_elem0();
02351 pushi(arr.find_elem(val) >= 0);
02352 break;
02353 }
02354 case 0x31:
02355 case 0xB1:
02356
02357
02358
02359 frame->ip += 2;
02360 if (opcode < 0x80)
02361 offset = (short)Read2(frame->ip);
02362 else
02363 offset = (sint32)Read4(frame->ip);
02364
02365 if (!found_answer)
02366 found_answer = true;
02367 else
02368 frame->ip += offset;
02369 break;
02370
02371 case 0x32:
02372 {
02373 show_pending_text();
02374
02375 Usecode_value zero(0);
02376 return_from_function(zero);
02377 frame_changed = true;
02378 break;
02379 }
02380 case 0x33:
02381 say_string();
02382 break;
02383 case 0x38:
02384 {
02385 offset = Read2(frame->ip);
02386 sval = *(frame->ip)++;
02387 Usecode_value ival = call_intrinsic(frame->eventid,
02388 offset, sval);
02389 push(ival);
02390 frame_changed = true;
02391 break;
02392 }
02393 case 0x39:
02394 offset = Read2(frame->ip);
02395 sval = *(frame->ip)++;
02396 call_intrinsic(frame->eventid, offset, sval);
02397 frame_changed = true;
02398 break;
02399 case 0x3e:
02400 pushref(frame->caller_item);
02401 break;
02402 case 0x3f:
02403 show_pending_text();
02404
02405 abort_function();
02406 frame_changed = true;
02407 aborted = true;
02408 break;
02409 case 0x40:
02410 found_answer = true;
02411 break;
02412 case 0x42:
02413 offset = Read2(frame->ip);
02414 if (offset < 0 || offset >= 1024) {
02415 FLAG_ERROR(offset);
02416 pushi(0);
02417 }
02418 pushi(gflags[offset]);
02419 break;
02420 case 0x43:
02421 offset = Read2(frame->ip);
02422 if (offset < 0 || offset >= 1024) {
02423 FLAG_ERROR(offset);
02424 }
02425 gflags[offset] = (unsigned char) popi();
02426
02427 if (offset == 0x272 && Game::get_game_type() ==
02428 SERPENT_ISLE)
02429 gflags[offset] = 0;
02430 break;
02431 case 0x44:
02432 pushi(*(frame->ip)++);
02433 break;
02434 case 0x46:
02435 {
02436
02437 offset = Read2(frame->ip);
02438 if (offset < 0 || offset >= num_locals) {
02439 LOCAL_VAR_ERROR(offset);
02440 break;
02441 }
02442
02443 Usecode_value& arr = frame->locals[offset];
02444 short index = popi();
02445 index--;
02446 Usecode_value val = pop();
02447 int size = arr.get_array_size();
02448 if (index >= 0 &&
02449 (index < size || arr.resize(index + 1)))
02450 arr.put_elem(index, val);
02451 break;
02452 }
02453 case 0x47:
02454 {
02455 Usecode_value ival = pop();
02456 Game_object *caller = get_item(ival);
02457 push(ival);
02458 offset = Read2(frame->ip);
02459 call_function(offset, frame->eventid, caller);
02460 frame_changed = true;
02461 break;
02462 }
02463 case 0x48:
02464 pushi(frame->eventid);
02465 break;
02466 case 0x4a:
02467 {
02468 Usecode_value val = pop();
02469 Usecode_value arr = pop();
02470 push(arr.concat(val));
02471 break;
02472 }
02473 case 0x4b:
02474 frame->eventid = popi();
02475 break;
02476 case 0x4c:
02477 {
02478 frame->line_number = Read2(frame->ip);
02479 break;
02480 }
02481 case 0x4d:
02482 {
02483 int funcname = Read2(frame->ip);
02484 int paramnames = Read2(frame->ip);
02485 break;
02486 }
02487 case 0x50:
02488 offset = Read2(frame->ip);
02489 if (offset < 0)
02490 if (-offset < statics.size())
02491 push(statics[-offset]);
02492 else
02493 pushi(0);
02494 else if (offset <
02495 frame->function->statics.size())
02496 push(frame->function->statics[offset]);
02497 else
02498 pushi(0);
02499 break;
02500 case 0x51:
02501 {
02502 offset = Read2(frame->ip);
02503
02504 Usecode_value val = pop();
02505 if (offset < 0)
02506 statics.put(-offset, val);
02507 else
02508 frame->function->statics.put(
02509 offset, val);
02510 }
02511 break;
02512 case 0x52:
02513 {
02514 Usecode_value ival = pop();
02515 Game_object *caller = get_item(ival);
02516 push(ival);
02517
02518 offset = Read2(frame->ip);
02519 call_function(offset, frame->eventid, caller,
02520 false, true);
02521 frame_changed = true;
02522 break;
02523 }
02524 case 0xcd:
02525 {
02526 int funcname = (sint32)Read4(frame->ip);
02527 int paramnames = (sint32)Read4(frame->ip);
02528 break;
02529 }
02530 default:
02531 cerr << "Opcode " << opcode << " not known. ";
02532 CERR_CURRENT_IP();
02533 break;
02534 }
02535 }
02536 }
02537
02538 if (call_stack.front() == 0) {
02539
02540 call_stack.pop_front();
02541 }
02542
02543 if (aborted)
02544 return 0;
02545
02546 return 1;
02547 }
02548
02549
02550
02551
02552
02553
02554
02555
02556
02557 int Usecode_internal::call_usecode
02558 (
02559 int id,
02560 Game_object *obj,
02561 Usecode_events event
02562 )
02563 {
02564
02565 if (!call_stack.empty() &&
02566 event == npc_proximity && Game::get_game_type() ==
02567 BLACK_GATE)
02568 return (0);
02569
02570 conv->clear_answers();
02571
02572 int ret;
02573 if (call_function(id, event, obj, true))
02574 ret = run();
02575 else
02576 ret = -1;
02577
02578 set_book(0);
02579
02580
02581 if (conv->get_num_faces_on_screen() > 0)
02582 {
02583 conv->init_faces();
02584 gwin->set_all_dirty();
02585 }
02586 if (modified_map)
02587 {
02588 Barge_object *barge = gwin->get_moving_barge();
02589 if (barge)
02590 barge->set_to_gather();
02591 modified_map = false;
02592 }
02593 return ret;
02594 }
02595
02596
02597
02598
02599
02600 void Usecode_internal::do_speech
02601 (
02602 int num
02603 )
02604 {
02605 speech_track = num;
02606 if (!Audio::get_ptr()->start_speech(num))
02607
02608 call_usecode(0x614, gwin->get_main_actor(), double_click);
02609 }
02610
02611
02612
02613
02614
02615 static void Write_useval
02616 (
02617 ostream& out,
02618 Usecode_value& val
02619 )
02620 {
02621 unsigned char buf[1024];
02622 int len = val.save(buf, sizeof(buf));
02623 if (len < 0)
02624 throw file_exception("Static usecode value overflows buf");
02625 else
02626 out.write((char *) buf, len);
02627 }
02628
02629
02630
02631
02632
02633
02634
02635
02636 void Usecode_internal::write
02637 (
02638 )
02639 {
02640
02641 if (Game::get_game_type() != BLACK_GATE)
02642 keyring->write();
02643
02644 ofstream out;
02645 U7open(out, FLAGINIT);
02646 out.write((char*)gflags, sizeof(gflags));
02647 out.close();
02648 U7open(out, USEDAT);
02649 Write2(out, partyman->get_count());
02650 int i;
02651 for (i = 0; i < EXULT_PARTY_MAX; i++)
02652 Write2(out, partyman->get_member(i));
02653
02654 for (size_t t = 0; t < sizeof(timers)/sizeof(timers[0]); t++)
02655 Write4(out, timers[t]);
02656 Write2(out, saved_pos.tx);
02657 Write2(out, saved_pos.ty);
02658 Write2(out, saved_pos.tz);
02659 out.flush();
02660 if( !out.good() )
02661 throw file_write_exception(USEDAT);
02662 out.close();
02663 U7open(out, USEVARS);
02664 Write4(out, statics.size());
02665 Exult_vector<Usecode_value>::iterator it;
02666 for (it = statics.begin(); it != statics.end(); ++it)
02667 Write_useval(out, *it);
02668
02669 int num_slots = sizeof(funs)/sizeof(funs[0]);
02670 for (i = 0; i < num_slots; i++)
02671 {
02672 vector<Usecode_function*>& slot = funs[i];
02673 for (std::vector<Usecode_function*>::iterator fit = slot.begin();
02674 fit != slot.end(); ++fit)
02675 {
02676 Usecode_function *fun = *fit;
02677 if (!fun || fun->statics.empty())
02678 continue;
02679 Write4(out, fun->id);
02680 Write4(out, fun->statics.size());
02681 for (it = fun->statics.begin();
02682 it != fun->statics.end(); ++it)
02683 Write_useval(out, *it);
02684 }
02685 }
02686 Write4(out, 0xffffffffU);
02687 out.flush();
02688 if( !out.good() )
02689 throw file_write_exception(USEVARS);
02690 out.close();
02691 }
02692
02693
02694
02695
02696
02697
02698
02699
02700 void Usecode_internal::read
02701 (
02702 )
02703 {
02704 if (Game::get_game_type() == SERPENT_ISLE)
02705 keyring->read();
02706
02707
02708 ifstream in;
02709 try
02710 {
02711 U7open(in, FLAGINIT);
02712 in.read((char*)gflags, sizeof(gflags));
02713 in.close();
02714 } catch(exult_exception &e) {
02715 if (!Game::is_editing())
02716 throw e;
02717 memset(&gflags[0], 0, sizeof(gflags));
02718 }
02719 try
02720 {
02721 U7open(in, USEVARS);
02722 read_usevars(in);
02723 in.close();
02724 }
02725 catch(exult_exception &e) {
02726 ;
02727
02728 }
02729 try
02730 {
02731 U7open(in, USEDAT);
02732 }
02733 catch(exult_exception &e) {
02734 partyman->set_count(0);
02735 partyman->link_party();
02736 return;
02737 }
02738 partyman->set_count(Read2(in));
02739 size_t i;
02740 for (i = 0; i < EXULT_PARTY_MAX; i++)
02741 partyman->set_member(i, Read2(in));
02742 partyman->link_party();
02743
02744 for (size_t t = 0; t < sizeof(timers)/sizeof(timers[0]); t++)
02745 timers[t] = Read4(in);
02746 if (!in.good())
02747 throw file_read_exception(USEDAT);
02748 saved_pos.tx = Read2(in);
02749 saved_pos.ty = Read2(in);
02750 saved_pos.tz = Read2(in);
02751 if (!in.good() ||
02752 saved_pos.tz < 0 || saved_pos.tz > 13)
02753 saved_pos = Tile_coord(-1, -1, -1);
02754 }
02755
02756
02757
02758
02759
02760 void Usecode_internal::read_usevars
02761 (
02762 std::istream& in
02763 )
02764 {
02765 in.seekg(0, ios::end);
02766 int size = in.tellg();
02767 in.seekg(0);
02768 if (!size)
02769 return;
02770 unsigned char *buf = new unsigned char[size];
02771 in.read((char *) buf, size);
02772 unsigned char *ptr = buf;
02773 unsigned char *ebuf = buf + size;
02774 int cnt = Read4(ptr);
02775 statics.resize(cnt);
02776 int i;
02777 for (i = 0; i < cnt; i++)
02778 statics[i].restore(ptr, ebuf - ptr);
02779 unsigned long funid;
02780 while (ptr < ebuf && (funid = Read4(ptr)) != 0xffffffffU)
02781 {
02782 int cnt = Read4(ptr);
02783 vector<Usecode_function*>& slot = funs[funid/0x100];
02784 size_t index = funid%0x100;
02785 Usecode_function *fun = index < slot.size() ? slot[index] : 0;
02786 if (!fun)
02787 {
02788 cerr << "Usecode " << funid << " not found" << endl;
02789 continue;
02790 }
02791 fun->statics.resize(cnt);
02792 for (i = 0; i < cnt; i++)
02793 fun->statics[i].restore(ptr, ebuf - ptr);
02794 }
02795 delete [] buf;
02796 }
02797
02798 #ifdef USECODE_DEBUGGER
02799
02800 int Usecode_internal::get_callstack_size() const
02801 {
02802 return call_stack.size();
02803 }
02804
02805 Stack_frame* Usecode_internal::get_stackframe(int i)
02806 {
02807 if (i >= 0 && i < call_stack.size())
02808 return call_stack[i];
02809 else
02810 return 0;
02811 }
02812
02813
02814
02815 int Usecode_internal::get_stack_size() const
02816 {
02817 return (int)(sp - stack);
02818 }
02819
02820
02821 Usecode_value* Usecode_internal::peek_stack(int depth) const
02822 {
02823 if (depth < 0 || depth >= get_stack_size())
02824 return 0;
02825
02826 return (sp - depth - 1);
02827 }
02828
02829
02830 void Usecode_internal::poke_stack(int depth, Usecode_value& val)
02831 {
02832 if (depth < 0 || (sp - depth) < stack)
02833 return;
02834
02835 *(sp - depth) = val;
02836 }
02837
02838
02839 void Usecode_internal::set_breakpoint()
02840 {
02841 breakpoints.add(new AnywhereBreakpoint());
02842 }
02843
02844 void Usecode_internal::dbg_stepover()
02845 {
02846 if (on_breakpoint)
02847 breakpoints.add(new StepoverBreakpoint(call_stack.front()));
02848 }
02849
02850 void Usecode_internal::dbg_finish()
02851 {
02852 if (on_breakpoint)
02853 breakpoints.add(new FinishBreakpoint(call_stack.front()));
02854 }
02855
02856 int Usecode_internal::set_location_breakpoint(int funcid, int ip)
02857 {
02858 Breakpoint *bp = new LocationBreakpoint(funcid, ip);
02859 breakpoints.add(bp);
02860
02861 return bp->id;
02862 }
02863
02864 #endif