Spellbook_gump.cc

Go to the documentation of this file.
00001 /*
00002  *  Copyright (C) 2000-2002  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 <SDL_timer.h>
00024 #include "actors.h"
00025 #include "cheat.h"
00026 #include "gamewin.h"
00027 #include "Gump_button.h"
00028 #include "items.h"
00029 #include "mouse.h"
00030 #include "Spellbook_gump.h"
00031 #include "spellbook.h"
00032 #include "game.h"
00033 #include "Gump_manager.h"
00034 
00035 #ifndef ALPHA_LINUX_CXX
00036 #  include <cstdio>
00037 #endif
00038 
00039 
00040 
00041 const int REAGENTS = 842;   // Shape #.
00042 
00043 /*
00044  *  Defines in 'gumps.vga':
00045  */
00046 #define SPELLBOOK (GAME_BG ? 43 : 38)
00047 #define SPELLS  (GAME_BG ? 33 : 28)   // First group of 9 spells.
00048 #define TURNINGPAGE  (GAME_BG ? 41 : 36)  // Animation?? (4 frames).
00049 #define BOOKMARK  (GAME_BG ? 42 : 37) // Red ribbon, 5 frames.
00050 #define LEFTPAGE  (GAME_BG ? 44 : 39) // At top-left of left page.
00051 #define RIGHTPAGE  (GAME_BG ? 45 : 40)  // At top-right of right page.
00052 #define SCROLLSPELLS  66    // First group of scroll spells (SI).
00053 
00054 /*
00055  *  And in 'text.flx':
00056  */
00057 #define CIRCLE (GAME_BG ? 0x545 : 0x551)
00058 #define CIRCLENUM (GAME_BG ? 0x545 : 0x552)
00059 
00060 /*
00061  *  Get circle, given a spell #.
00062  */
00063 inline int Get_circle(int spell)
00064   { return spell/8; }
00065 
00066 /*
00067  *  Get shape, frame for a given spell #.  There are 8 shapes, each
00068  *  containing 9 frames, where frame # = spell circle #.
00069  */
00070 inline int Get_spell_gump_shape
00071   (
00072   int spell,      // Spell # (as used in Usecode).
00073   int& shape,     // Shape returned (gumps.vga).
00074   int& frame      // Frame returned.
00075   )
00076   {
00077   if (spell < 0 || spell >= 0x48)
00078     return 0;
00079   shape = spell%8;
00080   frame = spell/8;
00081   return (1);
00082   }
00083 
00084 /*
00085  *  A 'page-turner' button.
00086  */
00087 class Page_button : public Gump_button
00088   {
00089   int leftright;      // 0=left, 1=right.
00090 public:
00091   Page_button(Gump *par, int px, int py, int lr)
00092     : Gump_button(par, lr ? RIGHTPAGE : LEFTPAGE, px, py),
00093       leftright(lr)
00094     {  }
00095           // What to do when 'clicked':
00096   virtual void activate();
00097   virtual void push() {}
00098   virtual void unpush() {}
00099   };
00100 
00101 /*
00102  *  Handle click.
00103  */
00104 
00105 void Page_button::activate
00106   (
00107   )
00108   {
00109   ((Spellbook_gump *) parent)->change_page(leftright ? 1 : -1);
00110   }
00111 
00112 /*
00113  *  The bookmark.
00114  */
00115 class Bookmark_button : public Gump_button
00116   {
00117 public:
00118   Bookmark_button(Gump *par)
00119     : Gump_button(par, BOOKMARK, 0, 0)
00120     {  }
00121   void set();     // Call this to set properly.
00122           // What to do when 'clicked':
00123   virtual void activate();
00124   virtual void push() {}
00125   virtual void unpush() {}
00126   };
00127 
00128 /*
00129  *  Set position and frame.
00130  */
00131 
00132 void Bookmark_button::set
00133   (
00134   )
00135   {
00136   Spellbook_gump *sgump = (Spellbook_gump *) parent;
00137   Rectangle& object_area = sgump->object_area;
00138   int spwidth = sgump->spwidth; // Spell width.
00139   Spellbook_object *book = sgump->book;
00140   int page = sgump->page;   // Page (circle) we're on.
00141   int bmpage = book->bookmark/8;  // Bookmark's page.
00142   int s = book->bookmark%8; // Get # within circle.
00143           // Which side for bookmark?
00144   bool left = bmpage == page ? (s < 4) : bmpage < page;
00145           // Figure coords.
00146   x = left ? object_area.x + spwidth/2
00147     : object_area.x + object_area.w - spwidth/2 - 2;
00148   Shape_frame *bshape = get_shape();
00149   x += bshape->get_xleft();
00150   y = object_area.y - 14 + bshape->get_yabove();
00151   set_frame(bmpage == page ? (1 + s%4) : 0);
00152   }
00153 
00154 /*
00155  *  Handle click.
00156  */
00157 
00158 void Bookmark_button::activate
00159   (
00160   )
00161   {
00162 
00163   Spellbook_gump *sgump = (Spellbook_gump *) parent;
00164   int bmpage = sgump->book->bookmark/8; // Bookmark's page.
00165           // On a different, valid page?
00166   if (bmpage >= 0 && bmpage != sgump->page)
00167     sgump->change_page(bmpage - sgump->page);
00168   }
00169 
00170 /*
00171  *  A spell button.
00172  */
00173 class Spell_button : public Gump_button
00174   {
00175   int spell;      // Spell # (0 - 71).
00176 public:
00177   Spell_button(Gump *par, int px, int py, int sp, int shnum, int frnum)
00178     : Gump_button(par, shnum, px, py), spell(sp)
00179     {
00180     set_frame(frnum); // Frame # is circle.
00181     }
00182           // What to do when 'clicked':
00183   virtual void activate();
00184   virtual void double_clicked(int x, int y);
00185   virtual void push() { }
00186   virtual void unpush() { }
00187   };
00188 
00189 /*
00190  *  Handle click.
00191  */
00192 
00193 void Spell_button::activate
00194   (
00195   )
00196   {
00197   ((Spelltype_gump *) parent)->select_spell(spell);
00198   }
00199 
00200 /*
00201  *  Method for double-click.
00202  */
00203 
00204 void Spell_button::double_clicked
00205   (
00206   int x, int y
00207   )
00208   {
00209   ((Spelltype_gump *) parent)->do_spell(spell);
00210   }
00211 
00212 /*
00213  *  Figure the availability of the spells.
00214  */
00215 
00216 void Spellbook_gump::set_avail
00217   (
00218   )
00219 {
00220   int i;        // Init.
00221   for (i = 0; i < 9*8; i++)
00222     avail[i] = 0;
00223   if (book_owner == book)
00224     return;     // Nobody owns it.
00225   int reagent_counts[NREAGENTS];  // Count reagents.
00226   int r;
00227   for (r = 0; r < NREAGENTS; r++) // Count, by frame (frame==bit#).
00228     reagent_counts[r] = book_owner->count_objects(
00229             REAGENTS, c_any_qual, r);
00230   bool has_ring = book->has_ring(gwin->get_main_actor());
00231   for (i = 0; i < 9*8; i++) // Now figure what's available.
00232   {
00233     if (has_ring)
00234       {
00235       avail[i] = 10000;
00236       continue;
00237       }
00238     avail[i] = 10000; // 'infinite'.
00239     unsigned short flags = book->reagents[i];
00240           // Go through bits.
00241     for (r = 0; flags; r++, flags = flags >> 1)
00242           // Take min. of req. reagent counts.
00243       if ((flags&1) && reagent_counts[r] < avail[i])
00244         avail[i] = reagent_counts[r];
00245   }
00246 }
00247 
00248 /*
00249  *  Create spellbook display.
00250  */
00251 
00252 Spellbook_gump::Spellbook_gump
00253   (
00254   Spellbook_object *b
00255   ) : Spelltype_gump(SPELLBOOK), page(0), book(b), turning_page(0)
00256 {
00257   set_object_area(Rectangle(36, 28, 102, 66), 7, 54);
00258 
00259           // Where to paint page marks:
00260   const int lpagex = 38, rpagex = 142, lrpagey = 25;
00261           // Get book's top owner.
00262   book_owner = book->get_outermost();
00263   set_avail();      // Figure spell counts.
00264   if (book->bookmark >= 0)  // Set to bookmarked page.
00265     page = Get_circle(book->bookmark);
00266   leftpage = new Page_button(this, lpagex, lrpagey, 0);
00267   rightpage = new Page_button(this, rpagex, lrpagey, 1);
00268   bookmark = new Bookmark_button(this);
00269           // Get dims. of a spell.
00270   Shape_frame *spshape = ShapeID(SPELLS, 0, SF_GUMPS_VGA).get_shape();
00271   spwidth = spshape->get_width();
00272   spheight = spshape->get_height();
00273   bookmark->set();    // Set to correct position, frame.
00274   int vertspace = (object_area.h - 4*spheight)/4;
00275   int spells0 = SPELLS;
00276   for (int c = 0; c < 9; c++) // Add each spell.
00277   {
00278     int spindex = c*8;
00279     unsigned char cflags = book->circles[c];
00280     for (int s = 0; s < 8; s++)
00281       if ((cflags & (1<<s)) || cheat.in_wizard_mode())
00282         {
00283         int spnum = spindex + s;
00284         spells[spnum] = new Spell_button(this,
00285           s < 4 ? object_area.x +
00286             spshape->get_xleft() + 1
00287           : object_area.x + object_area.w - 
00288             spshape->get_xright() - 2,
00289           object_area.y + spshape->get_yabove() +
00290             (spheight + vertspace)*(s%4),
00291           spnum,
00292           spells0 + spnum%8, spnum/8);
00293         }
00294       else
00295         spells[spindex + s] = 0;
00296   }
00297 }
00298 
00299 /*
00300  *  Delete.
00301  */
00302 
00303 Spellbook_gump::~Spellbook_gump
00304   (
00305   )
00306 {
00307   delete leftpage;
00308   delete rightpage;
00309   delete bookmark;
00310   for (int i = 0; i < 9*8; i++)
00311     delete spells[i];
00312 }
00313 
00314 /*
00315  *  Perform a spell.
00316  */
00317 
00318 void Spellbook_gump::do_spell
00319   (
00320   int spell
00321   )
00322 {
00323   if (!book->can_do_spell(gwin->get_main_actor(), spell))
00324     Mouse::mouse->flash_shape(Mouse::redx);
00325   else
00326     {
00327     Spellbook_object *save_book = book;
00328     close();    // We've just been deleted!
00329     gwin->paint();
00330     gwin->show();
00331           // Don't need to check again.
00332     save_book->do_spell(gwin->get_main_actor(), spell, true);
00333           // Close all gumps so animations can
00334           //   start.
00335     gumpman->close_all_gumps();
00336     }
00337 }
00338 
00339 /*
00340  *  Change page.
00341  */
00342 
00343 void Spellbook_gump::change_page
00344   (
00345   int delta
00346   )
00347 {
00348   if (delta > 0)
00349     {
00350     if (page == 8)
00351       return;
00352     turning_page = -1;
00353     }
00354   else if (delta < 0)
00355     {
00356     if (page == 0)
00357       return;
00358     turning_page = 1;
00359     }
00360   ShapeID shape(TURNINGPAGE, 0, SF_GUMPS_VGA);
00361   int nframes = shape.get_num_frames();
00362   int i;
00363   turning_frame = turning_page == 1 ? 0 : nframes - 1;
00364   for (i = 0; i < nframes; i++) // Animate.
00365     {
00366     if (i == nframes/2)
00367       {
00368       page += delta;  // Change page halfway through.
00369       bookmark->set();// Update bookmark for new page.
00370       }
00371     gwin->add_dirty(get_rect());
00372     gwin->paint_dirty();
00373     gwin->show();
00374     SDL_Delay(50);    // 1/20 sec.
00375     }
00376   paint();
00377 }
00378 
00379 /*
00380  *  Set bookmark.
00381  */
00382 
00383 void Spellbook_gump::select_spell
00384   (
00385   int spell
00386   )
00387 {
00388   if (spells[spell])
00389   {
00390     book->bookmark = spell;
00391     bookmark->set();  // Update bookmark's position/frame.
00392     paint();
00393   }
00394 }
00395 
00396 /*
00397  *  Get object that 'owns' this.
00398  */
00399 Game_object *Spellbook_gump::get_owner()
00400 {
00401   return book; 
00402 }
00403 
00404 /*
00405  *  Is a given screen point on one of our buttons?
00406  *
00407  *  Output: ->button if so.
00408  */
00409 
00410 Gump_button *Spellbook_gump::on_button
00411   (
00412   int mx, int my      // Point in window.
00413   )
00414 {
00415   Gump_button *btn = Gump::on_button(mx, my);
00416   if (btn)
00417     return btn;
00418   else if (leftpage->on_button(mx, my))
00419     return leftpage;
00420   else if (rightpage->on_button(mx, my))
00421     return rightpage;
00422   int spindex = page*8;   // Index into list.
00423   for (int s = 0; s < 8; s++) // Check spells.
00424   {
00425     Gump_button *spell = spells[spindex + s];
00426     if (spell && spell->on_button(mx, my))
00427       return spell;
00428   }
00429   if (bookmark->on_button(mx, my))
00430     return bookmark;
00431   return 0;
00432 }
00433 
00434 /*
00435  *  Our buttons are never drawn 'pushed'.
00436  */
00437 
00438 void Spellbook_gump::paint_button
00439   (
00440   Gump_button *btn
00441   )
00442 {
00443   btn->paint();
00444 }
00445 
00446 /*
00447  *  Render.
00448  */
00449 
00450 void Spellbook_gump::paint
00451   (
00452   )
00453 {
00454   const int numx = 1, numy = -4;// Where to draw numbers on spells,
00455           //   with numx being the right edge.
00456   Gump::paint();      // Paint outside & checkmark.
00457   if (page > 0)     // Not the first?
00458     paint_button(leftpage);
00459   if (page < 8)     // Not the last?
00460     paint_button(rightpage);
00461   int spindex = page*8;   // Index into list.
00462   for (int s = 0; s < 8; s++) // Paint spells.
00463     if (spells[spindex + s])
00464     {
00465       Gump_button *spell = spells[spindex + s];
00466       paint_button(spell);
00467       if (page == 0)  // No quantities for 1st circle.
00468         continue;
00469       int num = avail[spindex + s];
00470       char text[6];
00471       if (num > 0 && num < 1000)
00472         {
00473         snprintf(text, 6, "%d", num < 100 ? num : 99);
00474         sman->paint_text(5, text,
00475           x + spell->x + numx -
00476             sman->get_text_width(4, text),
00477           y + spell->y + numy);
00478         }
00479       else if (num >= 1000) // Fake an 'infinity'.
00480         {
00481         std::strcpy(text, "oo");
00482         int px = x + spell->x + numx + 2 -
00483             sman->get_text_width(4, text);
00484         sman->paint_text(5, text + 1, px,
00485           y + spell->y + numy);
00486         sman->paint_text(5, text + 1, px + 3,
00487           y + spell->y + numy);
00488         }
00489     }
00490   if (page > 0 ||     // Paint circle.
00491       Game::get_game_type() == SERPENT_ISLE)
00492   {
00493     char *circ = item_names[CIRCLE];
00494     char *cnum = item_names[CIRCLENUM + page];
00495     sman->paint_text(5, cnum, x + 40 + 
00496       (44 - sman->get_text_width(4, cnum))/2, y + 20);
00497     sman->paint_text(5, circ, x + 92 +
00498       (44 - sman->get_text_width(4, circ))/2, y + 20);
00499   }
00500   if (book->bookmark >= 0)  // Bookmark?
00501     paint_button(bookmark);
00502   if (turning_page)   // Animate turning page.
00503     {
00504     const int TPXOFF = 5, TPYOFF = 3;
00505     ShapeID shape(TURNINGPAGE, turning_frame, SF_GUMPS_VGA);
00506     Shape_frame *fr = shape.get_shape();
00507     int spritex = x + object_area.x + fr->get_xleft() + TPXOFF;
00508     int spritey = y + fr->get_yabove() + TPYOFF;
00509     shape.paint_shape(spritex, spritey);
00510     turning_frame += turning_page;
00511     if (turning_frame < 0 || turning_frame >= 
00512             shape.get_num_frames())
00513       turning_page = 0; // Last one.
00514     }
00515   gwin->set_painted();
00516 }
00517 
00518 /*
00519  *  Create spellscroll display.
00520  */
00521 
00522 Spellscroll_gump::Spellscroll_gump
00523   (
00524   Game_object *s
00525   ) : Spelltype_gump(65), scroll(s), spell(0)
00526   {
00527   set_object_area(Rectangle(30, 29, 50, 29), 8, 68);
00528 
00529           // Get dims. of a spell.
00530   Shape_frame *spshape = ShapeID(SCROLLSPELLS, 0, SF_GUMPS_VGA).get_shape();
00531   spwidth = spshape->get_width();
00532   spheight = spshape->get_height();
00533   int spellnum = scroll->get_quality();
00534   if (spellnum >= 0 && spellnum < 8*9)
00535     spell = new Spell_button(this, 
00536         object_area.x + 4 + spshape->get_xleft(), 
00537         object_area.y + 4 + spshape->get_yabove(), 
00538         spellnum, SCROLLSPELLS + spellnum/8,
00539         spellnum%8);
00540   }
00541 
00542 /*
00543  *  Delete.
00544  */
00545 
00546 Spellscroll_gump::~Spellscroll_gump
00547   (
00548   )
00549   {
00550   delete spell;
00551   }
00552 
00553 /*
00554  *  Perform the spell.
00555  */
00556 
00557 void Spellscroll_gump::do_spell
00558   (
00559   int spellnum
00560   )
00561   {
00562   scroll->remove_this();    // Scroll is gone.
00563   scroll = 0;
00564   close();      // We've just been deleted!
00565   gwin->paint();
00566   gwin->show();
00567   Spellbook_object::execute_spell(gwin->get_main_actor(), spellnum);
00568   }
00569 
00570 /*
00571  *  Return scroll.
00572  */
00573 
00574 Game_object *Spellscroll_gump::get_owner
00575   (
00576   )
00577   {
00578   return scroll;
00579   }
00580 
00581 /*
00582  *  Is a given screen point on one of our buttons?
00583  *
00584  *  Output: ->button if so.
00585  */
00586 
00587 Gump_button *Spellscroll_gump::on_button
00588   (
00589   int mx, int my      // Point in window.
00590   )
00591   {
00592   Gump_button *btn = Gump::on_button(mx, my);
00593   if (btn)
00594     return btn;
00595   else if (spell && spell->on_button(mx, my))
00596     return spell;
00597   return 0;
00598   }
00599 
00600 /*
00601  *  Our buttons are never drawn 'pushed'.
00602  */
00603 
00604 void Spellscroll_gump::paint_button
00605   (
00606   Gump_button *btn
00607   )
00608   {
00609   btn->paint();
00610   }
00611 
00612 /*
00613  *  Render.
00614  */
00615 
00616 void Spellscroll_gump::paint
00617   (
00618   )
00619   {
00620   Gump::paint();      // Paint outside & checkmark.
00621   if (spell)
00622     paint_button(spell);
00623   gwin->set_painted();
00624   }
00625 

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