spellbook.cc

Go to the documentation of this file.
00001 
00007 /*
00008 Copyright (C) 2000 The Exult Team.
00009 
00010 This program is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU General Public License
00012 as published by the Free Software Foundation; either version 2
00013 of the License, or (at your option) any later version.
00014 
00015 This program is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00023 */
00024 
00025 #ifdef HAVE_CONFIG_H
00026 #  include <config.h>
00027 #endif
00028 
00029 #include "spellbook.h"
00030 #include "gamewin.h"
00031 #include "gamemap.h"
00032 #include "utils.h"
00033 #include "game.h"
00034 #include "Gump_manager.h"
00035 #include "databuf.h"
00036 #include "ucsched.h"
00037 #include "actors.h"
00038 #include "cheat.h"
00039 #include "ucmachine.h"
00040 
00041 #ifndef UNDER_CE
00042 using std::memcpy;
00043 using std::ostream;
00044 #endif
00045 
00046 const int REAGENTS = 842;   // Shape #.
00047 
00048 /*
00049  *  Flags for required reagents.  Bits match frame #.
00050  */
00051 const int bp = 1;     // Black pearl.
00052 const int bm = 2;     // Blood moss.
00053 const int ns = 4;     // Nightshade.
00054 const int mr = 8;     // Mandrake root.
00055 const int gr = 16;      // Garlic.
00056 const int gn = 32;      // Ginseng.
00057 const int ss = 64;      // Spider silk.
00058 const int sa = 128;     // Sulphuras ash.
00059 const int bs = 256;     // Blood spawn.
00060 const int sc = 512;     // Serpent scales.
00061 const int wh = 1024;      // Worm's hart.
00062 
00063           // Black Gate:
00064 unsigned short Spellbook_object::bg_reagents[9*8] = {
00065   0, 0, 0, 0, 0, 0, 0, 0,   // Linear spells require no reagents.
00066           // Circle 1:
00067   gr|gn|mr, gr|gn, ns|ss, gr|ss, sa|ss, sa, ns, gr|gn,
00068           // Circle 2:
00069   bm|sa, bp|mr, bp|sa, mr|sa, gr|gn|mr, gr|gn|sa, bp|bm|mr,
00070               bm|ns|mr|sa|bp|ss,
00071           // Circle 3:
00072   gr|ns|sa, gr|gn|ss, ns|ss, ns|mr, ns|bm|bp, gr|gn|mr|sa,
00073             bp|ns|ss, ns|mr|bm,
00074           // Circle 4:
00075   ss|mr, bp|sa|mr, mr|bp|bm, gr|mr|ns|sa, mr|bp|bm, bm|sa,
00076             bm|mr|ns|ss|sa, bm|sa,
00077           // Circle 5:
00078   bp|ns|ss, mr|gr|bm, gr|bp|sa|ss, bm|bp|mr|sa, bp|ss|sa,
00079             gr|gn|mr|ss, bm|ns, gn|ns|ss,
00080           // Circle 6:
00081   gr|mr|ns, sa|ss|bm|gn|ns|mr, bp|mr|ss|sa, sa|bp|bm, mr|ns|sa|bm,
00082             ns|ss|bp, gn|ss|bp, bm|sa|mr,
00083           // Circle 7:
00084   mr|ss, bp|ns|sa, bm|bp|mr|ss|sa, bp|mr|ss|sa, bm|mr|ns|sa,
00085           bp|ns|ss|mr, bp|gn|mr, gr|gn|mr|sa,
00086           // Circle 8:
00087   bp|bm|gr|gn|mr|ns|ss|sa, bm|mr|ns|sa, bp|bm|mr|ns, bm|gr|gn|mr|ns,
00088         gr|gn|ss|sa, bm|gr|mr, bp|mr|ns, bm|gr|mr
00089   };
00090           // Serpent Isle:
00091 unsigned short Spellbook_object::si_reagents[9*8] = {
00092           // Circle 1:
00093   gr|gn|mr, gr|gn, ns|ss, gr|ss, sa|ss, sa, ns, bp|bm|mr,
00094           // Circle 2:
00095   gr|gn, bm|sa, ns|sa, bp|sa|wh, mr|sa, gr|gn|ss, gr|gn|mr, gr|gn|sa,
00096           // Circle 3:
00097   gr|gn|wh,gr|ns|sa, bp|mr, bp|gr, gr|gn|mr|sa, ns|ss, bp|ns|ss, bp|mr|sa|sa,
00098           // Circle 4:
00099   bm|mr, gr|ss, mr|sa, sa|bm|gr|mr|ss|sc, gr|mr|ns|sa, bm|sa, bp|ss, bm|sa,
00100           // Circle 5:
00101   mr|ss, bp|gr|ss|sa, bm|bp|mr|sa, gr|gn|mr|ss, bm|ns, gn|ns|ss, sa|bm|mr|ns|ss, 
00102           bp|gr|mr|sa,
00103           // Circle 6:
00104   bp|ns|ss, gr|mr|ns, gr|mr|ns, bp|wh|ss|sa, bp|wh|mr|ss|sa, 
00105           bm|bp|wh|sa, bm|gn|sa, mr|sa|ss|sc,
00106           // Circle 7:
00107   bp|mr|ss|sa, bm|mr|ns|sa, gr|gn, bp|gn|mr, bm|ns|sa, gr|gn|mr|ss, 
00108             bp|bm|mr|ss, bp|mr|sa,
00109           // Circle 8:
00110   wh|ss, bs|bp|ns|sa, bm|bp|mr|ss|sa, bm|bp|mr, bm|gr|ss|wh|sc, 
00111         bm|bp|gr|ss|wh|sc, gr|mr|sa, bp|bs|mr|ns,
00112           // Circle 9:
00113   bm|mr|ns|sa, bm|bs|gr|gn|mr|ns, bp|bm|mr|ns, bm|bs|bp|ns|sa, 
00114       bp|gr|mr|ss|sa, bm|gr|mr|ss, bm|gr|mr, ns|sa|wh|sc
00115   };
00116 
00117 /*
00118  *  Get usecode function for a given spell:
00119  */
00120 int Get_usecode(int spell)
00121   { return 0x640 + spell; }
00122 
00123 /*
00124  *  Test for Ring of Reagants.
00125  */
00126 
00127 bool Spellbook_object::has_ring
00128   (
00129   Actor *act
00130   )
00131   {
00132   if (Game::get_game_type() == SERPENT_ISLE)
00133     {
00134     Game_object *obj = act->get_readied(Actor::lfinger);
00135     if (obj && obj->get_shapenum() == 0x128 &&
00136             obj->get_framenum() == 3)
00137       return true;
00138     obj = act->get_readied(Actor::rfinger);
00139     if (obj && obj->get_shapenum() == 0x128 &&
00140             obj->get_framenum() == 3)
00141       return true;
00142     }
00143   return false;
00144   }
00145 
00146 /*
00147  *  Create a spellbook from Ireg data.
00148  */
00149 
00150 Spellbook_object::Spellbook_object
00151   (
00152   int shapenum, int framenum,
00153   unsigned int shapex, unsigned int shapey, 
00154   unsigned int lft, 
00155   unsigned char *c,   // Circle spell flags.
00156   unsigned char bmark   // Spell bookmark.
00157   ) : Ireg_game_object(shapenum, framenum,
00158       shapex, shapey, lft), bookmark(bmark == 255 ? -1 : bmark)
00159   {
00160   memcpy(circles, c, sizeof(circles));
00161           // Point to reagent table.
00162   reagents = GAME_SI ? si_reagents : bg_reagents;
00163   }
00164 
00165 /*
00166  *  Add a spell.
00167  *
00168  *  Output: 0 if already have it, 1 if successful.
00169  */
00170 
00171 int Spellbook_object::add_spell
00172   (
00173   int spell     // 0-71
00174   )
00175   {
00176   int circle = spell/8;
00177   int num = spell%8;    // # within circle.
00178   if (circles[circle] & (1<<num))
00179     return 0;   // Already have it.
00180   circles[circle] |= (1<<num);
00181   return 1;
00182   }
00183 
00184 /*
00185  *  Can we do a given spell?
00186  */
00187 
00188 bool Spellbook_object::can_do_spell
00189   (
00190   Actor *act,
00191   int spell
00192   )
00193   {
00194   if (cheat.in_wizard_mode())
00195     return true;    // Cheating.
00196   int circle = spell/8;   // Circle spell is in.
00197   unsigned char cflags = circles[circle];
00198   if ((cflags & (1<<(spell%8))) == 0)
00199     return false;   // We don't have that spell.
00200   int mana = act->get_property(Actor::mana);
00201   int level = act->get_level();
00202   if ((mana < circle) || (level < circle))
00203       // Not enough mana or not yet at required level?
00204     return false;
00205   if (has_ring(act))    // Ring of reagents (SI)?
00206     return true;
00207           // Figure what we used.
00208   unsigned short flags = reagents[spell];
00209           // Go through bits.
00210   for (int r = 0; flags; r++, flags = flags >> 1)
00211           // Need 1 of each required reagent.
00212     if ((flags&1) && 
00213         act->count_objects(REAGENTS, c_any_qual, r) == 0)
00214       return false; // Missing.
00215   return true;
00216   }
00217 
00218 /*
00219  *  Perform a spell.
00220  *
00221  *  Output: False if unsuccessful.
00222  */
00223 
00224 bool Spellbook_object::do_spell
00225   (
00226   Actor *act,
00227   int spell,
00228   bool can_do,      // Already checked.
00229   bool in_combat      // Being used in combat.
00230   )
00231   {
00232   if (can_do || can_do_spell(act, spell))
00233     {
00234     int circle = spell/8; // Figure/subtract mana.
00235     if (cheat.in_wizard_mode())
00236       circle = 0;
00237     int mana = act->get_property(Actor::mana);
00238     act->set_property(Actor::mana, mana-circle);
00239           // Figure what we used.
00240     unsigned short flags = reagents[spell];
00241 
00242     if (!cheat.in_wizard_mode() && !has_ring(act))
00243       {
00244           // Go through bits.
00245       for (int r = 0; flags; r++, flags = flags >> 1)
00246           // Remove 1 of each required reagent.
00247         if (flags&1)
00248           act->remove_quantity(1, 
00249             REAGENTS, c_any_qual, r);
00250       }
00251     execute_spell(act, spell, in_combat);
00252     return true;
00253     }
00254   return false;
00255   }
00256 
00257 /*
00258  *  Perform the usecode for a spell.
00259  */
00260 
00261 void Spellbook_object::execute_spell
00262   (
00263   Actor *act,
00264   int spell,
00265   bool in_combat      // Being used in combat.
00266   )
00267   {
00268   ucmachine->call_usecode(Get_usecode(spell), act, 
00269     in_combat ? Usecode_machine::weapon :
00270           Usecode_machine::double_click);
00271   }
00272 
00273 /*
00274  *  Show book when double-clicked.
00275  */
00276 
00277 void Spellbook_object::activate
00278   (
00279   int event
00280   )
00281   {
00282   gumpman->add_gump(this, Game::get_game_type() == BLACK_GATE ? 43 : 38);
00283   }
00284 
00285 /*
00286  *  Write out.
00287  */
00288 
00289 void Spellbook_object::write_ireg
00290   (
00291   DataSource *out
00292   )
00293   {
00294   unsigned char buf[19];    // 18-byte entry + length-byte.
00295   buf[0] = 18;
00296   uint8 *ptr = &buf[1]; // To avoid confusion about offsets.
00297   write_common_ireg(ptr);   // Fill in bytes 1-4.
00298   ptr += 4;
00299   memcpy(ptr, &circles[0], 5);  // Store the way U7 does it.
00300   ptr += 5;
00301   *ptr++ = (get_lift()&15)<<4;  // Low bits?++++++
00302   memcpy(ptr, &circles[5], 4);  // Rest of spell circles.
00303   ptr += 4;
00304   *ptr++ = 0;     // 3 unknowns.
00305   *ptr++ = 0;
00306   *ptr++ = 0;
00307   *ptr++ = bookmark >= 0 ? bookmark : 255;
00308   out->write((char*)buf, sizeof(buf));
00309           // Write scheduled usecode.
00310   Game_map::write_scheduled(out, this); 
00311   }
00312 
00313 // Get size of IREG. Returns -1 if can't write to buffer
00314 int Spellbook_object::get_ireg_size()
00315 {
00316   // These shouldn't ever happen, but you never know
00317   if (gumpman->find_gump(this) || Usecode_script::find(this))
00318     return -1;
00319 
00320   return 19;
00321 }

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