intrinsics.cc

Go to the documentation of this file.
00001 /*
00002  *  Copyright (C) 2000-2001  The Exult Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  */
00018 
00019 #ifdef HAVE_CONFIG_H
00020 #  include <config.h>
00021 #endif
00022 
00023 #include "Audio.h"
00024 #include "Book_gump.h"
00025 #include "Gump.h"
00026 #include "Gump_manager.h"
00027 #include "Scroll_gump.h"
00028 #include "Sign_gump.h"
00029 #include "items.h"
00030 #include "barge.h"
00031 #include "bodies.h"
00032 #include "cheat.h"
00033 #include "chunks.h"
00034 #include "conversation.h"
00035 #include "effects.h"
00036 #include "exult.h"
00037 #include "game.h"
00038 #include "gamewin.h"
00039 #include "gamemap.h"
00040 #include "gameclk.h"
00041 #include "keyring.h"
00042 #include "mouse.h"
00043 #include "rect.h"
00044 #include "schedule.h"
00045 #include "spellbook.h"
00046 #include "ucinternal.h"
00047 #include "ucsched.h"
00048 #include "useval.h"
00049 #include "virstone.h"
00050 #include "monsters.h"
00051 #include "egg.h"
00052 #include "monstinf.h"
00053 #include "actions.h"
00054 #include "ucscriptop.h"
00055 #include "ucfunction.h"
00056 #include "palette.h"
00057 #include "stackframe.h"
00058 #include "party.h"
00059 
00060 #ifndef UNDER_CE
00061 using std::cerr;
00062 using std::cout;
00063 using std::endl;
00064 using std::rand;
00065 using std::strchr;
00066 #endif
00067 
00068 Barge_object *Get_barge (Game_object *obj);
00069 extern Usecode_value no_ret;
00070 
00071 static Game_object *sailor = 0;   // The current barge captain.  Maybe
00072           //   this needs to be saved/restored.
00073 
00074 #define PARTY_MAX (sizeof(party)/sizeof(party[0]))
00075 
00076 #define USECODE_INTRINSIC(NAME) Usecode_value Usecode_internal:: UI_## NAME (int event,int intrinsic,int num_parms,Usecode_value parms[12])
00077 
00078 USECODE_INTRINSIC(NOP)
00079 {
00080   return(no_ret);
00081 }
00082 
00083 USECODE_INTRINSIC(UNKNOWN)
00084 {
00085 //  Unhandled(intrinsic, num_parms, parms);
00086   return(no_ret);
00087 }
00088 
00089 USECODE_INTRINSIC(get_random)
00090 {
00091   int range = parms[0].get_int_value();
00092   if (range == 0)
00093     {
00094     Usecode_value u(0);
00095     return(u);
00096     }
00097   Usecode_value u=(1 + (rand() % range));
00098   return(u);
00099 }
00100 
00101 USECODE_INTRINSIC(execute_usecode_array)
00102 {
00103   COUT("Executing intrinsic 1");
00104           // Start on next tick.
00105   create_script(parms[0], parms[1], 1);
00106 
00107   Usecode_value u(1);
00108   return(u);
00109 }
00110 
00111 USECODE_INTRINSIC(delayed_execute_usecode_array)
00112 {
00113   // Delay = .20 sec.?
00114           // +++++Special problem with inf. loop:
00115   if (Game::get_game_type() == BLACK_GATE &&
00116       event == internal_exec && parms[1].get_array_size() == 3 &&
00117       parms[1].get_elem(2).get_int_value() == 0x6f7)
00118     return(no_ret);
00119   int delay = parms[2].get_int_value();
00120   create_script(parms[0], parms[1], delay*gwin->get_std_delay());
00121   COUT("Executing intrinsic 2");
00122 
00123   Usecode_value u(1);
00124   return(u);
00125 }
00126 
00127 USECODE_INTRINSIC(show_npc_face)
00128 {
00129   show_npc_face(parms[0], parms[1]);
00130   return(no_ret);
00131 }
00132 
00133 USECODE_INTRINSIC(remove_npc_face)
00134 {
00135   remove_npc_face(parms[0]);
00136   return(no_ret);
00137 }
00138 
00139 USECODE_INTRINSIC(add_answer)
00140 {
00141   conv->add_answer(parms[0]);
00142   //  user_choice = 0;
00143   return(no_ret);
00144 }
00145 
00146 USECODE_INTRINSIC(remove_answer)
00147 {
00148   conv->remove_answer(parms[0]);
00149 // Commented out 'user_choice = 0' 8/3/00 for Tseramed conversation.
00150 //  user_choice = 0;
00151   return(no_ret);
00152 }
00153 
00154 USECODE_INTRINSIC(push_answers)
00155 {
00156   conv->push_answers();
00157   return(no_ret);
00158 }
00159 
00160 USECODE_INTRINSIC(pop_answers)
00161 {
00162   if(!conv->stack_empty())
00163   {
00164     conv->pop_answers();
00165     user_choice = 0;  // Added 7/24/2000.
00166   }
00167   return(no_ret);
00168 }
00169 
00170 USECODE_INTRINSIC(clear_answers)
00171 {
00172   conv->clear_answers();
00173   return(no_ret);
00174 }
00175 
00176 USECODE_INTRINSIC(select_from_menu)
00177 {
00178   user_choice = 0;
00179   const char *choice = get_user_choice();
00180   user_choice = 0;
00181   Usecode_value u(choice);
00182   return(u);
00183 }
00184 
00185 USECODE_INTRINSIC(select_from_menu2)
00186 {
00187   // Return index (1-n) of choice.
00188   user_choice = 0;
00189   Usecode_value val(get_user_choice_num() + 1);
00190   user_choice = 0;
00191   return(val);
00192 }
00193 
00194 USECODE_INTRINSIC(input_numeric_value)
00195 {
00196   // Ask for # (min, max, step, default).  Be sure to show conversation.
00197   Usecode_value ret(gumpman->prompt_for_number(
00198     parms[0].get_int_value(), parms[1].get_int_value(),
00199     parms[2].get_int_value(), parms[3].get_int_value(), conv));
00200   conv->clear_text_pending(); // Answered a question.
00201   return(ret);
00202 }
00203 
00204 USECODE_INTRINSIC(set_item_shape)
00205 {
00206   // Set item shape.
00207   set_item_shape(parms[0], parms[1]);
00208   return(no_ret);
00209 }
00210 
00211 USECODE_INTRINSIC(find_nearest)
00212 {
00213   // Think it rets. nearest obj. near parm0.
00214   Usecode_value u(find_nearest(parms[0], parms[1], parms[2]));
00215   return(u);
00216 }
00217 
00218 USECODE_INTRINSIC(die_roll)
00219 {
00220   // Rand. # within range.
00221   int low = parms[0].get_int_value();
00222   int high = parms[1].get_int_value();
00223   if (low > high)
00224     {
00225     int tmp = low;
00226     low = high;
00227     high = tmp;
00228     }
00229   int val = (rand() % (high - low + 1)) + low;
00230   Usecode_value u(val);
00231   return(u);
00232 }
00233 
00234 USECODE_INTRINSIC(get_item_shape)
00235 {
00236   Game_object *item = get_item(parms[0]);
00237           // Want the actual, not polymorph'd.
00238   Actor *act = as_actor(item);
00239   return Usecode_value(item == 0 ? 0 : 
00240     (act ? act->get_shape_real() : item->get_shapenum()));
00241 }
00242 
00243 USECODE_INTRINSIC(get_item_frame)
00244 {
00245   // Returns frame without rotated bit.
00246   Game_object *item = get_item(parms[0]);
00247           // Don't count rotated frames.
00248   return Usecode_value(item == 0 ? 0 : item->get_framenum()&31);
00249 }
00250 
00251 USECODE_INTRINSIC(set_item_frame)
00252 { // Set frame, but don't change rotated bit.
00253 //++++++++Seems like in BG, this should be the same as set_item_frame_rot()??
00254   set_item_frame(get_item(parms[0]), parms[1].get_int_value());
00255   return(no_ret);
00256 }
00257 
00258 USECODE_INTRINSIC(get_item_quality)
00259 {
00260   Game_object *obj = get_item(parms[0]);
00261   if (!obj)
00262     return Usecode_value(0);
00263   Shape_info& info = obj->get_info();
00264   return Usecode_value(info.has_quality() ? obj->get_quality() : 0);
00265 }
00266 
00267 USECODE_INTRINSIC(set_item_quality)
00268 {
00269   // Guessing it's 
00270   //  set_quality(item, value).
00271   int qual = parms[1].get_int_value();
00272   if (qual == c_any_qual)   // Leave alone (happens in SI)?
00273     return Usecode_value(1);
00274   Game_object *obj = get_item(parms[0]);
00275   if (obj)
00276     {
00277     Shape_info& info = obj->get_info();
00278     if (info.has_quality())
00279       {
00280       obj->set_quality((unsigned int) qual);
00281       return Usecode_value(1);
00282       }
00283     }
00284   return Usecode_value(0);
00285 }
00286 
00287 USECODE_INTRINSIC(get_item_quantity)
00288 {
00289   // Get quantity of an item.
00290   //   Get_quantity(item, mystery).
00291   Usecode_value ret(0);
00292   Game_object *obj = get_item(parms[0]);
00293   if (obj)
00294     ret = Usecode_value(obj->get_quantity());
00295   return(ret);
00296 }
00297 
00298 USECODE_INTRINSIC(set_item_quantity)
00299 {
00300   // Set_quantity (item, newcount).  Rets 1 iff item.has_quantity().
00301   Usecode_value ret(0);
00302   Game_object *obj = get_item(parms[0]);
00303   int newquant = parms[1].get_int_value();
00304   if (obj && obj->get_info().has_quantity())
00305     {
00306     ret = Usecode_value(1);
00307           // If not in world, don't delete!
00308     if (newquant == 0 && obj->get_cx() == 255)
00309       return ret;
00310     int oldquant = obj->get_quantity();
00311     int delta = newquant - oldquant;
00312           // Note:  This can delete the obj.
00313     int newdelta = obj->modify_quantity(delta);
00314     }
00315   return(ret);
00316 }
00317 
00318 USECODE_INTRINSIC(get_object_position)
00319 {
00320   // Takes itemref.  ?Think it rets.
00321   //  hotspot coords: (x, y, z).
00322   Game_object *obj = get_item(parms[0]);
00323   Tile_coord c(0, 0, 0);
00324   if (obj)    // (Watch for animated objs' wiggles.)
00325     c = obj->get_outermost()->get_original_tile_coord();
00326   Usecode_value vx(c.tx), vy(c.ty), vz(c.tz);
00327   Usecode_value arr(3, &vx);
00328   arr.put_elem(1, vy);
00329   arr.put_elem(2, vz);
00330   return(arr);
00331 }
00332 
00333 USECODE_INTRINSIC(get_distance)
00334 {
00335   // Distance from parm[0] -> parm[1].  Guessing how it's computed.
00336   Game_object *obj0 = get_item(parms[0]);
00337   Game_object *obj1 = get_item(parms[1]);
00338   Usecode_value u((obj0 && obj1) ? 
00339     obj0->get_outermost()->get_tile().distance(
00340         obj1->get_outermost()->get_tile()) : 0);
00341   return(u);
00342 }
00343 
00344 USECODE_INTRINSIC(find_direction)
00345 {
00346   // Direction from parm[0] -> parm[1].
00347   // Rets. 0-7.  Is 0 east?
00348   Usecode_value u=find_direction(parms[0], parms[1]);
00349   return(u);
00350 }
00351 
00352 USECODE_INTRINSIC(get_npc_object)
00353 {
00354   // Takes -npc.  Returns object, or array of objects.
00355   Usecode_value& v = parms[0];
00356   if (v.is_array())   // Do it for each element of array.
00357     {
00358     int sz = v.get_array_size();
00359     Usecode_value ret(sz, 0);
00360     for (int i = 0; i < sz; i++)
00361       {
00362       Usecode_value elem(get_item(v.get_elem(i)));
00363       ret.put_elem(i, elem);
00364       }
00365     return ret;
00366     }
00367   Game_object *obj = get_item(parms[0]);
00368   Usecode_value u(obj);
00369   return(u);
00370 }
00371 
00372 USECODE_INTRINSIC(get_schedule_type)
00373 {
00374   // GetSchedule(npc).  Rets. schedtype.
00375   Actor *npc = as_actor(get_item(parms[0]));
00376   if (!npc)
00377     return Usecode_value(0);
00378   Schedule *schedule = npc->get_schedule();
00379   int sched = schedule ? schedule->get_actual_type(npc) 
00380            : npc->get_schedule_type();
00381           // Path_run_usecode?  (This is to fix
00382           //   a bug in the Fawn Trial.)
00383           //+++++Should be a better way to check.
00384   if (Game::get_game_type() == SERPENT_ISLE &&
00385       npc->get_action() && npc->get_action()->as_usecode_path())
00386           // Give a 'fake' schedule.
00387     sched = Schedule::walk_to_schedule;
00388   Usecode_value u(sched);
00389   return(u);
00390 }
00391 
00392 USECODE_INTRINSIC(set_schedule_type)
00393 {
00394   // SetSchedule?(npc, schedtype).
00395   // Looks like 15=wait here, 11=go home, 0=train/fight... This is the
00396   // 'bNum' field in schedules.
00397   Actor *npc = as_actor(get_item(parms[0]));
00398   if (npc)
00399     {
00400     int newsched = parms[1].get_int_value();
00401     npc->set_schedule_type(newsched);
00402           // Taking Avatar out of combat?
00403     if (npc == gwin->get_main_actor() && gwin->in_combat() &&
00404         newsched != Schedule::combat)
00405           // End combat mode (for L.Field).
00406       {
00407       Audio::get_ptr()->stop_music();
00408       gwin->toggle_combat();
00409       }
00410     }
00411   return(no_ret);
00412 }
00413 
00414 USECODE_INTRINSIC(add_to_party)
00415 {
00416   // NPC joins party.
00417   Actor *npc = as_actor(get_item(parms[0]));
00418   if (!partyman->add_to_party(npc))
00419     return no_ret;    // Can't add.
00420   npc->set_schedule_type(Schedule::follow_avatar);
00421 // cout << "NPC " << npc->get_npc_num() << " added to party." << endl;
00422   return no_ret;
00423 }
00424 
00425 USECODE_INTRINSIC(remove_from_party)
00426 {
00427   // NPC leaves party.
00428   Game_object *npc = get_item(parms[0]);
00429   partyman->remove_from_party(as_actor(npc));
00430   return no_ret;
00431 }
00432 
00433 USECODE_INTRINSIC(get_npc_prop)
00434 {
00435   // Get NPC prop (item, prop_id).
00436   //   (9 is food level).
00437   Actor *npc = as_actor(get_item(parms[0]));
00438   Usecode_value u(npc ? 
00439     npc->get_property(parms[1].get_int_value()) : 0);
00440   return(u);
00441 }
00442 
00443 USECODE_INTRINSIC(set_npc_prop)
00444 {
00445   // Set NPC prop (item, prop_id, delta_value).
00446   Actor *npc = as_actor(get_item(parms[0]));
00447   if (npc)
00448     {     // NOTE: 3rd parm. is a delta!
00449     int prop = parms[1].get_int_value();
00450     npc->set_property(prop, npc->get_property(prop) +
00451             parms[2].get_int_value());
00452     return Usecode_value(1);// SI needs return.
00453     }
00454   return Usecode_value(0);
00455 }
00456 
00457 USECODE_INTRINSIC(get_avatar_ref)
00458 {
00459   // Guessing it's Avatar's itemref.
00460   Usecode_value u(gwin->get_main_actor());
00461   return(u);
00462 }
00463 
00464 USECODE_INTRINSIC(get_party_list)
00465 {
00466   // Return array with party members.
00467   Usecode_value u(get_party());
00468   return(u);
00469 }
00470 
00471 USECODE_INTRINSIC(create_new_object)
00472 {
00473   // create_new_object(shapenum).   Stores it in 'last_created' (which
00474   //   maybe should be a stack.
00475   int shapenum = parms[0].get_int_value();
00476 
00477   Game_object *obj;   // Create to be written to Ireg.
00478   Shape_info& info = ShapeID::get_info(shapenum);
00479   modified_map = true;
00480           // +++Not sure if 1st test is needed.
00481   if (info.get_monster_info() || info.is_npc())
00482   {
00483           // (Wait sched. added for FOV.)
00484     // don't add equipment (Erethian's transform sequence)
00485     Monster_actor *monster = Monster_actor::create(shapenum,
00486       Tile_coord(-1, -1, -1), Schedule::wait, 
00487           (int) Actor::neutral, true, false);
00488           // FORCE it to be neutral (dec04,01).
00489     monster->set_alignment((int) Actor::neutral);
00490     gwin->add_dirty(monster);
00491     gwin->add_nearby_npc(monster);
00492     gwin->show();
00493     last_created.push_back(monster);
00494     return Usecode_value(monster);
00495   }
00496   else
00497   {
00498     if (Is_body(shapenum))
00499     {
00500       obj = new Dead_body(shapenum, 0, 0, 0, 0, -1);
00501     }
00502     else
00503     {
00504       obj = gmap->create_ireg_object(shapenum, 0);
00505           // Be liberal about taking stuff.
00506       obj->set_flag(Obj_flags::okay_to_take);
00507     }
00508   }
00509   obj->set_invalid();   // Not in world yet.
00510   obj->set_flag(Obj_flags::okay_to_take);
00511   last_created.push_back(obj);
00512   Usecode_value u(obj);
00513   return(u);
00514 }
00515 
00516 USECODE_INTRINSIC(create_new_object2)
00517 {
00518   // create_new_object(shapenum, loc).
00519   Usecode_value ret = UI_create_new_object(event, intrinsic, 1, parms);
00520   if (ret == 0)
00521     return ret;   // Failed.
00522   UI_update_last_created(event, intrinsic, 1, &parms[1]);
00523   return ret;
00524 }
00525 
00526 USECODE_INTRINSIC(set_last_created)
00527 {
00528   // Take itemref off map and set last_created to it.
00529   Game_object *obj = get_item(parms[0]);
00530   modified_map = true;
00531   if (obj)
00532     {
00533     add_dirty(obj);   // Set to repaint area.
00534     last_created.push_back(obj);
00535     obj->remove_this(1);  // Remove, but don't delete.
00536     }
00537   Usecode_value u(obj);
00538   return(u);
00539 }
00540 
00541 USECODE_INTRINSIC(update_last_created)
00542 {
00543   // Think it takes array from 0x18,
00544   //   updates last-created object.
00545   //   ??guessing??
00546   modified_map = true;
00547   if (last_created.empty())
00548     {
00549     Usecode_value u((Game_object*) NULL);
00550     return(u);
00551     }
00552   Game_object *obj = last_created.back();
00553   last_created.pop_back();
00554   obj->set_invalid();   // It's already been removed.
00555   Usecode_value& arr = parms[0];
00556   int sz = arr.get_array_size();
00557   if (sz == 3 || sz == 2)
00558     {
00559     Tile_coord dest(arr.get_elem(0).get_int_value(),
00560         arr.get_elem(1).get_int_value(),
00561         sz == 3 ? arr.get_elem(2).get_int_value() : 0);
00562     obj->move(dest.tx, dest.ty, dest.tz);
00563     if (GAME_BG) {
00564       Usecode_value u(1);
00565       return u;
00566     } else {
00567       Usecode_value u(obj);
00568       return u;
00569     }
00570           // Taking a guess here:
00571   } else if (sz == 1)
00572     {
00573     obj->remove_this();
00574     }
00575 #ifdef DEBUG
00576   else
00577     {
00578     cout << " { Intrinsic 0x26:  "; arr.print(cout); cout << endl << "} ";
00579     }
00580 #endif
00581 //  gwin->paint_dirty();  // Problems in conversations.
00582 //  gwin->show();   // ??
00583   Usecode_value u(1);
00584   return(u);
00585 }
00586 
00587 USECODE_INTRINSIC(get_npc_name)
00588 {
00589   // Get NPC name(s).  Works on arrays, too.
00590   static const char *unknown = "??name??";
00591   Actor *npc;
00592   int cnt = parms[0].get_array_size();
00593   if (cnt)
00594     {     // Do array.
00595     Usecode_value arr(cnt, 0);
00596     for (int i = 0; i < cnt; i++)
00597       {
00598       Game_object *obj = get_item(parms[0].get_elem(i));
00599       npc = as_actor(obj);
00600       std::string namestr = npc ? npc->get_npc_name()
00601               : obj->get_name();
00602       Usecode_value v(namestr.c_str());
00603       arr.put_elem(i, v);
00604       }
00605     return(arr);
00606     }
00607   Game_object *obj = get_item(parms[0]);
00608   std::string namestr;
00609   if (obj)
00610     {
00611     npc = as_actor(obj);
00612     namestr = npc ? npc->get_npc_name() : obj->get_name();
00613     }
00614   else
00615     namestr = unknown;
00616   Usecode_value u(namestr.c_str());
00617   return(u);
00618 }
00619 
00620 USECODE_INTRINSIC(count_objects)
00621 {
00622   // How many?
00623   // ((npc?-357==party, -356=avatar), 
00624   //   item, quality, frame (c_any_framenum = any)).
00625   // Quality/frame -359 means any.
00626   Usecode_value u(count_objects(parms[0], parms[1], parms[2], parms[3]));
00627   return(u);
00628 }
00629 
00630 USECODE_INTRINSIC(find_object)
00631 {
00632   // Find_object(container(-357=party) OR loc, shapenum, qual?? (-359=any), 
00633   //            frame??(-359=any)).
00634   int shnum = parms[1].get_int_value(),
00635       qual  = parms[2].get_int_value(),
00636       frnum = parms[3].get_int_value();
00637   if (parms[0].get_array_size() == 3)
00638     {     // Location (x, y).
00639     Game_object_vector vec;
00640     Game_object::find_nearby(vec,
00641       Tile_coord(parms[0].get_elem(0).get_int_value(),
00642            parms[0].get_elem(1).get_int_value(),
00643            parms[0].get_elem(2).get_int_value()),
00644       shnum, 1, 0, qual, frnum);
00645     if (vec.empty())
00646       return Usecode_value((Game_object *) 0);
00647     else
00648       return Usecode_value(vec.front());
00649     }
00650   int oval  = parms[0].get_int_value();
00651   if (oval != -357)   // Not the whole party?
00652     {     // Find inside owner.
00653     Game_object *obj = get_item(parms[0]);
00654     if (!obj)
00655       return Usecode_value((Game_object*) NULL);
00656     Game_object *f = obj->find_item(shnum, qual, frnum);
00657     return Usecode_value(f);
00658     }
00659           // Look through whole party.
00660   Usecode_value party = get_party();
00661   int cnt = party.get_array_size();
00662   for (int i = 0; i < cnt; i++)
00663     {
00664     Game_object *obj = get_item(party.get_elem(i));
00665     if (obj)
00666       {
00667       Game_object *f = obj->find_item(shnum, qual, frnum);
00668       if (f)
00669         return Usecode_value(f);
00670       }
00671     }
00672   return Usecode_value((Game_object*) NULL);
00673 }
00674 
00675 USECODE_INTRINSIC(get_cont_items)
00676 {
00677   // Get cont. items(container, shape, qual, frame).
00678   // recursively find items in container
00679   Usecode_value u(get_objects(parms[0], parms[1], parms[2], parms[3]));
00680   return(u);
00681 }
00682 
00683 
00684 USECODE_INTRINSIC(remove_party_items)
00685 {
00686   // Remove items(quantity, item, ??quality?? (-359), frame(-359), T/F).
00687   return remove_party_items(parms[0], parms[1], parms[2],
00688             parms[3], parms[4]);
00689 }
00690 
00691 USECODE_INTRINSIC(add_party_items)
00692 {
00693   // Add items(num, item, ??quality?? (-359), frame (or -359), T/F).
00694   // Returns array of NPC's (->'s) who got the items.
00695   Usecode_value u(add_party_items(parms[0], parms[1], parms[2],
00696             parms[3], parms[4]));
00697   return(u);
00698 }
00699 
00700 USECODE_INTRINSIC(play_music)
00701 {
00702   // Play music(songnum, item).
00703   // ??Show notes by item?
00704 #ifdef DEBUG
00705   cout << "Music request in usecode" << endl;
00706   cout << "Parameter data follows" << endl;
00707   cout << "0: " << ((parms[0].get_int_value()>>8)&0xff) << " " <<  ((parms[0].get_int_value())&0xff) << endl;
00708   cout << "1: " << ((parms[1].get_int_value()>>8)&0x01) << " " <<  ((parms[1].get_int_value())&0x01) << endl;
00709 #endif
00710   int track = parms[0].get_int_value()&0xff;
00711   if (track == 0xff)    // I think this is right:
00712     Audio::get_ptr()->cancel_streams(); // Stop playing.
00713   else
00714     {
00715     Audio::get_ptr()->start_music(track, 
00716           (parms[0].get_int_value()>>8)&0x01);
00717           // Show notes.
00718     Game_object *obj = get_item(parms[1]);
00719     if (obj)
00720       gwin->get_effects()->add_effect(
00721         new Sprites_effect(24, obj, 0, 0, -2, -2));
00722     }
00723   return(no_ret);
00724 }
00725 
00726 USECODE_INTRINSIC(npc_nearby)
00727 {
00728   // NPC nearby? (item).
00729   Game_object *npc = get_item(parms[0]);
00730   int is_near = (npc != 0 && 
00731     npc->get_tile().distance(gwin->get_main_actor()->get_tile()) 
00732                 < 12 &&
00733           // FALSE if asleep.
00734     !npc->get_flag(Obj_flags::asleep));
00735   Usecode_value u(is_near);
00736   return(u);
00737 }
00738 
00739 USECODE_INTRINSIC(npc_nearby2)
00740 { // Guessing wildly (SI).  Handles start of Moonshade trial where
00741   //   companions are a fair distance away.
00742 
00743   Game_object *npc = get_item(parms[0]);
00744   int is_near = (npc != 0 && 
00745     npc->get_tile().distance(gwin->get_main_actor()->get_tile()) 
00746                 < 40 &&
00747           // FALSE if asleep.
00748     !npc->get_flag(Obj_flags::asleep));
00749   Usecode_value u(is_near);
00750   return(u);
00751 }
00752 
00753 USECODE_INTRINSIC(find_nearby_avatar)
00754 {
00755   // Find objs. with given shape near Avatar?
00756   Usecode_value av(gwin->get_main_actor());
00757           // Try bigger # for Test of Love tree.
00758   Usecode_value dist(/* 64 */ 192), mask(0);
00759   Usecode_value u(find_nearby(av, parms[0], dist, mask));
00760   return(u);
00761 }
00762 
00763 USECODE_INTRINSIC(is_npc)
00764 {
00765   // Is item an NPC?
00766   Actor *npc = as_actor(get_item(parms[0]));
00767   Usecode_value u(npc != 0);
00768   return(u);
00769 }
00770 
00771 USECODE_INTRINSIC(display_runes)
00772 {
00773   // Render text into runes for signs, tombstones, plaques and the like
00774   // Display sign (gump #, array_of_text).
00775   int cnt = parms[1].get_array_size();
00776   if (!cnt)
00777     cnt = 1;    // Try with 1 element.
00778   Sign_gump *sign = new Sign_gump(parms[0].get_int_value(), cnt);
00779   bool si = Game::get_game_type()== SERPENT_ISLE;
00780   for (int i = 0; i < cnt; i++)
00781     {     // Paint each line.
00782     Usecode_value& lval = !i ? parms[1].get_elem0() 
00783           : parms[1].get_elem(i);
00784     const char *str = lval.get_str_value();
00785 #if 0 /* ++++Not sure about this yet.  Compare with orig. */
00786     if (si)     // SI:  Add 0x20 to each chr.
00787       {
00788       char *newstr = strdup(str);
00789       for (char *ptr = newstr; *ptr; ptr++)
00790         if (*ptr >= 'A' && *ptr <= 'Z')
00791           *ptr += 0x20;
00792       sign->add_text(i, newstr);
00793       delete newstr;
00794       }
00795     else
00796 #endif
00797       sign->add_text(i, str);
00798     }
00799   int x, y;     // Paint it, and wait for click.
00800   Get_click(x, y, Mouse::hand, 0, false, sign);
00801   delete sign;
00802   gwin->paint();
00803   return(no_ret);
00804 }
00805 
00806 USECODE_INTRINSIC(click_on_item)
00807 {
00808   // Doesn't ret. until user single-
00809   //   clicks on an item.  Rets. item.
00810   Game_object *obj;
00811   Tile_coord t;
00812 
00813   // intercept this click?
00814   if (intercept_item) {
00815     obj = intercept_item;
00816     intercept_item = 0;
00817     t = obj->get_tile();
00818 
00819           // Special case for weapon hit:
00820   } else if (event == weapon && caller_item)
00821   {
00822         // if caller_item is the Avatar, return the Avatar's target
00823         // instead. This makes combat spellcasting work
00824 
00825         // if caller_item is not the Avatar return caller_item itself
00826         // this is needed for hitting Draygan with sleep arrows (SI)
00827     Actor *npc = as_actor(caller_item);
00828     if (npc == gwin->get_main_actor() && npc->get_target())
00829       obj = npc->get_target();
00830     else
00831       obj = caller_item;
00832     t = obj->get_tile();
00833     }
00834   else
00835     {
00836     int x, y;   // Allow dragging while here:
00837     if (!Get_click(x, y, Mouse::greenselect, 0, true))
00838       return Usecode_value(0);
00839           // Get abs. tile coords. clicked on.
00840     t = Tile_coord(gwin->get_scrolltx() + x/c_tilesize,
00841         gwin->get_scrollty() + y/c_tilesize, 0);
00842           // Look for obj. in open gump.
00843     Gump *gump = gumpman->find_gump(x, y);
00844     if (gump)
00845     {
00846       obj = gump->find_object(x, y);
00847       if (!obj) obj = gump->find_actor(x, y);
00848     }
00849     else      // Search rest of world.
00850       {
00851       obj = gwin->find_object(x, y);
00852       if (obj)  // Found object?  Use its coords.
00853         t = obj->get_tile();
00854       }
00855     }
00856   Usecode_value oval(obj);  // Ret. array with obj as 1st elem.
00857   Usecode_value ret(4, &oval);
00858   Usecode_value xval(t.tx), yval(t.ty), zval(t.tz);
00859   ret.put_elem(1, xval);
00860   ret.put_elem(2, yval);
00861   ret.put_elem(3, zval);
00862   return (ret);
00863 }
00864 
00865 /*  Set item to be returned by next call to click_on_item().
00866  *  Added for Exult.
00867  */
00868 USECODE_INTRINSIC(set_intercept_item)
00869 {
00870   intercept_item = get_item(parms[0]);
00871   return no_ret;
00872 }
00873 
00874 USECODE_INTRINSIC(find_nearby)
00875 {
00876   // Think it rets. objs. near parm0.
00877   Usecode_value u(find_nearby(parms[0], parms[1], parms[2], parms[3]));
00878   return(u);
00879 }
00880 
00881 USECODE_INTRINSIC(give_last_created)
00882 {
00883   // Think it's give_last_created(container).
00884   Game_object *cont = get_item(parms[0]);
00885   int ret = 0;
00886   if (cont && !last_created.empty())
00887     {
00888           // Get object, but don't pop yet.
00889     Game_object *obj = last_created.back();
00890           // Don't check vol.  Causes failures.
00891     ret = cont->add(obj, 1);
00892     if (ret)    // Pop only if added.  Fixes chest/
00893           //   tooth bug in SI.
00894       last_created.pop_back();
00895     }
00896   Usecode_value u(ret);
00897   return(u);
00898 }
00899 
00900 USECODE_INTRINSIC(is_dead)
00901 {
00902   // Return 1 if parm0 is a dead NPC.
00903   Actor *npc = as_actor(get_item(parms[0]));
00904   Usecode_value u(npc && npc->is_dead());
00905   return(u);
00906 }
00907 
00908 USECODE_INTRINSIC(game_hour)
00909 {
00910   // Return. game time hour (0-23).
00911   Usecode_value u(gclock->get_hour());
00912   return(u);
00913 }
00914 
00915 USECODE_INTRINSIC(game_minute)
00916 {
00917   // Return minute (0-59).
00918   Usecode_value u(gclock->get_minute());
00919   return(u);
00920 }
00921 
00922 USECODE_INTRINSIC(get_npc_number)
00923 {
00924   // Returns NPC# of item. (-356 =
00925   //   avatar).
00926   Actor *npc = as_actor(get_item(parms[0]));
00927   if (npc == gwin->get_main_actor())
00928     {
00929     Usecode_value u(-356);
00930     return(u);
00931     }
00932   int num = npc ? npc->get_npc_num() : 0;
00933   Usecode_value u(-num);
00934   return(u);
00935 }
00936 
00937 USECODE_INTRINSIC(part_of_day)
00938 {
00939   // Return 3-hour # (0-7, 0=midnight).
00940   Usecode_value u(gclock->get_hour()/3);
00941   return(u);
00942 }
00943 
00944 USECODE_INTRINSIC(get_alignment)
00945 {
00946   // Get npc's alignment.
00947   Actor *npc = as_actor(get_item(parms[0]));
00948   Usecode_value u(npc ? npc->get_alignment() : 0);
00949   return(u);
00950 }
00951 
00952 USECODE_INTRINSIC(set_alignment)
00953 {
00954   // Set npc's alignment.
00955   // 2,3==bad towards Ava. 0==good.
00956   Actor *npc = as_actor(get_item(parms[0]));
00957   int val = parms[1].get_int_value();
00958   if (npc)
00959     {
00960     int oldalign = npc->get_alignment();
00961     npc->set_alignment(val);
00962     if (oldalign != val)  // Changed?  Force search for new opp.
00963       npc->set_target(0);
00964           // For fixing List Field fleeing:
00965     if (npc->get_attack_mode() == Actor::flee)
00966       npc->set_attack_mode(Actor::nearest);
00967     }
00968   return(no_ret);
00969 }
00970 
00971 USECODE_INTRINSIC(move_object)
00972 {
00973   // move_object(obj(-357=party), (tx, ty, tz)).
00974   Usecode_value& p = parms[1];
00975   Tile_coord tile(p.get_elem(0).get_int_value(),
00976       p.get_elem(1).get_int_value(),
00977       p.get_elem(2).get_int_value());
00978   Actor *ava = gwin->get_main_actor();
00979   modified_map = true;
00980   if (parms[0].get_int_value() == -357)
00981     {     // Move whole party.
00982           // If Freedom exit teleport, don't ac-
00983           //   tivate eggs when you arrive.
00984     gwin->teleport_party(tile, Game::get_game_type() ==
00985       SERPENT_ISLE && frame->function->id == 0x7df && 
00986         caller_item->get_quality() == 0xcf);
00987     return (no_ret);
00988     }
00989   Game_object *obj = get_item(parms[0]);
00990   if (!obj)
00991     return (no_ret);
00992   Tile_coord oldpos = obj->get_tile();
00993   obj->move(tile.tx, tile.ty, tile.tz);
00994   Actor *act = as_actor(obj);
00995   if (act)
00996     {
00997     act->set_action(0);
00998     if (act == ava)
00999       {   // Teleported Avatar?
01000           // Make new loc. visible, test eggs.
01001       gwin->center_view(tile);
01002       Map_chunk::try_all_eggs(ava, tile.tx, 
01003         tile.ty, tile.tz, oldpos.tx, oldpos.ty);
01004       }
01005           // Close?  Add to 'nearby' list.
01006     else if (ava->distance(act) < gwin->get_width()/c_tilesize)
01007       {
01008       Npc_actor *npc = act->as_npc();
01009       if (npc) gwin->add_nearby_npc(npc);
01010       }
01011     }
01012   return(no_ret);
01013 }
01014 
01015 USECODE_INTRINSIC(remove_npc)
01016 {
01017   // Remove_npc(npc) - Remove npc from world.
01018   Actor *npc = as_actor(get_item(parms[0]));
01019   if (npc)
01020     {
01021     modified_map = true;
01022           // Don't want him/her coming back!
01023     npc->set_schedule_type(Schedule::wait);
01024     gwin->add_dirty(npc);
01025     npc->remove_this(1);  // Remove, but don't delete.
01026     }
01027   return (no_ret);
01028 }
01029 
01030 USECODE_INTRINSIC(item_say)
01031 {
01032   // Show str. near item (item, str).
01033   if (!conv->is_npc_text_pending())
01034     item_say(parms[0], parms[1]); // Do it now.
01035   return(no_ret);
01036 }
01037 
01038 USECODE_INTRINSIC(clear_item_say)
01039 {
01040   // Clear str. near item (item).
01041   Game_object *item = get_item(parms[0]);
01042   if (item)
01043     gwin->get_effects()->remove_text_effect(item);
01044   return(no_ret);
01045 }
01046 
01047 USECODE_INTRINSIC(projectile_effect)
01048 {
01049   // animate(fromitem, toitem, anim_shape_in_shapesdotvga).
01050   // ???? When it reaches toitem, toitem is 'attacked' by anim_shape.
01051   //   Returns??}
01052   Game_object *from = get_item(parms[0]),
01053         *to = get_item(parms[1]);
01054   if (!from || !to)
01055     return Usecode_value(0);
01056   Actor *attacker = as_actor(from);
01057   if (!attacker)
01058     return Usecode_value(0);
01059   int shnum = parms[2].get_int_value();
01060   gwin->get_effects()->add_effect(
01061         new Projectile_effect(attacker, to, shnum));
01062 
01063   return Usecode_value(0);  // Not sure what this should be.
01064 }
01065 
01066 USECODE_INTRINSIC(get_lift)
01067 {
01068   // ?? Guessing rets. lift(item).
01069   Game_object *obj = get_item(parms[0]);
01070   Usecode_value u(obj ? Usecode_value(obj->get_lift())
01071           : Usecode_value(0));
01072   return(u);
01073 }
01074 
01075 USECODE_INTRINSIC(set_lift)
01076 {
01077   // ?? Guessing setlift(item, lift).
01078   Game_object *obj = get_item(parms[0]);
01079   if (obj)
01080     {
01081     Tile_coord t = obj->get_tile();
01082     int lift = parms[1].get_int_value();
01083     if (lift >= 0 && lift < 20)
01084       obj->move(t.tx, t.ty, lift);
01085     gwin->paint();
01086     gwin->show();
01087     modified_map = true;
01088     }
01089   return(no_ret);
01090 }
01091 
01092 USECODE_INTRINSIC(get_weather)
01093 {
01094   // Get_weather()
01095   return Usecode_value(gwin->get_effects()->get_weather());
01096 }
01097 
01098 USECODE_INTRINSIC(set_weather)
01099 {
01100   // Set_weather(i)
01101   Egg_object::set_weather(parms[0].get_int_value());
01102   return no_ret;
01103 }
01104 
01105 
01106 USECODE_INTRINSIC(sit_down)
01107 {
01108   // Sit_down(npc, chair).
01109   Game_object *nobj = get_item(parms[0]);
01110   Actor *npc = as_actor(nobj);
01111   if (!npc)
01112     return (no_ret);  // Doesn't look like an NPC.
01113   Game_object *chair = get_item(parms[1]);
01114   if (!chair)
01115     return (no_ret);
01116   npc->set_schedule_type(Schedule::sit, new Sit_schedule(npc, chair));
01117   return(no_ret);
01118 }
01119 
01120 USECODE_INTRINSIC(summon)
01121 {
01122   // summon(shape, flag??).  Create monster of desired shape.
01123 
01124   int shapenum = parms[0].get_int_value();
01125   Monster_info *info = ShapeID::get_info(shapenum).get_monster_info();
01126   if (!info)
01127     return Usecode_value(0);
01128   Tile_coord start = gwin->get_main_actor()->get_tile();
01129   Tile_coord dest = Map_chunk::find_spot(start, 5, shapenum, 0, 1,
01130       -1, gwin->is_main_actor_inside() ?
01131         Map_chunk::inside : Map_chunk::outside);
01132   if (dest.tx == -1)
01133     return Usecode_value(0);
01134   Monster_actor *monst = Monster_actor::create(shapenum, dest,
01135           Schedule::combat, Actor::friendly);
01136   return Usecode_value(monst);
01137 }
01138 
01139 /*
01140  *  Class to paint a shape centered.
01141  */
01142 class Paint_centered : public Paintable, public Game_singletons
01143   {
01144 protected:
01145   ShapeID *sid;     // ->shape.
01146   int x, y;     // Where to paint.
01147 public:
01148   Paint_centered(ShapeID *si) : sid(si)
01149     {
01150     Shape_frame *s = sid->get_shape();
01151           // Get coords. for centered view.
01152     x = (gwin->get_width() - s->get_width())/2 + s->get_xleft();
01153     y = (gwin->get_height() - s->get_height())/2 + s->get_yabove();
01154     }
01155   virtual void paint()
01156     {
01157     sid->paint_shape(x, y);
01158     }
01159   };
01160 /*
01161  *  Paint map.
01162  */
01163 class Paint_map : public Paint_centered
01164   {
01165   bool show_loc;
01166 public:
01167   Paint_map(ShapeID *s, bool loc) : Paint_centered(s), show_loc(loc)
01168     {  }
01169   virtual void paint()
01170     {
01171     Paint_centered::paint();
01172     if (show_loc)
01173       {   // mark location
01174       int xx, yy;
01175       Tile_coord t = gwin->get_main_actor()->get_tile();
01176       if (Game::get_game_type()==BLACK_GATE) {
01177         xx = (int)(t.tx/16.05 + 5 + 0.5);
01178         yy = (int)(t.ty/15.95 + 4 + 0.5);
01179       } else if (Game::get_game_type()==SERPENT_ISLE) {
01180         xx = (int)(t.tx/16.0 + 18 + 0.5);
01181         yy = (int)(t.ty/16.0 + 9.4 + 0.5);
01182       }
01183       Shape_frame *s = sid->get_shape();
01184       xx += x - s->get_xleft();
01185       yy += y - s->get_yabove();
01186       gwin->get_win()->fill8(255, 1, 5, xx, yy - 2);
01187       gwin->get_win()->fill8(255, 5, 1, xx - 2, yy);
01188       }
01189     }
01190   };
01191 
01192 USECODE_INTRINSIC(display_map)
01193 {
01194 
01195   //count all sextants in party
01196   Usecode_value v_357(-357), v650(650), v_359(-359);
01197   long sextants=count_objects(v_357, v650, v_359, v_359).get_int_value();
01198   bool loc = !gwin->is_main_actor_inside() && (sextants > 0);
01199   // Display map.
01200   ShapeID msid(game->get_shape("sprites/map"), 0, SF_SPRITES_VGA);
01201   Paint_map map(&msid, loc);
01202 
01203   int xx, yy;
01204   Get_click(xx, yy, Mouse::hand, 0, false, &map);
01205   gwin->paint();
01206   return(no_ret);
01207 }
01208 
01209 USECODE_INTRINSIC(si_display_map)
01210 {
01211   int mapnum = parms[0].get_int_value();
01212   int shapenum;
01213 
01214   switch (mapnum) {
01215     case 0: return UI_display_map(event,intrinsic,num_parms,parms);
01216     case 1: shapenum = 57; break;
01217     case 2: shapenum = 58; break;
01218     case 3: shapenum = 59; break;
01219     case 4: shapenum = 60; break;
01220     case 5: shapenum = 52; break;
01221     default: return no_ret;
01222   }
01223       
01224   // Display map.
01225   
01226   // Display map.
01227   ShapeID msid(shapenum, 0, SF_SPRITES_VGA);
01228   Paint_centered map(&msid);
01229   int xx, yy;
01230   Get_click(xx, yy, Mouse::hand, 0, false, &map);
01231   gwin->paint();
01232 
01233   return no_ret;
01234 }
01235 
01236 USECODE_INTRINSIC(kill_npc)
01237 {
01238   // kill_npc(npc).
01239   Game_object *item = get_item(parms[0]);
01240   Actor *npc = as_actor(item);
01241   if (npc)
01242     npc->die(0);
01243   modified_map = true;
01244   return (no_ret);
01245 }
01246 
01247 USECODE_INTRINSIC(roll_to_win)
01248 {
01249   // roll_to_win(attackpts, defendpts)
01250   int attack = parms[0].get_int_value();
01251   int defend = parms[1].get_int_value();
01252   return Usecode_value((int) Actor::roll_to_win(attack, defend));
01253 }
01254 
01255 USECODE_INTRINSIC(set_attack_mode)
01256 {
01257   // set_attack_mode(npc, mode).
01258   Actor *npc = as_actor(get_item(parms[0]));
01259   if (npc)
01260     npc->set_attack_mode((Actor::Attack_mode) 
01261           parms[1].need_int_value());
01262   return (no_ret);
01263 }
01264 
01265 USECODE_INTRINSIC(get_attack_mode)
01266 {
01267   // get_attack_mode(npc).
01268   Actor *npc = as_actor(get_item(parms[0]));
01269   if (npc)
01270     return Usecode_value((int) npc->get_attack_mode());
01271   return Usecode_value(0);
01272 }
01273 
01274 USECODE_INTRINSIC(set_opponent)
01275 {
01276   // set_opponent(npc, new_opponent).
01277   Actor *npc = as_actor(get_item(parms[0]));
01278   Game_object *opponent = get_item(parms[1]);
01279   if (npc && opponent)
01280     npc->set_target(opponent);
01281   return (no_ret);
01282 }
01283 
01284 USECODE_INTRINSIC(clone)
01285 {
01286   // clone(npc)
01287   Actor *npc = as_actor(get_item(parms[0]));
01288   if (npc)
01289     {
01290     modified_map = true;
01291     npc->set_alignment(Actor::friendly);
01292     npc->set_schedule_type(Schedule::combat);
01293     return Usecode_value(npc->clone());
01294     }
01295   return Usecode_value(0);
01296 }
01297 
01298 USECODE_INTRINSIC(get_oppressor)
01299 {
01300   // get_oppressor(npc) Returns 0-n, NPC # (0=avatar).
01301   Actor *npc = as_actor(get_item(parms[0]));
01302   return Usecode_value(npc ? npc->get_oppressor() : 0);
01303 }
01304 
01305 USECODE_INTRINSIC(set_oppressor)
01306 {
01307   // set_oppressor(npc, opp)
01308   Actor *npc = as_actor(get_item(parms[0]));
01309   Actor *opp = as_actor(get_item(parms[1]));
01310   if (npc && opp)
01311     {
01312     if (opp == gwin->get_main_actor())
01313       npc->set_oppressor(0);
01314     else
01315       npc->set_oppressor(opp->get_npc_num());
01316           // Need this for SI ListField training:
01317     npc->set_target(opp);
01318     }
01319   return no_ret;
01320 }
01321 
01322 USECODE_INTRINSIC(get_weapon)
01323 {
01324   // get_weapon(npc).  Returns shape.
01325   Actor *npc = as_actor(get_item(parms[0]));
01326   if (npc)
01327     {
01328     int shape, points;
01329     if (npc->get_weapon(points, shape))
01330       return Usecode_value(shape);
01331     }
01332   return Usecode_value(0);
01333 }
01334 
01335 USECODE_INTRINSIC(display_area)
01336 {
01337   // display_area(tilepos) - used for crystal balls.
01338   int size = parms[0].get_array_size();
01339   if (size >= 3)
01340     {
01341     int tx = parms[0].get_elem(0).get_int_value();
01342     int ty = parms[0].get_elem(1).get_int_value();
01343     int unknown = parms[0].get_elem(2).get_int_value();
01344           // Figure in tiles.
01345     int tw = gwin->get_width()/c_tilesize, 
01346         th = gwin->get_height()/c_tilesize;
01347     gwin->clear_screen(); // Fill with black.
01348     Shape_frame *sprite = ShapeID(10, 0, SF_SPRITES_VGA).get_shape();
01349           // Center it.
01350     int topx = (gwin->get_width() - sprite->get_width())/2,
01351         topy = (gwin->get_height() - sprite->get_height())/2;
01352           // Get area to fill.
01353     int x = topx, y = topy, w = sprite->get_width(),
01354           h = sprite->get_height();
01355     if (w > gwin->get_width())
01356       { x = 0; w = gwin->get_width(); }
01357     if (h > gwin->get_height())
01358       { y = 0; h = gwin->get_height(); }
01359     int save_dungeon = gwin->is_in_dungeon();
01360     gwin->set_in_dungeon(0);  // Disable dungeon.
01361           // Paint game area.
01362     gwin->paint_map_at_tile(x, y, w, h, tx - tw/2, ty - th/2, 4);
01363           // Paint sprite #10 (black gate!)
01364           //   over it, transparently.
01365     sman->paint_shape(topx + sprite->get_xleft(),
01366         topy + sprite->get_yabove(), sprite, 1);
01367     gwin->set_in_dungeon(save_dungeon);
01368     gwin->show();
01369           // Wait for click.
01370     Get_click(x, y, Mouse::hand);
01371     gwin->paint();    // Repaint normal area.
01372     }
01373   return (no_ret);
01374 }
01375 
01376 USECODE_INTRINSIC(wizard_eye)
01377 {
01378   // wizard_eye(#ticks, ??);
01379   extern void Wizard_eye(long);
01380           // Let's give 50% longer.
01381   Wizard_eye(parms[0].get_int_value()*(3*gwin->get_std_delay())/2);
01382   return no_ret;
01383 }
01384 
01385 USECODE_INTRINSIC(resurrect)
01386 {
01387   // resurrect(body).  Returns actor if successful.
01388   Game_object *body = get_item(parms[0]);
01389   int npc_num = body ? body->get_live_npc_num() : -1;
01390   if (npc_num < 0)
01391     return Usecode_value((Game_object*) NULL);
01392   Actor *actor = gwin->get_npc(npc_num);
01393   if (actor)
01394     {     // Want to resurrect after returning.
01395     Usecode_script *scr = new Usecode_script(body);
01396     (*scr) << Ucscript::resurrect;
01397     scr->start();
01398     modified_map = true;
01399     }
01400   return Usecode_value(actor);
01401 }
01402 
01403 USECODE_INTRINSIC(get_body_npc)
01404 {
01405   // get_body_npc(body).  Returns npc # (negative).
01406   Game_object *obj = get_item(parms[0]);
01407   int num = obj ? obj->get_live_npc_num() : -1;
01408   return Usecode_value(num > 0 ? -num : 0);
01409 }
01410 
01411 USECODE_INTRINSIC(add_spell)
01412 {
01413   // add_spell(spell# (0-71), ??, spoolbook).
01414   // Returns 0 if book already has that spell.
01415   Game_object *obj = get_item(parms[2]);
01416   if (!obj || obj->get_info().get_shape_class() != Shape_info::spellbook)
01417     return Usecode_value(0);
01418   Spellbook_object *book = (Spellbook_object *) (obj);
01419   if (!book)
01420     {
01421     cout << "Add_spell - Not a spellbook!" << endl;
01422     return Usecode_value(0);
01423     }
01424   return Usecode_value(book->add_spell(parms[0].get_int_value()));
01425 }
01426 
01427 USECODE_INTRINSIC(sprite_effect)
01428 {
01429   // Display animation from sprites.vga.
01430   // show_sprite(sprite#, tx, ty, dx, dy, frame, length??);
01431           // ++++++Pass frame, length+++++++
01432   gwin->get_effects()->add_effect(
01433     new Sprites_effect(parms[0].get_int_value(),
01434     Tile_coord(parms[1].get_int_value(), parms[2].get_int_value(),
01435                   0),
01436       parms[3].get_int_value(), parms[4].get_int_value()));
01437   return(no_ret);
01438 }
01439 
01440 USECODE_INTRINSIC(obj_sprite_effect)
01441 {
01442   // obj_sprite_effect(obj, sprite#, -xoff, -yoff, dx, dy, 
01443   //            frame, length??)
01444   Game_object *obj = get_item(parms[0]);
01445   if (obj)
01446           // ++++++Pass frame, length+++++++
01447     gwin->get_effects()->add_effect(
01448       new Sprites_effect(parms[1].get_int_value(), obj,
01449       -parms[2].get_int_value(), -parms[3].get_int_value(),
01450       parms[4].get_int_value(), parms[5].get_int_value()));
01451   return(no_ret);
01452 }
01453 
01454 USECODE_INTRINSIC(explode)
01455 {
01456   // Explode(obj??, item-to-explode, powder-keg-shape).
01457   Game_object *exp = get_item(parms[1]);
01458   if (!exp)
01459     return Usecode_value(0);
01460           // Use container if it's in one.
01461   Tile_coord pos = exp->get_outermost()->get_tile();
01462           // Sprite 1,4,5 look like explosions.
01463   gwin->get_effects()->add_effect(new Explosion_effect(pos, exp));
01464   return Usecode_value(1);
01465 }
01466 
01467 USECODE_INTRINSIC(book_mode)
01468 {
01469   // Display book or scroll.
01470   Text_gump *gump;
01471   Game_object *obj = get_item(parms[0]);
01472   if (!obj)
01473     {
01474     return(no_ret);
01475     }
01476 
01477   // check for avatar read here
01478   bool do_serp = gwin->get_main_actor()->get_flag(Obj_flags::read) == false;
01479   
01480   if (obj->get_shapenum() == 707)   // Serpentine Scroll - Make SI only???
01481     gump = new Scroll_gump(do_serp);
01482   else if (obj->get_shapenum() == 705)  // Serpentine Book - Make SI only???
01483     gump = new Book_gump(do_serp);
01484   else if (obj->get_shapenum() == 797)
01485     gump = new Scroll_gump();
01486   else
01487     gump = new Book_gump();
01488   set_book(gump);
01489   return(no_ret);
01490 }
01491 
01492 USECODE_INTRINSIC(stop_time)
01493 { // stop_time(.25 secs).
01494 
01495   int length = parms[0].get_int_value();
01496   gwin->set_time_stopped(length*250);
01497   return no_ret;
01498 }
01499 
01500 USECODE_INTRINSIC(cause_light)
01501 {
01502   // Cause_light(game_minutes??)
01503 
01504   gwin->add_special_light(parms[0].get_int_value());
01505   return no_ret;
01506 }
01507 
01508 USECODE_INTRINSIC(get_barge)
01509 {
01510   // get_barge(obj) - returns barge object is part of or lying on.
01511 
01512   Game_object *obj = get_item(parms[0]);
01513   if (!obj)
01514     return Usecode_value((Game_object*) NULL);
01515   return Usecode_value(Get_barge(obj));
01516 }
01517 
01518 USECODE_INTRINSIC(earthquake)
01519 {
01520   int len = parms[0].get_int_value();
01521   gwin->get_tqueue()->add(Game::get_ticks() + 10,
01522     new Earthquake(len), (long) this);
01523   return(no_ret);
01524 }
01525 
01526 USECODE_INTRINSIC(is_pc_female)
01527 {
01528   // Is player female?
01529   Usecode_value u(gwin->get_main_actor()->get_type_flag(Actor::tf_sex));
01530   return(u);
01531 }
01532 
01533 USECODE_INTRINSIC(armageddon)
01534 {
01535   int cnt = gwin->get_num_npcs();
01536   Rectangle screen = gwin->get_win_tile_rect();
01537   for (int i = 1; i < cnt; i++) // Most everyone dies.
01538     {     // Leave LB, Batlin, Hook.
01539     Actor *npc = gwin->get_npc(i);
01540     if (npc && i != 26 && i != 23 && npc->get_shapenum() != 506 &&
01541         !npc->is_dead())
01542       {
01543       const char *text[] = {"Aiiiieee!", "Noooo!", "#!?*#%!"};
01544       const int numtext = sizeof(text)/sizeof(text[0]);
01545       Tile_coord loc = npc->get_tile();
01546       if (screen.has_point(loc.tx, loc.ty))
01547         npc->say(text[rand()%numtext]);
01548       npc->die(0);
01549       }
01550     }
01551   Actor_vector vec;   // Get any monsters nearby.
01552   gwin->get_main_actor()->find_nearby_actors(vec, c_any_shapenum, 40);
01553   for (Actor_vector::const_iterator it = vec.begin(); it != vec.end();
01554                   ++it)
01555     {
01556     Actor *act = *it;
01557     if (act->is_monster())  // Assume only Avatar can cast this.
01558       act->die(gwin->get_main_actor());
01559     }
01560   gwin->armageddon = true;
01561   return no_ret;
01562 }
01563 
01564 USECODE_INTRINSIC(halt_scheduled)
01565 {
01566   // Halt_scheduled(item)
01567   Game_object *obj = get_item(parms[0]);
01568   if (obj)
01569     Usecode_script::terminate(obj);
01570   return(no_ret);
01571 }
01572 
01573 USECODE_INTRINSIC(lightning)
01574 {
01575           // 1 sec. is long enough for 1 flash.
01576   gwin->get_effects()->add_effect(new Lightning_effect(1000));
01577   return no_ret;
01578 }
01579 
01580 USECODE_INTRINSIC(get_array_size)
01581 {
01582   int cnt;
01583   if (parms[0].is_array())  // An array?  We might return 0.
01584     cnt = parms[0].get_array_size();
01585   else        // Not an array?  Usecode wants a 1.
01586     cnt = 1;
01587   Usecode_value u(cnt);
01588   return(u);
01589 }
01590 
01591 USECODE_INTRINSIC(mark_virtue_stone)
01592 {
01593   Game_object *obj = get_item(parms[0]);
01594   if (obj->get_info().get_shape_class() == Shape_info::virtue_stone)
01595     {
01596     Virtue_stone_object *vs = (Virtue_stone_object *) (obj);
01597     vs->set_pos(obj->get_outermost()->get_tile());
01598     }
01599   return no_ret;
01600 }
01601 
01602 USECODE_INTRINSIC(recall_virtue_stone)
01603 {
01604   Game_object *obj = get_item(parms[0]);
01605   if (obj->get_info().get_shape_class() == Shape_info::virtue_stone)
01606     {
01607     Virtue_stone_object *vs = (Virtue_stone_object *) (obj);
01608     gumpman->close_all_gumps();
01609           // Pick it up if necessary.
01610     if (!obj->get_owner())
01611       {   // Go through whole party.
01612       obj->remove_this(1);
01613       Usecode_value party = get_party();
01614       int cnt = party.get_array_size();
01615       int i;
01616       for (i = 0; i < cnt; i++)
01617         {
01618         Game_object *npc = get_item(party.get_elem(i));
01619         if (npc && npc->add(obj))
01620           break;
01621         }
01622       if (i == cnt) // Failed?  Force it on Avatar.
01623         gwin->get_main_actor()->add(obj, 1);
01624       }
01625     Tile_coord t = vs->get_pos();
01626     if (t.tx > 0 || t.ty > 0)
01627       gwin->teleport_party(t);
01628     }
01629   return no_ret;
01630 }
01631 
01632 USECODE_INTRINSIC(apply_damage)
01633 {
01634   // apply_damage(??str?, hps, ??type?, NPC);
01635   int hps = parms[1].get_int_value();
01636   Actor *npc = as_actor(get_item(parms[3]));
01637   if (npc)
01638     npc->reduce_health(hps);
01639   return Usecode_value(1);  // ?? Guessing.
01640 }
01641 
01642 USECODE_INTRINSIC(is_pc_inside)
01643 {
01644   Usecode_value u(gwin->is_main_actor_inside());
01645   return(u);
01646 }
01647 
01648 USECODE_INTRINSIC(get_timer)
01649 {
01650   int tnum = parms[0].get_int_value();
01651   int ret;
01652   if (tnum >= 0 && tnum < (int)(sizeof(timers)/sizeof(timers[0])))
01653           // Return 0 if not set.
01654     ret = timers[tnum] > 0 ?
01655       (gclock->get_total_hours() - timers[tnum]) : 0;
01656   else
01657     {
01658     cerr << "Attempt to use invalid timer " << tnum << endl;
01659     ret = 0;
01660     }
01661   return Usecode_value(ret);
01662 }
01663 
01664 USECODE_INTRINSIC(set_timer)
01665 {
01666   int tnum = parms[0].get_int_value();
01667   if (tnum >= 0 && tnum < (int)(sizeof(timers)/sizeof(timers[0])))
01668     timers[tnum] = gclock->get_total_hours();
01669   else
01670     cerr << "Attempt to use invalid timer " << tnum << endl;
01671   return(no_ret);
01672 }
01673 
01674 USECODE_INTRINSIC(wearing_fellowship)
01675 {
01676   Game_object *obj = gwin->get_main_actor()->get_readied(Actor::neck);
01677   if (obj && obj->get_shapenum() == 955 && obj->get_framenum() == 1)
01678     return Usecode_value(1);
01679   else
01680     return Usecode_value(0);
01681 }
01682 
01683 USECODE_INTRINSIC(mouse_exists)
01684 {
01685   Usecode_value u(1);
01686   return(u);
01687 }
01688 
01689 USECODE_INTRINSIC(get_speech_track)
01690 {
01691   // Get speech track set by 0x74 or 0x8f.
01692   return Usecode_value(speech_track);
01693 }
01694 
01695 USECODE_INTRINSIC(flash_mouse)
01696 {
01697   // flash_mouse(code)
01698   Mouse::Mouse_shapes shape;
01699   switch (parms[0].need_int_value())
01700     {
01701   case 2:
01702     shape = Mouse::outofrange; break;
01703   case 3:
01704     shape = Mouse::outofammo; break;
01705   case 4:
01706     shape = Mouse::tooheavy; break;
01707   case 5:
01708     shape = Mouse::wontfit; break;
01709   case 0:
01710   case 1:
01711   default:
01712     shape = Mouse::redx; break;
01713     }
01714   Mouse::mouse->flash_shape(shape);
01715   return (no_ret);
01716 }
01717 
01718 USECODE_INTRINSIC(get_item_frame_rot)
01719 {
01720   // Same as get_item_frame, but (guessing!) include rotated bit.
01721   Game_object *obj = get_item(parms[0]);
01722   return Usecode_value(obj ? obj->get_framenum() : 0);
01723 }
01724 
01725 USECODE_INTRINSIC(set_item_frame_rot)
01726 { // Set entire frame, including rotated bit.
01727   set_item_frame(get_item(parms[0]), parms[1].get_int_value(), 0, 1);
01728   return(no_ret);
01729 }
01730 
01731 USECODE_INTRINSIC(on_barge)
01732 {
01733   // Only used once for BG, in usecode for magic-carpet.
01734   // For SI, used for turtle.
01735   // on_barge()
01736   Barge_object *barge = Get_barge(gwin->get_main_actor());
01737   if (barge)
01738     {     // See if party is on barge.
01739     Rectangle foot = barge->get_tile_footprint();
01740     Actor *party[9];
01741     int cnt = gwin->get_party(party, 1);
01742     for (int i = 0; i < cnt; i++)
01743       {
01744       Actor *act = party[i];
01745       Tile_coord t = act->get_tile();
01746       if (!foot.has_point(t.tx, t.ty))
01747         return Usecode_value(0);
01748       }
01749           // Force 'gather()' for turtle.
01750     if (Game::get_game_type() == SERPENT_ISLE)
01751       barge->done();
01752     return Usecode_value(1);
01753     } 
01754   return Usecode_value(0);
01755 //  return Usecode_value(1);
01756 }
01757 
01758 USECODE_INTRINSIC(get_container)
01759 {
01760   // Takes itemref, returns container.
01761   Game_object *obj = get_item(parms[0]);
01762   Usecode_value u((Game_object *) NULL);
01763   if (obj)
01764     u = Usecode_value(obj->get_owner());
01765   return(u);
01766 }
01767 
01768 USECODE_INTRINSIC(remove_item)
01769 {
01770   // Think it's 'delete object'.
01771   remove_item(get_item(parms[0]));
01772   modified_map = true;
01773   return no_ret;
01774 }
01775 
01776 USECODE_INTRINSIC(reduce_health)
01777 {
01778   // Reduce_health(npc, amount, ??property/flags??0?).
01779   Actor *npc = as_actor(get_item(parms[0]));
01780   if (npc)      // Dies if health goes too low.
01781     npc->reduce_health(parms[1].get_int_value());
01782   return no_ret;
01783 }
01784 
01785 /*
01786  *  Convert Usecode spot # to ours (or -1 if not found).
01787  */
01788 
01789 static int Get_spot(int ucspot)
01790   {
01791   int spot;
01792   switch (ucspot)
01793     {
01794   case 1:
01795     spot = Actor::lhand; break;
01796   case 2:
01797     spot = Actor::rhand; break;
01798   case 3:
01799     spot = Actor::neck; break;
01800   case 5:
01801     spot = Actor::hands2_spot; break;
01802   case 6:
01803     spot = Actor::lfinger; break;
01804   case 7:
01805     spot = Actor::rfinger; break;
01806   case 9:
01807     spot = Actor::head; break; 
01808   case 11:
01809     spot = Actor::belt; break;
01810   default:
01811     cerr << "Readied: spot #" << ucspot <<
01812             " not known yet" << endl;
01813     spot = -1;
01814     }
01815   return spot;
01816   }
01817 
01818 USECODE_INTRINSIC(is_readied)
01819 {
01820   // is_readied(npc, where, itemshape, frame (-359=any)).
01821   // Where:
01822   //   1=weapon hand, 
01823   //   2=other hand,
01824   //   6=one finger, 
01825   //   7=other finger,
01826   //   9=head
01827   //  20=???
01828 
01829   Actor *npc = as_actor(get_item(parms[0]));
01830   if (!npc)
01831     return Usecode_value(0);
01832   int where = parms[1].get_int_value();
01833   int shnum = parms[2].get_int_value();
01834   int frnum = parms[3].get_int_value();
01835           // Spot defined in Actor class.
01836   int spot = Get_spot(where);
01837   if (spot >= 0)
01838     {     // See if it's the right one.
01839     Game_object *obj = npc->get_readied(spot);
01840     if (obj && obj->get_shapenum() == shnum &&
01841         (frnum == c_any_framenum || obj->get_framenum() == frnum))
01842       return Usecode_value(1);
01843     }
01844   return Usecode_value(0);
01845 }
01846 
01847 USECODE_INTRINSIC(get_readied)
01848 {
01849   // get_readied(npc, where)
01850   // Where:
01851   //   1=weapon hand, 
01852   //   2=other hand,
01853   //   6=one finger, 
01854   //   7=other finger,
01855   //   9=head
01856   //  11=belt
01857   //  20=???
01858 
01859   Actor *npc = as_actor(get_item(parms[0]));
01860   if (!npc)
01861     return Usecode_value(0);
01862   int where = parms[1].get_int_value();
01863           // Spot defined in Actor class.
01864   int spot = Get_spot(where);
01865   if (spot >= 0)
01866     return Usecode_value(npc->get_readied(spot));
01867   return Usecode_value(0);
01868 }
01869 
01870 USECODE_INTRINSIC(restart_game)
01871 {
01872   // Think it's 'restart game'.  
01873   // Happens if you die before leaving trinsic.
01874   Audio::get_ptr()->stop_music();
01875   quitting_time = QUIT_TIME_RESTART;    // Quit & restart.
01876   return(no_ret);
01877 }
01878 
01879 USECODE_INTRINSIC(start_speech)
01880 {
01881   // Start_speech(num).  Also sets speech_track.
01882   bool okay = false;
01883   speech_track = parms[0].get_int_value();
01884   if (speech_track >= 0)
01885     okay = Audio::get_ptr()->start_speech(speech_track);
01886   if (!okay)      // Failed?  Clear faces.  (Fixes SI).
01887     init_conversation();
01888   return(Usecode_value(okay ? 1 : 0));
01889 }
01890 
01891 USECODE_INTRINSIC(is_water)
01892 {
01893   // Is_water(pos).
01894   int size = parms[0].get_array_size();
01895   if (size >= 3)
01896     {
01897     Tile_coord t(parms[0].get_elem(0).get_int_value(),
01898            parms[0].get_elem(1).get_int_value(),
01899            parms[0].get_elem(2).get_int_value());
01900           // Didn't click on an object?
01901     int x = (t.tx - gwin->get_scrolltx())*c_tilesize,
01902         y = (t.ty - gwin->get_scrollty())*c_tilesize;
01903     if (t.tz != 0 || gwin->find_object(x, y))
01904       return Usecode_value(0);
01905     ShapeID sid = gwin->get_flat(x, y);
01906     if (sid.is_invalid())
01907       return Usecode_value(0);
01908     Shape_info& info = sid.get_info();
01909     return Usecode_value(info.is_water());
01910     }
01911   return Usecode_value(0);
01912 }
01913 
01914 USECODE_INTRINSIC(run_endgame)
01915 {
01916   Audio::get_ptr()->stop_sound_effects();
01917   game->end_game(parms[0].get_int_value() != 0);
01918   // If successful enable menu entry and play credits afterwards
01919   if(parms[0].get_int_value() != 0) {
01920     std::ofstream endgameflg;
01921                 U7open(endgameflg, "<SAVEGAME>/endgame.flg");
01922                 endgameflg.close();
01923     game->show_credits();
01924   }
01925   quitting_time = QUIT_TIME_YES;
01926   return(no_ret);
01927 }
01928 
01929 USECODE_INTRINSIC(fire_cannon)
01930 {
01931   // fire_cannon(cannon, dir, ballshape, dist?, cannonshape, cannonshape)
01932 
01933   Game_object *cannon = get_item(parms[0]);
01934           // Get direction (0,2,4, or 6).
01935   int dir = parms[1].get_int_value();
01936   dir = dir/2;      // 0, 1, 2, 3.
01937   int ball = parms[2].get_int_value();
01938   int dist = parms[3].get_int_value();
01939   int cshape = parms[4].get_int_value();
01940   Tile_coord pos = cannon->get_tile();
01941   short blastoff[8] = {-2, -5, 1, -2, -2, 1, -5, -2};
01942   Tile_coord blastpos = pos + Tile_coord(
01943         blastoff[2*dir], blastoff[2*dir + 1], 0);
01944           // Sprite 5 is a small explosion.
01945   gwin->get_effects()->add_effect(new Sprites_effect(5, blastpos));
01946   Tile_coord dest = pos;
01947   switch (dir)      // Figure where to aim.
01948     {
01949   case 0: dest.ty -= dist; break;
01950   case 1: dest.tx += dist; break;
01951   case 2: dest.ty += dist; break;
01952   case 3: dest.tx -= dist; break;
01953     }
01954           // Shoot cannonball.
01955   gwin->get_effects()->add_effect(
01956       new Projectile_effect(blastpos, dest, ball, cshape));
01957   return no_ret;
01958 }
01959 
01960 USECODE_INTRINSIC(nap_time)
01961 {
01962   // nap_time(bed)
01963   Game_object *bed = get_item(parms[0]);
01964   if (!bed)
01965     return no_ret;
01966           // !!! Seems 622 handles sleeping.
01967   Actor_vector npcs;    // See if bed is occupied by an NPC.
01968   int cnt = bed->find_nearby_actors(npcs, c_any_shapenum, 0);
01969   if (cnt > 0)
01970     {
01971     Actor_vector::const_iterator it;
01972     for (it = npcs.begin(); it != npcs.end(); ++it)
01973       {
01974       Game_object *npc = *it;
01975       int zdiff = npc->get_lift() - bed->get_lift();
01976       if (npc != gwin->get_main_actor() &&
01977           (npc->get_framenum()&0xf) == Actor::sleep_frame &&
01978             zdiff <= 2 && zdiff >= -2)
01979         break;  // Found one.
01980       }
01981     if (it != npcs.end())
01982       {   // Show party member's face.
01983       int party_cnt = partyman->get_count();
01984       int npcnum = party_cnt ? partyman->get_member(
01985             rand()%party_cnt) : 356;
01986       Usecode_value actval(-npcnum), frval(0);
01987       show_npc_face(actval, frval);
01988       conv->show_npc_message(item_names[first_bed_occupied +
01989             rand()%num_bed_occupied]);
01990       remove_npc_face(actval);
01991       gwin->get_main_actor()->set_schedule_type(
01992             Schedule::follow_avatar);
01993       return no_ret;
01994       }
01995     }
01996   Schedule *sched = gwin->get_main_actor()->get_schedule();
01997   if (sched)      // Tell (sleep) sched. to use bed.
01998     sched->set_bed(bed);
01999           // Give him a chance to get there (at
02000           //   most 5 seconds.)
02001   Wait_for_arrival(gwin->get_main_actor(), bed->get_tile(),
02002                 5000);
02003   call_usecode(0x622, bed, double_click);
02004   return(no_ret);
02005 }
02006 
02007 USECODE_INTRINSIC(advance_time)
02008 {
02009   // Incr. clock by (parm[0]*.04min.).
02010   gclock->increment(parms[0].get_int_value()/25);
02011   return(no_ret);
02012 }
02013 
02014 USECODE_INTRINSIC(in_usecode)
02015 {
02016   // in_usecode(item):  Return 1 if executing usecode on parms[0].
02017 
02018   Game_object *obj = get_item(parms[0]);
02019   if (!obj)
02020     return Usecode_value(0);
02021   return Usecode_value(Usecode_script::find(obj) != 0);
02022 }
02023 
02024 USECODE_INTRINSIC(call_guards)
02025 {
02026   // Attack thieving Avatar.
02027   gwin->call_guards();
02028   return no_ret;
02029 }
02030 
02031 USECODE_INTRINSIC(attack_avatar)
02032 {
02033   // Attack thieving Avatar.
02034   gwin->attack_avatar();
02035   return no_ret;
02036 }
02037 
02038 USECODE_INTRINSIC(path_run_usecode)
02039 {
02040   // exec(loc(x,y,z)?, usecode#, itemref, eventid).
02041   // Think it should have Avatar walk path to loc, return 0
02042   //  if he can't get there (and return), 1 if he can.
02043   Usecode_value ava(gwin->get_main_actor());
02044   return Usecode_value(path_run_usecode(ava, parms[0], parms[1],
02045         parms[2], parms[3],
02046           // SI:  Look for free spot. (Guess).
02047       Game::get_game_type() == SERPENT_ISLE));
02048 }
02049 
02050 USECODE_INTRINSIC(close_gumps)
02051 {
02052   if (!gwin->is_dragging()) // NOT while dragging stuff.
02053     gumpman->close_all_gumps();
02054   return(no_ret);
02055 }
02056 
02057 USECODE_INTRINSIC(in_gump_mode)
02058 {
02059                 // No persistent
02060   return Usecode_value(gumpman->showing_gumps(true));
02061 }
02062 
02063 USECODE_INTRINSIC(is_not_blocked)
02064 {
02065   // Is_not_blocked(tile, shape, frame (or -359).
02066   Usecode_value fail(0);
02067           // Parm. 0 should be tile coords.
02068   Usecode_value& pval = parms[0];
02069   if (pval.get_array_size() < 3)
02070     return fail;
02071   Tile_coord tile(pval.get_elem(0).get_int_value(),
02072       pval.get_elem(1).get_int_value(),
02073       pval.get_elem(2).get_int_value());
02074   int shapenum = parms[1].get_int_value();
02075   int framenum = parms[2].get_int_value();
02076           // Find out about given shape.
02077   Shape_info& info = ShapeID::get_info(shapenum);
02078   Rectangle footprint(
02079     tile.tx - info.get_3d_xtiles(framenum) + 1,
02080     tile.ty - info.get_3d_ytiles(framenum) + 1,
02081     info.get_3d_xtiles(framenum), info.get_3d_ytiles(framenum));
02082   int new_lift;
02083   int blocked = Map_chunk::is_blocked(
02084     info.get_3d_height(), tile.tz, 
02085     footprint.x, footprint.y, footprint.w, footprint.h,
02086     new_lift, MOVE_ALL_TERRAIN, 1);
02087           // Okay?
02088   if (!blocked && new_lift == tile.tz)
02089     return Usecode_value(1);
02090   else
02091     return Usecode_value(0);
02092 }
02093 
02094 USECODE_INTRINSIC(direction_from)
02095 {
02096   // ?Direction from parm[0] -> parm[1].
02097   // Rets. 0-7, with 0 = North, 1 = Northeast, etc.
02098   // Same as 0x1a??
02099   Usecode_value u=find_direction(parms[0], parms[1]);
02100   return(u);
02101 }
02102 
02103 /*
02104  *  Test for a 'moving barge' flag.
02105  */
02106 
02107 static int Is_moving_barge_flag
02108   (
02109   int fnum
02110   )
02111   {
02112   if (Game::get_game_type() == BLACK_GATE)
02113     {
02114     return fnum == (int) Obj_flags::on_moving_barge ||
02115       fnum == (int) Obj_flags::in_motion;
02116     }
02117   else        // SI.
02118     {
02119     return fnum == (int) Obj_flags::si_on_moving_barge ||
02120           // Ice raft needs this one:
02121       fnum == (int) Obj_flags::on_moving_barge ||
02122       fnum == (int) Obj_flags::in_motion;
02123     }
02124   }
02125 
02126 USECODE_INTRINSIC(get_item_flag)
02127 {
02128   // Get npc flag(item, flag#).
02129   Game_object *obj = get_item(parms[0]);
02130   if (!obj)
02131     return Usecode_value(0);
02132   int fnum = parms[1].get_int_value();
02133           // Special cases:
02134   if (Is_moving_barge_flag(fnum))
02135     {     // Test for moving barge.
02136     Barge_object *barge;
02137     if (!gwin->get_moving_barge() || !(barge = Get_barge(obj)))
02138       return Usecode_value(0);
02139     return Usecode_value(barge == gwin->get_moving_barge());
02140     }
02141   else if (fnum == (int) Obj_flags::okay_to_land)
02142     {     // Okay to land flying carpet?
02143     Barge_object *barge = Get_barge(obj);
02144     if (!barge)
02145       return Usecode_value(0);
02146     return Usecode_value(barge->okay_to_land());
02147     }
02148   else if (fnum == (int) Obj_flags::cant_die)
02149     {
02150     Monster_info *inf = obj->get_info().get_monster_info();
02151     return Usecode_value(inf != 0 && inf->cant_die());
02152     }
02153           // +++++0x18 is used in testing for
02154           //   blocked gangplank. What is it?????
02155   else if (fnum == 0x18 && Game::get_game_type() == BLACK_GATE)
02156     return Usecode_value(1);
02157   else if (fnum == (int) Obj_flags::in_dungeon)
02158     return Usecode_value(obj == gwin->get_main_actor() &&
02159           gwin->is_in_dungeon());
02160   else if (fnum == 0x14)    // Must be the sailor, as this is used
02161           //   to check for Ferryman.
02162     return Usecode_value(sailor);
02163   Usecode_value u(obj->get_flag(fnum) != 0);
02164   return(u);
02165 }
02166 
02167 USECODE_INTRINSIC(set_item_flag)
02168 {
02169   // Set npc flag(item, flag#).
02170   Game_object *obj = get_item(parms[0]);
02171   int flag = parms[1].get_int_value();
02172   if (!obj)
02173     return no_ret;
02174   switch (flag)
02175     {
02176   case Obj_flags::dont_move:
02177     obj->set_flag(flag);
02178           // Get out of combat mode.
02179     if (obj == gwin->get_main_actor() && 
02180       Game::get_game_type() == SERPENT_ISLE &&
02181               gwin->in_combat())
02182       gwin->toggle_combat();
02183           // Show change in status.
02184     gwin->set_all_dirty();
02185     break;
02186   case Obj_flags::invisible:
02187     if (as_actor(obj))  // Only NPC's for now.
02188       {
02189       obj->set_flag(flag);
02190       gwin->add_dirty(obj);
02191       }
02192     break;
02193   case 0x14:      // The sailor (Ferryman).
02194     sailor = obj;
02195   default:
02196     obj->set_flag(flag);
02197     if (Is_moving_barge_flag(flag))
02198       {   // Set barge in motion.
02199       Barge_object *barge = Get_barge(obj);
02200       if (barge)
02201         gwin->set_moving_barge(barge);
02202       }
02203       break;
02204     }
02205   return(no_ret);
02206 }
02207 
02208 USECODE_INTRINSIC(clear_item_flag)
02209 {
02210   // Clear npc flag(item, flag#).
02211   Game_object *obj = get_item(parms[0]);
02212   int flag = parms[1].get_int_value();
02213   if (obj)
02214     {
02215     obj->clear_flag(flag);
02216     if (flag == Obj_flags::dont_move)
02217       { // Show change in status.
02218       show_pending_text();  // Fixes Lydia-tatoo.
02219       gwin->set_all_dirty();
02220       }
02221     else if (Is_moving_barge_flag(flag))
02222       { // Stop barge object is on or part of.
02223       Barge_object *barge = Get_barge(obj);
02224       if (barge && barge == gwin->get_moving_barge())
02225         gwin->set_moving_barge(0);
02226       }
02227     else if (flag == 0x14)    // Handles Ferryman
02228       sailor = 0;
02229     }
02230   return(no_ret);
02231 }
02232 
02233 USECODE_INTRINSIC(set_path_failure)
02234 {
02235   // set_path_failure(fun, itemref, eventid) for the last NPC in
02236   //  a path_run_usecode() call.
02237 
02238   int fun = parms[0].get_int_value(),
02239       eventid = parms[2].get_int_value();
02240   Game_object *item = get_item(parms[1]);
02241   if (path_npc && item)   // Set in path_run_usecode().
02242     {
02243     If_else_path_actor_action *action = 
02244       path_npc->get_action() ?
02245       path_npc->get_action()->as_usecode_path() : 0;
02246     if (action)   // Set in in path action.
02247       action->set_failure(
02248         new Usecode_actor_action(fun, item, eventid));
02249     }
02250   return no_ret;
02251 }
02252 
02253 USECODE_INTRINSIC(fade_palette)
02254 {
02255   // Fade(cycles?, ??(always 1), in_out (0=fade to black, 1=fade in)).
02256   int cycles = parms[0].get_int_value();
02257   int inout = parms[2].get_int_value();
02258   if (inout == 0)
02259     show_pending_text();  // Make sure prev. text was seen.
02260   gwin->get_pal()->fade(cycles, inout);
02261   return(no_ret);
02262 }
02263 
02264 USECODE_INTRINSIC(get_party_list2)
02265 {
02266   // Return party.  Same as 0x23
02267   // Probably returns a list of everyone with (or without) some flag
02268   // List of live chars? Dead chars?
02269   Usecode_value u(get_party());
02270   return(u);
02271 }
02272 
02273 USECODE_INTRINSIC(set_camera)
02274 {
02275   // Set_camera(actor)
02276   Actor *actor = as_actor(get_item(parms[0]));
02277   if (actor)
02278     gwin->set_camera_actor(actor);
02279   return no_ret;
02280 }
02281 
02282 USECODE_INTRINSIC(in_combat)
02283 {
02284   // Are we in combat mode?
02285   return Usecode_value(gwin->in_combat());
02286 }
02287 
02288 USECODE_INTRINSIC(center_view)
02289 {
02290   // Center view around given item.
02291   Game_object *obj = get_item(parms[0]);
02292   if (obj)
02293     {
02294     Tile_coord t = obj->get_tile();
02295     gwin->center_view(t);
02296     activate_cached(t); // Mar-10-01 - For Test of Love.
02297     }
02298   return no_ret;
02299 }
02300 
02301 USECODE_INTRINSIC(get_dead_party)
02302 {
02303   // Return list of dead companions' bodies.
02304   int cnt = partyman->get_dead_count();
02305   Usecode_value ret(cnt, 0);
02306   for (int i = 0; i < cnt; i++)
02307     {
02308     Game_object *body = gwin->get_body(
02309           partyman->get_dead_member(i));
02310           // Body within 50 tiles (a guess)?
02311     if (body && body->distance(gwin->get_main_actor()) < 50)
02312       {
02313       Usecode_value v(body);
02314       ret.put_elem(i, v);
02315       }
02316     }
02317   return ret;
02318 }
02319 
02320 USECODE_INTRINSIC(play_sound_effect)
02321 {
02322   if (num_parms < 1) return(no_ret);
02323   // Play music(isongnum).
02324   COUT("Sound effect " << parms[0].get_int_value() << " request in usecode");
02325 
02326   Audio::get_ptr()->play_sound_effect (parms[0].get_int_value());
02327   return(no_ret);
02328 }
02329 
02330 USECODE_INTRINSIC(play_sound_effect2)
02331 {
02332   if (num_parms < 2) return(no_ret);
02333   // Play music(songnum, item).
02334   Game_object *obj = get_item(parms[1]);
02335   int volume = SDL_MIX_MAXVOLUME; // Set volume based on distance.
02336   int dir = 0;
02337   if (obj)
02338     {
02339     Tile_coord apos = gwin->get_main_actor()->get_tile();
02340     Tile_coord opos = obj->get_tile();
02341     int dist = apos.distance(opos);
02342     if (dist)
02343       {   // 160/8 = 20 tiles. 20*20=400.
02344       volume = (SDL_MIX_MAXVOLUME*64)/(dist*dist);
02345       if (volume < 8)
02346         volume = 8;
02347       else if (volume > SDL_MIX_MAXVOLUME)
02348         volume = SDL_MIX_MAXVOLUME;
02349       dir = Get_direction16(apos.ty - opos.ty,
02350             opos.tx - apos.tx);
02351       }
02352     }
02353 #ifdef DEBUG
02354   cout << "Sound effect(2) " << parms[0].get_int_value() << 
02355     " request in usecode with volume = " << volume 
02356     << ", dir = " << dir << endl;
02357 #endif
02358   Audio::get_ptr()->play_sound_effect (parms[0].get_int_value(), volume,
02359                   dir);
02360   return(no_ret);
02361 }
02362 
02363 USECODE_INTRINSIC(get_npc_id)
02364 {
02365   Actor *actor = as_actor(get_item(parms[0]));
02366   if (!actor) return(no_ret);
02367   return Usecode_value (actor->get_ident());
02368 }
02369 
02370 USECODE_INTRINSIC(set_npc_id)
02371 {
02372   Actor *actor = as_actor(get_item(parms[0]));
02373   if (actor) actor->set_ident(parms[1].get_int_value());
02374   return(no_ret);
02375 }
02376 
02377 
02378 USECODE_INTRINSIC(add_cont_items)
02379 {
02380   // Add items(num, item, ??quality?? (-359), frame (or -359), T/F).
02381   return add_cont_items(parms[0], parms[1], parms[2],
02382           parms[3], parms[4], parms[5]);
02383 }
02384 
02385 // Is this SI Only
02386 USECODE_INTRINSIC(remove_cont_items)
02387 {
02388   // Add items(num, item, ??quality?? (-359), frame (or -359), T/F).
02389   return remove_cont_items(parms[0], parms[1], parms[2],
02390           parms[3], parms[4], parms[5]);
02391 }
02392 
02393 /*
02394  *  SI-specific functions.
02395  */
02396 
02397 USECODE_INTRINSIC(show_npc_face0)
02398 {
02399   // Show_npc_face0(npc, frame).  Show in position 0.
02400   show_npc_face(parms[0], parms[1], 0);
02401   return no_ret;
02402 }
02403 
02404 USECODE_INTRINSIC(show_npc_face1)
02405 {
02406   // Show_npc_face1(npc, frame).  Show in position 1.
02407   show_npc_face(parms[0], parms[1], 1);
02408   return no_ret;
02409 }
02410 
02411 USECODE_INTRINSIC(remove_npc_face0)
02412 {
02413   show_pending_text();
02414   conv->remove_slot_face(0);
02415   return no_ret;
02416 }
02417 
02418 USECODE_INTRINSIC(remove_npc_face1)
02419 {
02420   show_pending_text();
02421   conv->remove_slot_face(1);
02422   return no_ret;
02423 }
02424 
02425 USECODE_INTRINSIC(set_conversation_slot)
02426 {
02427   // set_conversation_slot(0 or 1) - Choose which face is talking.
02428   conv->set_slot(parms[0].get_int_value());
02429   return no_ret;
02430 }
02431 
02432 USECODE_INTRINSIC(init_conversation)
02433 {
02434   init_conversation();
02435   return no_ret;
02436 }
02437 
02438 USECODE_INTRINSIC(end_conversation)
02439 {
02440   show_pending_text();    // Wait for click if needed.
02441   conv->init_faces();   // Removes faces from screen.
02442   gwin->set_all_dirty();
02443   return no_ret;
02444 }
02445 
02446 USECODE_INTRINSIC(si_path_run_usecode)
02447 {
02448   // exec(npc, loc(x,y,z)?, eventid, itemref, usecode#, ??true/false).
02449   // Schedule Npc to walk to loc and then execute usecode.
02450           // Guessing:
02451   int always = parms[5].get_int_value();
02452   path_run_usecode(parms[0], parms[1], parms[4], parms[3], parms[2], 1,
02453               always);
02454   return no_ret;
02455 }
02456 
02457 USECODE_INTRINSIC(error_message)
02458 {
02459   // exec(array)
02460   // Output everything to stdout
02461 
02462   for (int i = 0; i < num_parms; i++)
02463   {
02464     if (parms[i].is_int()) std::cout << parms[i].get_int_value() ;
02465     else if (parms[i].is_ptr()) std::cout << parms[i].get_ptr_value();
02466     else if (!parms[i].is_array()) std::cout << parms[i].get_str_value();
02467     else for (int j = 0; j < parms[i].get_array_size(); j++)
02468     {
02469       if (parms[i].get_elem(j).is_int()) std::cout << parms[i].get_elem(j).get_int_value() ;
02470       else if (parms[i].get_elem(j).is_ptr()) std::cout << parms[i].get_elem(j).get_ptr_value();
02471       else if (!parms[i].get_elem(j).is_array()) std::cout << parms[i].get_elem(j).get_str_value();
02472     }
02473   }
02474 
02475   std::cout << std::endl;
02476   return no_ret;
02477 }
02478 
02479 USECODE_INTRINSIC(set_polymorph)
02480 {
02481   // exec(npc, shape).
02482   // Npc's shape is change to shape.
02483   Actor *actor = as_actor(get_item(parms[0]));
02484   if (actor) actor->set_polymorph(parms[1].get_int_value());
02485   return no_ret;
02486 }
02487 
02488 USECODE_INTRINSIC(set_new_schedules)
02489 {
02490   // set_new_schedules ( npc, time, activity, [x, y] )
02491   //
02492   // or
02493   //
02494   // set_new_schedules ( npc, [ time1, time2, ...],
02495   //      [activity1, activity2, ...],
02496   //      [x1,y1, x2, y2, ...] )
02497   //
02498 
02499   Actor *actor = as_actor(get_item(parms[0]));
02500 
02501   // If no actor return
02502   if (!actor) return no_ret;
02503 
02504   int count = parms[1].is_array()?parms[1].get_array_size():1;
02505   Schedule_change *list = new Schedule_change[count];
02506 
02507   if (!parms[1].is_array())
02508   {
02509     int time = parms[1].get_int_value();
02510     int sched = parms[2].get_int_value();
02511     int tx = parms[3].get_elem(0).get_int_value();
02512     int ty = parms[3].get_elem(1).get_int_value();
02513     list[0].set(tx, ty, sched, time);
02514   }
02515   else for (int i = 0; i < count; i++)
02516   {
02517     int time = parms[1].get_elem(i).get_int_value();
02518     int sched = parms[2].get_elem(i).get_int_value();
02519     int tx = parms[3].get_elem(i*2).get_int_value();
02520     int ty = parms[3].get_elem(i*2+1).get_int_value();
02521     list[i].set(tx, ty, sched, time);
02522   }
02523 
02524   actor->set_schedules(list, count);
02525 
02526   return no_ret;
02527 }
02528 
02529 USECODE_INTRINSIC(revert_schedule)
02530 {
02531   // revert_schedule(npc)
02532   // Reverts the schedule of the npc to the saved state in
02533   // <STATIC>/schedule.dat
02534 
02535   Actor *actor = as_actor(get_item(parms[0]));
02536   if (actor) gwin->revert_schedules(actor);
02537 
02538   return no_ret;
02539 }
02540 
02541 USECODE_INTRINSIC(run_schedule)
02542 {
02543   // run_schedule(npc)
02544   // I think this is actually reset activity to current
02545   // scheduled activity - Colourless
02546   Actor *actor = as_actor(get_item(parms[0]));
02547   
02548   if (actor)
02549   {
02550     actor->update_schedule(gclock->get_hour()/3, 7);
02551 
02552   }
02553 
02554   return no_ret;
02555 }
02556 
02557 USECODE_INTRINSIC(modify_schedule)
02558 {
02559   // modify_schedule ( npc, time, activity, [x, y] )
02560 
02561   Actor *actor = as_actor(get_item(parms[0]));
02562 
02563   // If no actor return
02564   if (!actor) return no_ret;
02565 
02566   int time = parms[1].get_int_value();
02567   int sched = parms[2].get_int_value();
02568   int tx = parms[3].get_elem(0).get_int_value();
02569   int ty = parms[3].get_elem(1).get_int_value();
02570 
02571   actor->set_schedule_time_type(time, sched);
02572   actor->set_schedule_time_location(time, tx, ty);
02573 
02574   return no_ret;
02575 }
02576 
02577 USECODE_INTRINSIC(get_temperature)
02578 {
02579   Actor *npc = as_actor(get_item(parms[0]));
02580   return Usecode_value(npc ? npc->get_temperature() : 0);
02581 }
02582 
02583 USECODE_INTRINSIC(set_temperature)
02584 {
02585   // set_temperature(npc, value (0-63)).
02586   Actor *npc = as_actor(get_item(parms[0]));
02587   if (npc)
02588     npc->set_temperature(parms[1].get_int_value());
02589   return no_ret;
02590 }
02591 
02592 #if 0 /* +++++Not used at the moment. */
02593 USECODE_INTRINSIC(add_removed_npc)
02594 {
02595   // move_offscreen(npc, x, y) - I think (seems good) I think
02596   //
02597   // returns false if not moved
02598   // else, moves the object to the closest position off 
02599 
02600   // Actor we want to move
02601   Actor *actor = as_actor(get_item(parms[0]));
02602 
02603   // Need to check superchunk
02604   int cx = actor->get_cx();
02605   int cy = actor->get_cx();
02606   int scx = cx / c_chunks_per_schunk;
02607   int scy = cy / c_chunks_per_schunk;
02608   int scx2 = parms[1].get_int_value() / c_tiles_per_schunk;
02609   int scy2 = parms[2].get_int_value() / c_tiles_per_schunk;
02610 
02611   // Are the coords are good
02612   if ( (cx == 0xff && scx2) || (cx != 0xff && scx != scx2) ||
02613     (cy == 0xff && scy2) || (cy != 0xff && scy != scy2) ) 
02614     return (Usecode_value(false));
02615 
02616 
02617   // Ok they were good, now move it
02618 
02619 
02620   // Get the tiles around the edge of the screen
02621   Rectangle rect = gwin->get_win_tile_rect();
02622 
02623   int sx = rect.x;    // Tile coord of x start
02624   int ex = rect.x + rect.w; // Tile coord of x end
02625   int sy = rect.y;    // y start
02626   int ey = rect.y + rect.h; // x end
02627 
02628   // The height of the Actor we are checking
02629   int height = actor->get_info().get_3d_height();
02630 
02631   int i = 0, nlift = 0;
02632   int tx, ty;
02633 
02634   // Avatars coords
02635   Tile_coord av = gwin->get_main_actor()->get_tile();;
02636 
02637   Tile_coord close; // The tile coords of the closest tile
02638   int dist = -1;    // The distance
02639 
02640   cy = sy/c_tiles_per_chunk;
02641   ty = sy%c_tiles_per_chunk;
02642   cout << "1" << endl;
02643   for (i = 0; i < rect.w; i++)
02644   {
02645     cx = (sx+i)/c_tiles_per_chunk;
02646     tx = (sx+i)%c_tiles_per_chunk;
02647 
02648     Map_chunk *clist = gmap->get_chunk_safely(cx, cy);
02649     clist->setup_cache();
02650     if (!clist->is_blocked (height, 0, tx, ty, nlift, actor->get_type_flags(), 1))
02651     {
02652       Tile_coord cur(tx+cx*c_tiles_per_chunk, ty+cy*c_tiles_per_chunk, nlift);
02653       if (cur.distance(av) < dist || dist == -1)
02654       {
02655         dist = cur.distance(av);
02656         cout << "(" << cur.tx << ", " << cur.ty << ") " << dist << endl;
02657         close = cur;
02658       }
02659     }
02660   }
02661 
02662   cx = ex/c_tiles_per_chunk;
02663   tx = ex%c_tiles_per_chunk;
02664   cout << "2" << endl;
02665   for (i = 0; i < rect.h; i++)
02666   {
02667     cy = (sy+i)/c_tiles_per_chunk;
02668     ty = (sy+i)%c_tiles_per_chunk;
02669 
02670     Map_chunk *clist = gmap->get_chunk_safely(cx, cy);
02671     clist->setup_cache();
02672     if (!clist->is_blocked (height, 0, tx, ty, nlift, actor->get_type_flags(), 1))
02673     {
02674       Tile_coord cur(tx+cx*c_tiles_per_chunk, ty+cy*c_tiles_per_chunk, nlift);
02675       if (cur.distance(av) < dist || dist == -1)
02676       {
02677         dist = cur.distance(av);
02678         cout << "(" << cur.tx << ", " << cur.ty << ") " << dist << endl;
02679         close = cur;
02680       }
02681     }
02682   }
02683 
02684   cy = ey/c_tiles_per_chunk;
02685   ty = ey%c_tiles_per_chunk;
02686   cout << "3" << endl;
02687   for (i = 0; i < rect.w; i++)
02688   {
02689     cx = (ex-i)/c_tiles_per_chunk;
02690     tx = (ex-i)%c_tiles_per_chunk;
02691 
02692     Map_chunk *clist = gmap->get_chunk_safely(cx, cy);
02693     clist->setup_cache();
02694     if (!clist->is_blocked (height, 0, tx, ty, nlift, actor->get_type_flags(), 1))
02695     {
02696       Tile_coord cur(tx+cx*c_tiles_per_chunk, ty+cy*c_tiles_per_chunk, nlift);
02697       if (cur.distance(av) < dist || dist == -1)
02698       {
02699         dist = cur.distance(av);
02700         cout << "(" << cur.tx << ", " << cur.ty << ") " << dist << endl;
02701         close = cur;
02702       }
02703     }
02704   }
02705 
02706   cx = sx/c_tiles_per_chunk;
02707   tx = sx%c_tiles_per_chunk;
02708   cout << "4" << endl;
02709   for (i = 0; i < rect.h; i++)
02710   {
02711     cy = (ey-i)/c_tiles_per_chunk;
02712     ty = (ey-i)%c_tiles_per_chunk;
02713 
02714     Map_chunk *clist = gmap->get_chunk_safely(cx, cy);
02715     clist->setup_cache();
02716     if (!clist->is_blocked (height, 0, tx, ty, nlift, actor->get_type_flags(), 1))
02717     {
02718       Tile_coord cur(tx+cx*c_tiles_per_chunk, ty+cy*c_tiles_per_chunk, nlift);
02719       if (cur.distance(av) < dist || dist == -1)
02720       {
02721         dist = cur.distance(av);
02722         cout << "(" << cur.tx << ", " << cur.ty << ") " << dist << endl;
02723         close = cur;
02724       }
02725     }
02726   }
02727 
02728   if (dist != -1)
02729   {
02730     actor->move(close);
02731     return (Usecode_value(true));
02732   }
02733 
02734   return (Usecode_value(false));
02735 }
02736 #endif
02737 
02738 USECODE_INTRINSIC(approach_avatar)
02739 {
02740   // Approach_avatar(npc, ?, ?).
02741   // Actor we want to move
02742   Actor *actor = as_actor(get_item(parms[0]));
02743   if (!actor || actor->is_dead())
02744     return Usecode_value(0);
02745           // Guessing!! If already close...
02746   if (actor->distance(gwin->get_main_actor()) < 10)
02747     return Usecode_value(1);
02748           // Approach, and wait.
02749   if (!actor->approach_another(gwin->get_main_actor(), true))
02750     return Usecode_value(0);
02751   return Usecode_value(1);
02752   }
02753 
02754 USECODE_INTRINSIC(set_barge_dir)
02755 {
02756   // set_barge_dir(barge, dir (0-7)).
02757   Game_object *obj = get_item(parms[0]);
02758   int dir = parms[1].get_int_value();
02759   Barge_object *barge = obj ? obj->as_barge() : 0;
02760   if (barge)
02761     barge->face_direction(dir);
02762   return no_ret;
02763 }
02764 
02765 USECODE_INTRINSIC(telekenesis)
02766 {
02767   // telekenesis(fun#) - Save item for executing Usecode on.
02768   telekenesis_fun = parms[0].get_int_value();
02769   return no_ret;
02770 }
02771 
02772 USECODE_INTRINSIC(a_or_an)
02773 {
02774   // a_or_an (word)
02775   // return a/an depending on 'word'
02776 
02777   if (strchr("aeiouyAEIOUY", (parms[0].get_str_value())[0]) == 0)
02778     return (Usecode_value("a"));
02779   else
02780     return (Usecode_value("an"));
02781 
02782 }
02783 
02784 USECODE_INTRINSIC(remove_from_area)
02785 {
02786   // Remove_from_area(shapenum, framenum, [x,y]from, [x,y]to).
02787   int shnum = parms[0].get_int_value(), frnum = parms[1].get_int_value();
02788   int fromx = parms[2].get_elem(0).get_int_value(),
02789       fromy = parms[2].get_elem(1).get_int_value(),
02790       tox   = parms[3].get_elem(0).get_int_value(),
02791       toy   = parms[3].get_elem(1).get_int_value();
02792   Rectangle area(fromx, fromy, tox - fromx + 1, toy - fromy + 1);
02793   if (area.w <= 0 || area.h <= 0)
02794     return no_ret;
02795   Game_object_vector vec;   // Find objects.
02796   Map_chunk::find_in_area(vec, area, shnum, frnum);
02797           // Remove them.
02798   for (Game_object_vector::iterator it = vec.begin(); it != vec.end();
02799                 it++)
02800     {
02801     Game_object *obj = *it;
02802     gwin->add_dirty(obj);
02803     obj->remove_this(0);
02804     }
02805   return no_ret;
02806 }
02807 
02808 USECODE_INTRINSIC(infravision)
02809 {
02810   // infravision(npc, onoff)
02811   Actor *npc = as_actor(get_item(parms[0]));
02812   if (npc && npc->is_in_party())
02813     {
02814     if (parms[1].get_int_value())
02815       {   // On?
02816       cheat.set_infravision(true);
02817       gwin->get_pal()->set(0);
02818       }
02819     else
02820       {
02821       cheat.set_infravision(false);
02822       gclock->set_palette();
02823       }
02824     }
02825   return no_ret;
02826 }
02827 
02828 // parms[0] = quality of key to be added
02829 USECODE_INTRINSIC(add_to_keyring)
02830 {
02831   getKeyring()->addkey(parms[0].get_int_value());
02832 
02833   return no_ret;
02834 }
02835 
02836 // parms[0] = quality of key to check
02837 // returns true if key is on keyring
02838 
02839 USECODE_INTRINSIC(is_on_keyring)
02840 {
02841   if (getKeyring()->checkkey(parms[0].get_int_value()))
02842     return Usecode_value(true);
02843   else
02844     return Usecode_value(false);
02845 }
02846 
02847 USECODE_INTRINSIC(save_pos)
02848 {
02849   // save_pos(item).
02850   Game_object *item = get_item(parms[0]);
02851   if (item)
02852     saved_pos = item->get_tile();
02853   return no_ret;
02854 }
02855 
02856 USECODE_INTRINSIC(teleport_to_saved_pos)
02857 {
02858   // teleport_to_saved_pos(actor).  Only supported for Avatar for now.
02859   Actor *npc = as_actor(get_item(parms[0]));
02860   if (npc == gwin->get_main_actor())
02861     {     // Bad value?
02862     if (saved_pos.tx < 0 || saved_pos.tx >= c_num_tiles)
02863           // Fix old games.  Send to Monitor.
02864       saved_pos = Tile_coord(719, 2608, 1);
02865     gwin->teleport_party(saved_pos);
02866     }
02867   return no_ret;
02868 }
02869 
02870 USECODE_INTRINSIC(get_item_usability)
02871 {
02872   // Complete guess:  Returns 1 for grabbable items (for fetch spell).
02873   Game_object *obj = get_item(parms[0]);
02874   if (!obj || !obj->is_dragable())
02875     return Usecode_value(0);
02876   else
02877     return Usecode_value(1);// Only 1 I'm pretty sure of.
02878 }
02879 
02880 USECODE_INTRINSIC(get_skin_colour)
02881 {
02882   // Gets skin colour of avatar. 0 (wh), 1 (br) or 2 (bl)
02883   Main_actor *av = gwin->get_main_actor();
02884   return Usecode_value(av->get_skin_color());
02885 }
02886 
02887 /*
02888  *  This is like the C version, but only '%s' is supported, and all the
02889  *  parms should be packed into one array.
02890  *  Added for Exult.
02891  */
02892 USECODE_INTRINSIC(printf)
02893 {
02894   Usecode_value ret("");
02895   const char *fmt = parms[0].get_elem0().get_str_value();
02896   int count;
02897   cout << endl;     // For now...
02898   if (!fmt || (count = parms[0].get_array_size()) <= 1)
02899     {
02900     parms[0].print(cout);
02901     return ret;
02902     }
02903   int i = 1;      // Parm. #.
02904   while (*fmt)
02905     {
02906     const char *spec = strchr(fmt, '%');
02907     if (!spec)
02908       spec = fmt + std::strlen(fmt);
02909     cout.write(fmt, spec - fmt);
02910     if (*spec == '%')
02911       {
02912       if (spec[1] == 's')
02913         {
02914         Usecode_value p = i < count ? parms[0][i]
02915               : Usecode_value(0);
02916         if (p.get_type() == Usecode_value::int_type)
02917           cout << p.get_int_value();
02918         else
02919           p.print(cout);
02920         spec += 2;
02921         }
02922       else
02923         {
02924         cout << '%';
02925         spec++;
02926         }
02927       }
02928     fmt = spec;
02929     }
02930   return ret;
02931 }
02932 

Generated on Mon Jul 9 14:42:51 2007 for ExultEngine by  doxygen 1.5.1