npctime.cc

Go to the documentation of this file.
00001 /*
00002  *  Npctime.cc - Timed-even handlers for NPC's.
00003  *
00004  *  Copyright (C) 2000-2001  The Exult Team
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; either version 2 of the License, or
00009  *  (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00019  */
00020 
00021 #ifdef HAVE_CONFIG_H
00022 #  include <config.h>
00023 #endif
00024 
00025 #include "npctime.h"
00026 #include "gamewin.h"
00027 #include "gameclk.h"
00028 #include "actors.h"
00029 #include "items.h"
00030 #include "schedule.h"
00031 #include "game.h"
00032 
00033 #ifndef UNDER_CE
00034 using std::rand;
00035 #endif
00036 
00037 extern bool god_mode;
00038 
00039 /*
00040  *  Base class for keeping track of things like poison, protection, hunger.
00041  */
00042 class Npc_timer : public Time_sensitive, public Game_singletons
00043   {
00044 protected:
00045   Npc_timer_list *list;   // Where NPC stores ->this.
00046   uint32 get_minute();  // Get game minutes.
00047 public:
00048   Npc_timer(Npc_timer_list *l, int start_delay = 0);
00049   virtual ~Npc_timer();
00050   };
00051 
00052 /*
00053  *  Handle starvation.
00054  */
00055 class Npc_hunger_timer : public Npc_timer
00056   {
00057   uint32 last_time; // Last game minute when penalized.
00058 public:
00059   Npc_hunger_timer(Npc_timer_list *l) : Npc_timer(l, 5000)
00060     { last_time = get_minute(); }
00061   virtual ~Npc_hunger_timer();
00062           // Handle events:
00063   void handle_event(unsigned long curtime, long udata);
00064   };
00065 
00066 /*
00067  *  Handle poison.
00068  */
00069 class Npc_poison_timer : public Npc_timer
00070   {
00071   uint32 end_time;    // Time when it wears off.
00072 public:
00073   Npc_poison_timer(Npc_timer_list *l);
00074   virtual ~Npc_poison_timer();
00075           // Handle events:
00076   void handle_event(unsigned long curtime, long udata);
00077   };
00078 
00079 /*
00080  *  Handle sleep.
00081  */
00082 class Npc_sleep_timer : public Npc_timer
00083   {
00084   uint32 end_time;    // Time when it wears off.
00085 public:
00086   Npc_sleep_timer(Npc_timer_list *l) : Npc_timer(l)
00087     {     // Lasts 5-10 seconds..
00088     end_time = Game::get_ticks() + 5000 + rand()%5000;
00089     }
00090   virtual ~Npc_sleep_timer()
00091     { list->sleep = 0; }
00092           // Handle events:
00093   void handle_event(unsigned long curtime, long udata);
00094   };
00095 
00096 /*
00097  *  Invisibility timer.
00098  */
00099 class Npc_invisibility_timer : public Npc_timer
00100   {
00101   uint32 end_time;    // Time when it wears off.
00102 public:
00103   Npc_invisibility_timer(Npc_timer_list *l) : Npc_timer(l)
00104     {     // Lasts 60-80 seconds..
00105     end_time = Game::get_ticks() + 60000 + rand()%20000;
00106     }
00107   virtual ~Npc_invisibility_timer()
00108     { list->invisibility = 0; }
00109           // Handle events:
00110   void handle_event(unsigned long curtime, long udata);
00111   };
00112 
00113 /*
00114  *  Protection timer.
00115  */
00116 class Npc_protection_timer : public Npc_timer
00117   {
00118   uint32 end_time;    // Time when it wears off.
00119 public:
00120   Npc_protection_timer(Npc_timer_list *l) : Npc_timer(l)
00121     {     // Lasts 60-80 seconds..
00122     end_time = Game::get_ticks() + 60000 + rand()%20000;
00123     }
00124   virtual ~Npc_protection_timer()
00125     { list->protection = 0; }
00126           // Handle events:
00127   void handle_event(unsigned long curtime, long udata);
00128   };
00129 
00130 /*
00131  *  Timer for flags that don't need any other checks.
00132  */
00133 class Npc_flag_timer : public Npc_timer
00134   {
00135   int flag;     // Flag # in Obj_flags.
00136   uint32 end_time;    // Time when it wears off.
00137   Npc_flag_timer **listloc; // Where it's stored in Npc_timer_list.
00138 public:
00139   Npc_flag_timer(Npc_timer_list *l, int f, Npc_flag_timer **loc) 
00140     : Npc_timer(l), flag(f), listloc(loc)
00141     {     // Lasts 60-120 seconds..
00142     end_time = Game::get_ticks() + 60000 + rand()%60000;
00143     }
00144   virtual ~Npc_flag_timer()
00145     { *listloc = 0; }
00146           // Handle events:
00147   void handle_event(unsigned long curtime, long udata);
00148   };
00149 
00150 
00151 /*
00152  *  Delete list.
00153  */
00154 
00155 Npc_timer_list::~Npc_timer_list
00156   (
00157   )
00158   {
00159   delete hunger;
00160   delete poison;
00161   delete sleep;
00162   delete invisibility;
00163   delete protection;
00164   delete might;
00165   delete curse;
00166   delete paralyze;
00167   }
00168 
00169 /*
00170  *  Start hunger (if not already there).
00171  */
00172 
00173 void Npc_timer_list::start_hunger
00174   (
00175   )
00176   {
00177   if (!hunger)      // Not already there?
00178     hunger = new Npc_hunger_timer(this);
00179   }
00180 
00181 /*
00182  *  Start poison.
00183  */
00184 
00185 void Npc_timer_list::start_poison
00186   (
00187   )
00188   {
00189   if (poison)     // Remove old one.
00190     delete poison;
00191   poison = new Npc_poison_timer(this);
00192   }
00193 
00194 /*
00195  *  Start sleep.
00196  */
00197 
00198 void Npc_timer_list::start_sleep
00199   (
00200   )
00201   {
00202   if (sleep)      // Remove old one.
00203     delete sleep;
00204   sleep = new Npc_sleep_timer(this);
00205   }
00206 
00207 /*
00208  *  Start invisibility.
00209  */
00210 
00211 void Npc_timer_list::start_invisibility
00212   (
00213   )
00214   {
00215   if (invisibility)     // Remove old one.
00216     delete invisibility;
00217   invisibility = new Npc_invisibility_timer(this);
00218   }
00219 
00220 /*
00221  *  Start protection.
00222  */
00223 
00224 void Npc_timer_list::start_protection
00225   (
00226   )
00227   {
00228   if (protection)     // Remove old one.
00229     delete protection;
00230   protection = new Npc_protection_timer(this);
00231   }
00232 
00233 
00234 /*
00235  *  Start might.
00236  */
00237 
00238 void Npc_timer_list::start_might
00239   (
00240   )
00241   {
00242   if (might)      // Remove old one.
00243     delete might;
00244   might = new Npc_flag_timer(this, Obj_flags::might, &might);
00245   }
00246 
00247 /*
00248  *  Start curse.
00249  */
00250 
00251 void Npc_timer_list::start_curse
00252   (
00253   )
00254   {
00255   if (curse)      // Remove old one.
00256     delete curse;
00257   curse = new Npc_flag_timer(this, Obj_flags::cursed, &curse);
00258   }
00259 
00260 /*
00261  *  Start paralyze.
00262  */
00263 
00264 void Npc_timer_list::start_paralyze
00265   (
00266   )
00267   {
00268   if (paralyze)     // Remove old one.
00269     delete paralyze;
00270   paralyze = new Npc_flag_timer(this, Obj_flags::paralyzed, &paralyze);
00271   }
00272 
00273 /*
00274  *  Get game minute from start.
00275  */
00276 
00277 uint32 Npc_timer::get_minute
00278   (
00279   )
00280   {
00281   Game_window *gwin = Game_window::get_instance();
00282   return 60*gclock->get_total_hours() + gclock->get_minute();
00283   }
00284 
00285 /*
00286  *  Start timer.
00287  */
00288 
00289 Npc_timer::Npc_timer
00290   (
00291   Npc_timer_list *l,
00292   int start_delay     // Time in msecs. before starting.
00293   ) : list(l)
00294   {
00295   gwin->get_tqueue()->add(Game::get_ticks() + start_delay, this, 0L);
00296   }
00297 
00298 /*
00299  *  Be sure we're no longer in the time queue.
00300  */
00301 
00302 Npc_timer::~Npc_timer
00303   (
00304   )
00305   {
00306   if (in_queue())
00307     {
00308     Time_queue *tq = Game_window::get_instance()->get_tqueue();
00309     tq->remove(this);
00310     }
00311   }
00312 
00313 /*
00314  *  Done with hunger timer.
00315  */
00316 
00317 Npc_hunger_timer::~Npc_hunger_timer
00318   (
00319   )
00320   {
00321   list->hunger = 0;
00322   }
00323 
00324 /*
00325  *  Time to penalize for hunger.
00326  */
00327 
00328 void Npc_hunger_timer::handle_event
00329   (
00330   unsigned long curtime, 
00331   long udata
00332   )
00333   {
00334   Actor *npc = list->npc;
00335           // No longer a party member?
00336   if (!npc->is_in_party() ||
00337           //   or no longer hungry?
00338       npc->get_property(static_cast<int>(Actor::food_level)) >= 0 ||
00339       npc->is_dead())   // Obviously.
00340     {
00341     delete this;
00342     return;
00343     }
00344   uint32 minute = get_minute();
00345           // Once/hour.
00346   if (minute >= last_time + 60)
00347     {
00348     int hp = rand()%3;
00349     if (rand()%4)
00350       npc->say(first_starving, first_starving + 2);
00351     npc->reduce_health(hp);
00352 
00353 //    npc->set_property(static_cast<int>(Actor::health),
00354 //      npc->get_property(static_cast<int>(Actor::health)) - hp);
00355     last_time = minute;
00356     }
00357   gwin->get_tqueue()->add(curtime + 30000, this, 0L);
00358   }
00359 
00360 /*
00361  *  Initialize poison timer.
00362  */
00363 
00364 Npc_poison_timer::Npc_poison_timer
00365   (
00366   Npc_timer_list *l
00367   ) : Npc_timer(l, 5000)
00368   {
00369           // Lasts 1-3 minutes.
00370   end_time = Game::get_ticks() + 60000 + rand()%120000;
00371   }
00372 
00373 /*
00374  *  Done with poison timer.
00375  */
00376 
00377 Npc_poison_timer::~Npc_poison_timer
00378   (
00379   )
00380   {
00381   list->poison = 0;
00382   }
00383 
00384 /*
00385  *  Time to penalize for poison, or see if it's worn off.
00386  */
00387 
00388 void Npc_poison_timer::handle_event
00389   (
00390   unsigned long curtime, 
00391   long udata
00392   )
00393   {
00394   Actor *npc = list->npc;
00395   if (curtime >= end_time ||  // Long enough?  Or cured?
00396       npc->get_flag(Obj_flags::poisoned) == 0 ||
00397       npc->is_dead())   // Obviously.
00398     {
00399     npc->clear_flag(Obj_flags::poisoned);
00400     delete this;
00401     return;
00402     }
00403   int penalty = rand()%3;
00404   npc->reduce_health(penalty);
00405 
00406 //  npc->set_property(static_cast<int>(Actor::health),
00407 //    npc->get_property(static_cast<int>(Actor::health)) - penalty);
00408           // Check again in 10-20 secs.
00409   gwin->get_tqueue()->add(curtime + 10000 + rand()%10000, this, 0L);
00410   }
00411 
00412 /*
00413  *  Time to see if we should wake up.
00414  */
00415 
00416 void Npc_sleep_timer::handle_event
00417   (
00418   unsigned long curtime, 
00419   long udata
00420   )
00421   {
00422   Actor *npc = list->npc;
00423   if (curtime >= end_time ||  // Long enough?  Or cured?
00424       npc->get_flag(Obj_flags::asleep) == 0)
00425     {
00426           // Avoid waking Penumbra.
00427     if (npc->get_schedule_type() != Schedule::sleep &&
00428         !npc->is_dead())  // Don't wake the dead.
00429       {
00430       npc->clear_flag(Obj_flags::asleep);
00431       int frnum = npc->get_framenum();
00432       if ((frnum&0xf) == Actor::sleep_frame &&
00433           // Slimes don't change.
00434           !npc->get_info().has_strange_movement())
00435           // Stand up.
00436         npc->change_frame(
00437           Actor::standing | (frnum&0x30));
00438       }
00439     delete this;
00440     return;
00441     }
00442           // Check again in 2 secs.
00443   gwin->get_tqueue()->add(curtime + 2000, this, 0L);
00444   }
00445 
00446 /*
00447  *  Check for a given ring.
00448  */
00449 
00450 inline int Wearing_ring
00451   (
00452   Actor *actor,
00453   int shnum,      // Ring shape to look for.
00454   int frnum
00455   )
00456   {
00457           // See if wearing ring.
00458   Game_object *ring = actor->get_readied(Actor::lfinger);
00459   if (ring && ring->get_shapenum() == shnum &&
00460       ring->get_framenum() == frnum)
00461     return 1;
00462   ring = actor->get_readied(Actor::rfinger);
00463   if (ring && ring->get_shapenum() == shnum &&
00464       ring->get_framenum() == frnum)
00465     return 1;
00466   return 0;
00467   }
00468 
00469 /*
00470  *  See if invisibility wore off.
00471  */
00472 
00473 void Npc_invisibility_timer::handle_event
00474   (
00475   unsigned long curtime, 
00476   long udata
00477   )
00478   {
00479   Actor *npc = list->npc;
00480   if (Wearing_ring(npc, 296, 0))  // (Works for SI and BG.)
00481     {     // Wearing invisibility ring.
00482     delete this;    // Don't need timer.
00483     return;
00484     }
00485   if (curtime >= end_time ||  // Long enough?  Or cleared.
00486       npc->get_flag(Obj_flags::invisible) == 0)
00487     {
00488     npc->clear_flag(Obj_flags::invisible);
00489     if (!npc->is_dead())
00490       gwin->add_dirty(npc);
00491     delete this;
00492     return;
00493     }
00494           // Check again in 2 secs.
00495   gwin->get_tqueue()->add(curtime + 2000, this, 0L);
00496   }
00497 
00498 /*
00499  *  See if protection wore off.
00500  */
00501 
00502 void Npc_protection_timer::handle_event
00503   (
00504   unsigned long curtime, 
00505   long udata
00506   )
00507   {
00508   Actor *npc = list->npc;
00509   if (Wearing_ring(npc, 297, 0))  // ++++SI has an Amulet.
00510     {     // Wearing protection ring.
00511     delete this;    // Don't need timer.
00512     return;
00513     }
00514   if (curtime >= end_time ||  // Long enough?  Or cleared.
00515       npc->get_flag(Obj_flags::protection) == 0)
00516     {
00517     npc->clear_flag(Obj_flags::protection);
00518     if (!npc->is_dead())
00519       gwin->add_dirty(npc);
00520     delete this;
00521     return;
00522     }
00523           // Check again in 2 secs.
00524   gwin->get_tqueue()->add(curtime + 2000, this, 0L);
00525   }
00526 
00527 /*
00528  *  Might/curse/paralyze wore off.
00529  */
00530 
00531 void Npc_flag_timer::handle_event
00532   (
00533   unsigned long curtime, 
00534   long udata
00535   )
00536   {
00537   Actor *npc = list->npc;
00538   if (curtime >= end_time ||  // Long enough?  Or cleared.
00539       npc->get_flag(flag) == 0)
00540     {
00541     npc->clear_flag(flag);
00542     delete this;
00543     }
00544   else        // Check again in 10 secs.
00545     gwin->get_tqueue()->add(curtime + 10000, this, 0L);
00546   }
00547 

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