/[enigma]/enigma/src/world.cc
ViewVC logotype

Diff of /enigma/src/world.cc

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.72.2.1 by dheck, Fri Sep 19 17:42:38 2003 UTC revision 1.72.2.2 by dheck, Mon Sep 22 02:49:35 2003 UTC
# Line 46  using namespace std; Line 46  using namespace std;
46  using namespace world;  using namespace world;
47  using namespace px;  using namespace px;
48    
49    #include "world_internal.hh"
50    
51  namespace  namespace
52  {  {
     class Field;  
   
     typedef px::Array2<Field> FieldArray;  
     typedef std::vector<Actor*> ActorList;  
   
     typedef vector<ForceField*> ForceList;  
     typedef vector<StoneContact> StoneContactList;  
53  }  }
54    
55  namespace  Object *SimpleSignal::get_target()
56  {  {
57      Object *GetObject (const GridLoc &l)      return GetObject(destloc);
58      {  }
         switch (l.layer) {  
         case GRID_FLOOR:  return GetFloor(l.pos);  
         case GRID_ITEMS:  return GetItem(l.pos);  
         case GRID_STONES: return GetStone(l.pos);  
         default: return 0;  
         }  
     }  
   
     class Signal {  
     public:  
         virtual ~Signal() {};  
         virtual void emit_from(Object *source, int value) = 0;  
         virtual Object *get_target() = 0;  
         virtual Object *get_source() = 0;  
     };  
59    
     class SimpleSignal : public Signal {  
     public:  
         SimpleSignal (Object *src, GridLoc dstloc, const string &msg)  
         : source (src), destloc(dstloc), message(msg)  
         {}  
60    
61          Object *get_target() {  void SimpleSignal::emit_from (Object *src, int value)
62              return GetObject(destloc);  {
63          }      if (source == src) {
64          Object *get_source() {          Object *dst = get_target();
             return source;  
         }  
   
         void emit_from (Object *src, int value) {  
             if (source == src) {  
                 Object *dst = get_target();  
65    
66  #if defined(VERBOSE_MESSAGES)  #if defined(VERBOSE_MESSAGES)
67                  src->warning("emit_from: msg='%s' dest=%i/%i obj=%p",          src->warning("emit_from: msg='%s' dest=%i/%i obj=%p",
68                               message.c_str(),                       message.c_str(),
69                               destloc.pos.x, destloc.pos.y,                       destloc.pos.x, destloc.pos.y,
70                               dst);                       dst);
71  #endif // VERBOSE_MESSAGES  #endif
72            SendMessage (dst, message, value);
73                  SendMessage (dst, message, value);      }
             }  
74  #if defined(VERBOSE_MESSAGES)  #if defined(VERBOSE_MESSAGES)
75  //             else {      else {
76  //                 fprintf(stderr,          fprintf(stderr,
77  //                         "emit_from source object does not match -- signal '%s' dropped (expected=%p=%s found=%p=%s)\n",                  "emit_from source object does not match\n"
78  //                         message.c_str(), source, source->get_kind(), src, src->get_kind());                  "signal '%s' dropped (expected=%p=%s found=%p=%s)\n",
79  //             }                  message.c_str(), source, source->get_kind(), src, src->get_kind());
80  #endif // VERBOSE_MESSAGES      }
81          }  #endif
82      private:  }
         Object *source;  
         GridLoc destloc;  
         string message;  
     };  
   
     class SignalList {  
         typedef vector<Signal *> ListT;  
         ListT m_signals;  
   
     public:  
         ~SignalList() { clear(); }  
         void clear() {  
             delete_sequence (m_signals.begin(), m_signals.end());  
             m_signals.clear();  
         }  
83    
84          void add (Signal *sig) { m_signals.push_back(sig); }  void SignalList::emit_from (Object *source, int value)
85    {
86        // signals may have side effects. To minimize them
87        //   1. collect all targets and then
88        //   2. emit signals to targets
89    
90          void emit_from (Object *source, int value) {      size_t          size = m_signals.size();
91              // signals may have side effects. To minimize them      vector<Object*> targets;
92              //   1. collect all targets and then      targets.resize(size);
             //   2. emit signals to targets  
93    
94              size_t          size = m_signals.size();      for (unsigned i=0; i<size; ++i) {
95              vector<Object*> targets;          targets[i] = m_signals[i]->get_target();
96              targets.resize(size);      }
97    
98              for (unsigned i=0; i<size; ++i) {      for (unsigned i=0; i<size; ++i) {
99                  targets[i] = m_signals[i]->get_target();          if (m_signals[i]->get_target() == targets[i])
100              }              m_signals[i]->emit_from (source, value);
101        }
102    }
103    
104              for (unsigned i=0; i<size; ++i) {  Object *SignalList::find_single_destination(Object *src)
105                  if (m_signals[i]->get_target() == targets[i])  {
106                      m_signals[i]->emit_from (source, value);      Object *found = 0;
107              }      size_t size = m_signals.size();
         }  
108    
109          Object *find_single_destination(Object *src) {      for (unsigned i = 0; i<size; ++i) {
110              Object *found = 0;          if (m_signals[i]->get_source() == src) {
111              size_t size = m_signals.size();              Object *candidate = m_signals[i]->get_target();
112                if (candidate) {
113              for (unsigned i = 0; i<size; ++i) {                  if (!found)
114                  if (m_signals[i]->get_source() == src) {                      found = candidate;
115                      Object *candidate = m_signals[i]->get_target();                  else if (candidate != found) {
116                      if (candidate) {                      found = 0; // multiple targets
117                          if (!found)                      break;
                             found = candidate;  
                         else if (candidate != found) {  
                             found = 0; // multiple targets  
                             break;  
                         }  
                     }  
118                  }                  }
119              }              }
   
             return found;  
120          }          }
121      };      }
122    
123        return found;
124  }  }
125    
126  //----------------------------------------  //----------------------------------------
127  // Rubber band  // Rubber band
128  //----------------------------------------  //----------------------------------------
 namespace world  
 {  
     class RubberBand {  
     public:  
         RubberBand (Actor *a1, Actor *a2, double strength=10, double length=2);  
         RubberBand (Actor *a1, Stone *st, double strength=10, double length=2);  
         ~RubberBand();  
   
         void tick(double);  
         V2 get_force(Actor *a);  
   
         Actor *get_actor() const { return actor; }  
         Actor *get_actor2() const { return actor2; }  
         Stone *get_stone() const { return stone; }  
   
         double get_strength() const { return strength; }  
         double get_length() const { return length; }  
     private:  
         V2 get_p1() const;  
         V2 get_p2() const;  
   
         // Variables.  
         Actor *actor, *actor2;  
         Stone *stone;  
         display::RubberHandle model;  
         double strength, length;  
     };  
 }  
129    
130  RubberBand::RubberBand (Actor *a1, Actor *a2, double strength_, double length_)  RubberBand::RubberBand (Actor *a1, Actor *a2, double strength_, double length_)
131  : actor(a1), actor2(a2), stone(0),  : actor(a1), actor2(a2), stone(0),
# Line 264  V2 RubberBand::get_p2() const Line 187  V2 RubberBand::get_p2() const
187  //----------------------------------------  //----------------------------------------
188  // Field  // Field
189  //----------------------------------------  //----------------------------------------
 namespace  
 {  
     class Field {  
     public:  
         Field();  
         ~Field();  
   
         Floor *floor;  
         Item *item;  
         Stone *stone;  
     };  
 }  
   
190    
191  Field::Field()  Field::Field()
192  {  {
# Line 292  Field::~Field() Line 202  Field::~Field()
202      DisposeObject(stone);      DisposeObject(stone);
203  }  }
204    
 /*  
 ** This class implements the "force field" that accelerates objects  
 ** when the mouse is moved.  Only objects that have the "mouseforce"  
 ** attribute set are affected by this force field.  
 */  
 namespace  
 {  
     class MouseForce {  
     public:  
         void set_force(V2 f) { force=f; }  
         void add_force(V2 f) { force+=f; }  
   
         V2 get_force(Actor *a) {  
             double mouseforce = 0;  
             a->double_attrib("mouseforce", &mouseforce);  
             if (a->is_flying() || a->is_dead())  
                 return V2();  
             else  
                 return force * mouseforce;  
         }  
205    
206          void tick(double /*dtime*/) {  //----------------------------------------
207              force=V2();  // StoneContact
208          }  //----------------------------------------
     private:  
         V2 force;  
     };  
 }  
209    
210  StoneContact::StoneContact(Actor *a, GridPos p,  StoneContact::StoneContact(Actor *a, GridPos p,
211                             const V2 &cp, const V2 &n)                             const V2 &cp, const V2 &n)
# Line 375  world::contact_face(const StoneContact & Line 261  world::contact_face(const StoneContact &
261          return NODIR;          return NODIR;
262  }  }
263    
 // ------------------  
 //      Scrambles  
 // ------------------  
 // Stores all positions plus direction where puzzle scrambling should be done.  
   
 namespace  
 {  
     struct Scramble {  
         GridPos   pos;  
         Direction dir;  
         int       intensity;  
   
         Scramble(GridPos p, Direction d, int i) : pos(p), dir(d), intensity(i) {}  
   
         bool expired() const { return intensity<1; }  
     };  
 }  
   
   
   
 //======================================================================  
 // VARIABLES  
 //======================================================================  
   
 namespace  
 {  
     class World {  
     public:  
         virtual ~World() {}  
         virtual void name_object (Object *obj, const string &name) = 0;  
     };  
   
     class WorldImpl : public World {  
     public:  
         WorldImpl(int ww, int hh);  
         ~WorldImpl();  
   
         bool contains (GridPos p) {  
             return (p.x>=0 && p.y>=0 && p.x<w && p.y<h);  
         }  
   
         bool is_border (GridPos p) {  
             return(p.x==0 || p.y==0 || p.x==w-1 || p.y==h-1);  
         }  
   
         Field *get_field (GridPos p) {  
             if (this->contains(p))  
                 return &fields(p.x,p.y);  
             else  
                 return 0;  
         }  
   
         void    name_object (Object *obj, const string &name);  
         void    unname (Object *);  
         Object *get_named (const string &);  
   
         void tick (double dtime);  
         void remove (ForceField *ff);  
   
         void add_scramble(GridPos p, Direction dir);  
         void scramble_puzzles();  
   
     public:  
         // Variables.  
         FieldArray           fields; // Contains floors, items, etc.  
         int                  w, h; // Width and height of the level  
         ForceList            forces;  
         ActorList            actorlist; // List of movable, dynamic objects  
         vector<RubberBand *> rubbers;  
         SignalList           signals;  
         MouseForce           mouseforce;  
         int                  scrambleIntensity;  
   
     private:  
         /* Objects can be named with NameObject and referenced with  
            GetNamedObject.  This dictionary maps the names to the  
            actual objects. */  
         px::Dict<Object *> m_objnames;  
   
         list<Scramble> scrambles;  
     };  
   
     auto_ptr<WorldImpl> level;  
 }  
   
264    
265  WorldImpl::WorldImpl(int ww, int hh) : fields(ww,hh)  WorldImpl::WorldImpl(int ww, int hh) : fields(ww,hh)
266  {  {
# Line 523  enigma::Timer world::g_timer; Line 324  enigma::Timer world::g_timer;
324    
325  void WorldImpl::add_scramble(GridPos p, Direction dir)  void WorldImpl::add_scramble(GridPos p, Direction dir)
326  {  {
327      // fprintf(stderr, "scrambles.size()=%i ; add_scramble(%i, %i, %s)\n", scrambles.size(), p.x, p.y, to_suffix(dir).c_str());      // fprintf(stderr, "scrambles.size()=%i ; add_scramble(%i, %i, %s)\n",
328        //         scrambles.size(), p.x, p.y, to_suffix(dir).c_str());
329      scrambles.push_back(Scramble(p, dir, scrambleIntensity));      scrambles.push_back(Scramble(p, dir, scrambleIntensity));
330  }  }
331    
# Line 553  void WorldImpl::scramble_puzzles() Line 355  void WorldImpl::scramble_puzzles()
355    
356    
357  //======================================================================  //======================================================================
358    // VARIABLES
359    //======================================================================
360    
361    namespace
362    {
363        auto_ptr<WorldImpl> level;
364    }
365    
366    
367    
368    //======================================================================
369  // PHYSICS SIMULATION  // PHYSICS SIMULATION
370  //======================================================================  //======================================================================
371    
372  /* Calculate the total acceleration on an actor A at time TIME.  The  /*
373     actor's current position X and velocity V are also passed.  Note  ** Calculate the total acceleration on an actor A at time TIME.  The
374     that the position and velocity entries in ActorInfo will be updated  ** actor's current position X and velocity V are also passed.  [Note
375     only after a *successful* time step, so they cannot be used  ** that the position and velocity entries in ActorInfo will be updated
376     here. */  ** only after a *successful* time step, so they cannot be used here.]
377    */
378  static V2  static V2
379  get_accel (Actor *a, const V2 & x, const V2 & v, double time)  get_accel (Actor *a, const V2 & x, const V2 & v, double time)
380  {  {
# Line 791  find_stone_contacts (Actor *a, StoneCont Line 605  find_stone_contacts (Actor *a, StoneCont
605  }  }
606    
607    
608  /* This function is called for every contact between an actor and a  /*
609     stone.  It is here that the stones are informed about contacts.  ** This function is called for every contact between an actor and a
610     Note that a stone may kill itself during a call to actor_hit() or  ** stone.  It is here that the stones are informed about contacts.
611     actor_contact() so we must not refer to it after having called  ** Note that a stone may kill itself during a call to actor_hit() or
612     these functions.  (Incidentally, this is why StoneContact only  ** actor_contact() so we must not refer to it after having called
613     contains a 'stonepos' and no 'stone' entry.)  ** these functions.  (Incidentally, this is why StoneContact only
614    ** contains a 'stonepos' and no 'stone' entry.)
615  */  */
616  static void  static void
617  handle_stone_contact (StoneContact &sc, double total_dtime)  handle_stone_contact (StoneContact &sc, double total_dtime)
618  {  {
619      Actor *a = sc.actor;      Actor     *a  = sc.actor;
620      ActorInfo &ai = *a->get_actorinfo();      ActorInfo &ai = *a->get_actorinfo();
621    
622      if (sc.is_collision) {      if (sc.is_collision) {
# Line 810  handle_stone_contact (StoneContact &sc, Line 625  handle_stone_contact (StoneContact &sc,
625              bool new_collision = false;              bool new_collision = false;
626              if (total_dtime != 0) {              if (total_dtime != 0) {
627                  double vn = (ai.pos - ai.last_pos)/total_dtime * sc.normal;                  double vn = (ai.pos - ai.last_pos)/total_dtime * sc.normal;
628                  new_collision = (vn < -0.5);                  new_collision = (vn < -0.25);
629              }              }
630    
631                ai.pos = ai.oldpos;         // Reset actor position
632              if (new_collision) {              if (new_collision) {
633                  if (Stone *stone = world::GetStone(sc.stonepos)) {                  if (Stone *stone = world::GetStone(sc.stonepos)) {
634                      V2 pos = ai.pos;  //                     V2 pos = ai.pos;
635                      stone->actor_hit(sc);                      stone->actor_hit(sc);
636                      if (ai.pos != pos) { // actor position was changed by actor_hit() (e.g. turnstile, pull-stone)  //                     if (ai.pos != pos) {
637                          ai.oldpos = ai.pos; // HACK: avoid resetting actors position  //                         actor position was changed by actor_hit() (e.g. turnstile, pull-stone)
638                      }  //                         ai.oldpos = ai.pos; // HACK: avoid resetting actors position
639    //                     }
640                  }                  }
641  //             if (length(ai->vel) > 0.1) {  //             if (length(ai->vel) > 0.1) {
642                  display::AddEffect (sc.contact_point, "ring-anim");                  display::AddEffect (sc.contact_point, "ring-anim");
643                  sound::PlaySound(sc.sound.c_str(), sc.contact_point);                  sound::PlaySound(sc.sound.c_str(), sc.contact_point);
644  //             }  //             }
645              }              }
646              double restitution = 0.95;              double restitution = 1.0; //0.95;
647              ai.vel -= (1 + restitution)*(ai.vel*sc.normal)*sc.normal;              ai.vel -= (1 + restitution)*(ai.vel*sc.normal)*sc.normal;
             ai.pos = ai.oldpos;         // Reset actor position  
648          }          }
649      }      }
650      else if (sc.is_contact) {      else if (sc.is_contact) {
# Line 843  handle_contacts(Actor *actor1, double to Line 659  handle_contacts(Actor *actor1, double to
659      ActorInfo &a1 = *actor1->get_actorinfo();      ActorInfo &a1 = *actor1->get_actorinfo();
660    
661      /*      /*
662      ** Handle contacts with stones       * Handle contacts with stones
663      */       */
664      StoneContactList cl;      StoneContactList cl;
665      find_stone_contacts(actor1, cl);      find_stone_contacts(actor1, cl);
666      for (StoneContactList::iterator i=cl.begin();      for (StoneContactList::iterator i=cl.begin();
# Line 854  handle_contacts(Actor *actor1, double to Line 670  handle_contacts(Actor *actor1, double to
670      }      }
671    
672      /*      /*
673      ** Handle contacts with other actors       * Handle contacts with other actors
674      */       */
675      V2     p1 = a1.pos;      V2     p1 = a1.pos;
676      double r1 = a1.radius;      double r1 = a1.radius;
677      double m1 = a1.mass;      double m1 = a1.mass;
# Line 884  handle_contacts(Actor *actor1, double to Line 700  handle_contacts(Actor *actor1, double to
700              bool collisionp = (v2-v1)*(p2-p1) < 0;              bool collisionp = (v2-v1)*(p2-p1) < 0;
701              bool reboundp = (!actor1->is_dead() && !actor2->is_dead() &&              bool reboundp = (!actor1->is_dead() && !actor2->is_dead() &&
702                               (actor1->is_on_floor() == actor2->is_on_floor()));                               (actor1->is_on_floor() == actor2->is_on_floor()));
 //     if (!actor1->is_on_floor() || actor1->is_dead())  
 //         return;  
   
 //         if (!actor2->is_on_floor() || actor2->is_dead())  
 //             continue;  
703    
704              if (collisionp) {              if (collisionp) {
705                  double m2 = a2.mass;                  double m2 = a2.mass;
# Line 918  tick_actor(Actor *a, double dtime) Line 729  tick_actor(Actor *a, double dtime)
729      ActorInfo &ai = * a->get_actorinfo();      ActorInfo &ai = * a->get_actorinfo();
730    
731      ai.last_pos = ai.pos;      ai.last_pos = ai.pos;
     ai.oldpos = ai.pos;  
     ai.oldvel = ai.vel;  
732    
733      double rest_time = dtime;      double rest_time = dtime;
734      double dt = 0.005; //dtime;      double dt = 0.0025; //dtime;
735    
736      handle_contacts(a, 0.0);      handle_contacts(a, 0.0);
737      while (rest_time > 0 && !ai.grabbed)      while (rest_time > 0 && !ai.grabbed)
738      {      {
739          advance_actor(a, dtime-rest_time, dt);          advance_actor(a, dtime-rest_time, dt);
740            handle_contacts(a, dtime-rest_time);
         double l = length(ai.pos-ai.oldpos);  
   
         // time step too large? try again  
         if (l > 0.04 && dt > 1/1000.) {  
             dt /= 2;  
             ai.pos = ai.oldpos;  
             ai.vel = ai.oldvel;  
             continue;  
         }  
   
         // ok, accept this step  
741          a->move();          a->move();
742          rest_time -= dt;          rest_time -= dt;
   
         handle_contacts(a, dtime-rest_time);  
   
         ai.oldpos  = ai.pos;  
         ai.oldvel  = ai.vel;  
   
         // time step too small?  
         if (l < 0.01) {  
             dt *= 2;  
             dt = dt > rest_time? rest_time : dt;  
         }  
743      }      }
744  }  }
745    
# Line 1026  bool world::InitWorld() Line 813  bool world::InitWorld()
813      return true;      return true;
814  }  }
815    
816  void world::SetMouseForce(V2 f) {  void world::SetMouseForce(V2 f)
817    {
818      level->mouseforce.add_force(f);      level->mouseforce.add_force(f);
819  }  }
820    
821  void world::NameObject(Object *obj, const std::string &name) {  void world::NameObject(Object *obj, const std::string &name)
822    {
823      string old_name;      string old_name;
824      if (obj->string_attrib("name", &old_name)) {      if (obj->string_attrib("name", &old_name)) {
825          obj->warning("name '%s' overwritten by '%s'",          obj->warning("name '%s' overwritten by '%s'",
# Line 1040  void world::NameObject(Object *obj, cons Line 829  void world::NameObject(Object *obj, cons
829      level->name_object (obj, name);      level->name_object (obj, name);
830  }  }
831    
832  void world::UnnameObject(Object *obj) {  void world::UnnameObject(Object *obj)
833    {
834      level->unname(obj);      level->unname(obj);
835  }  }
836    
837  void  void world::TransferObjectName (Object *source, Object *target)
838  world::TransferObjectName(Object *source, Object *target) {  {
839      string name;      string name;
840      if (source->string_attrib("name", &name)) {      if (source->string_attrib("name", &name)) {
841          UnnameObject(source);          UnnameObject(source);
# Line 1059  world::TransferObjectName(Object *source Line 849  world::TransferObjectName(Object *source
849      }      }
850  }  }
851    
852  Object * world::GetNamedObject(const std::string &name) {  Object * world::GetNamedObject (const std::string &name)
853    {
854      return level->get_named (name);      return level->get_named (name);
855  }  }
856    
857  bool world::IsLevelBorder(GridPos p) {  bool world::IsLevelBorder(GridPos p)
858    {
859      return level->is_border(p);      return level->is_border(p);
860  }  }
861    
# Line 1071  bool world::IsLevelBorder(GridPos p) { Line 863  bool world::IsLevelBorder(GridPos p) {
863  // Force fields  // Force fields
864  //----------------------------------------  //----------------------------------------
865    
866    void world::AddForceField(ForceField *ff)
 void  
 world::AddForceField(ForceField *ff)  
867  {  {
868      level->forces.push_back(ff);      level->forces.push_back(ff);
869  }  }
# Line 1191  void world::EmitSignals (Object *src, in Line 981  void world::EmitSignals (Object *src, in
981      level->signals.emit_from (src, value);      level->signals.emit_from (src, value);
982  }  }
983    
984  // searches all signals for a signal starting at 'src'  /*
985  // returns the target object.  ** Searches all signals for a signal starting at 'src' and returns the
986  // if multiple signals start from 'src' this function  ** target object.  If multiple signals start from 'src' this function
987  // returns 0 if more than one target objects exists.  ** returns 0.
988    */
989  Object *world::FindSignalDestination(Object *src)  Object *world::FindSignalDestination(Object *src)
990  {  {
991      return level->signals.find_single_destination(src);      return level->signals.find_single_destination(src);
# Line 1305  namespace Line 1096  namespace
1096    
1097  }  }
1098    
   
   
1099  namespace  namespace
1100  {  {
1101      FloorLayer      fl_layer;      FloorLayer      fl_layer;
# Line 1316  namespace Line 1105  namespace
1105    
1106      // delayed impulses :      // delayed impulses :
1107    
     class DelayedImpulse {  
         Impulse      impulse;  
         double       delay;  
         const Stone *receiver;  // to test if stone has changed  
   
         DelayedImpulse& operator = (const DelayedImpulse& other); // forbidden  
     public:  
         DelayedImpulse(const Impulse& impulse_, double delay_, const Stone *receiver_)  
         : impulse(impulse_), delay(delay_), receiver(receiver_) {}  
   
         DelayedImpulse(const DelayedImpulse& other)  
             : impulse(other.impulse), delay(other.delay), receiver(other.receiver) {}  
   
         bool tick(double dtime) { // returns true if Impulse has to be sent NOW  
             delay -= dtime;  
             return delay <= 0;  
         }  
   
         const GridPos& destination() const { return impulse.dest; }  
   
         void send_impulse(Stone *target) const {  
   
             // @@@ FIXME: the test for equality of Stones sometimes fails  
             // (e.g. with turnstiles rotated by rotators)  
             //  
             // I guess this happens, because when the turnstile-pivot removes and add arms  
             // during turn, it may happen, that the Stone receives the same memory address  
             //  
             // Possible fix : add unique ID to all objects  
   
             if (target == receiver) { // if object did not change since impulse was initiated  
                 target->on_impulse(impulse);  
             }  
         }  
     };  
   
     typedef list<DelayedImpulse> ImpulseList;  
1108      ImpulseList delayed_impulses;      ImpulseList delayed_impulses;
1109  }  }
1110    
1111    Object *world::GetObject (const GridLoc &l)
1112    {
1113        switch (l.layer) {
1114        case GRID_FLOOR:  return GetFloor(l.pos);
1115        case GRID_ITEMS:  return GetItem(l.pos);
1116        case GRID_STONES: return GetStone(l.pos);
1117        default: return 0;
1118        }
1119    }
1120    
1121  //----------------------------------------  //----------------------------------------
1122  // Floor manipulation.  // Floor manipulation.
# Line 1392  namespace Line 1153  namespace
1153  }  }
1154    
1155  void  void
1156  world::BroadcastMessage(const std::string& msg, const Value& value, GridLayerBits grids) {  world::BroadcastMessage (const std::string& msg, const Value& value, GridLayerBits grids)
1157    {
1158      int  width     = level->w;      int  width     = level->w;
1159      int  height    = level->h;      int  height    = level->h;
1160      bool to_floors = grids & GRID_FLOOR_BIT;      bool to_floors = grids & GRID_FLOOR_BIT;
# Line 1402  world::BroadcastMessage(const std::strin Line 1164  world::BroadcastMessage(const std::strin
1164      for (int y = 0; y<height; ++y) {      for (int y = 0; y<height; ++y) {
1165          for (int x = 0; x<width; ++x) {          for (int x = 0; x<width; ++x) {
1166              GridPos p(x, y);              GridPos p(x, y);
1167              if (to_floors) if (Floor *fl = GetFloor(p)) SendMessage(fl, msg, value);              if (to_floors) SendMessage (GetFloor(p), msg, value);
1168              if (to_items)  if (Item *it  = GetItem(p))  SendMessage(it, msg, value);              if (to_items)  SendMessage (GetItem(p),  msg, value);
1169              if (to_stones) if (Stone *st = GetStone(p)) SendMessage(st, msg, value);              if (to_stones) SendMessage (GetStone(p), msg, value);
1170          }          }
1171      }      }
1172  }  }
1173    
1174    Stone *
1175    world::GetStone(GridPos p)
1176    {
1177        return st_layer.get(p);
1178    }
1179    
1180  void  void
1181  world::KillStone(GridPos p)  world::KillStone(GridPos p)
1182  {  {
1183      st_layer.kill(p);      st_layer.kill(p);
 //    stone_change(p);  
1184      changed_stones.push_back(p);      changed_stones.push_back(p);
1185  }  }
1186    
1187  Stone *  Stone *
 world::GetStone(GridPos p) {return st_layer.get(p);}  
   
 Stone *  
1188  world::YieldStone(GridPos p)  world::YieldStone(GridPos p)
1189  {  {
1190      Stone *st = st_layer.yield(p);      Stone *st = st_layer.yield(p);
     laser::MaybeRecalcLight(p);  
1191      changed_stones.push_back(p);      changed_stones.push_back(p);
1192      return st;      return st;
1193  }  }
# Line 1433  void Line 1196  void
1196  world::SetStone(GridPos p, Stone* st)  world::SetStone(GridPos p, Stone* st)
1197  {  {
1198      st_layer.set(p,st);      st_layer.set(p,st);
     laser::MaybeRecalcLight(p);  
1199      changed_stones.push_back(p);      changed_stones.push_back(p);
1200  }  }
1201    
# Line 1448  world::ReplaceStone(GridPos p, Stone* st Line 1210  world::ReplaceStone(GridPos p, Stone* st
1210      SetStone(p, st);      SetStone(p, st);
1211  }  }
1212    
1213  #if 0 // currently unused  void
1214  void  world::MoveStone(GridPos oldPos, GridPos newPos)
 world::SwapStones(GridPos p, GridPos newp)  
1215  {  {
     if (!IsLevelBorder(newp) && !IsLevelBorder(p)) {  
         Stone *tmp  = st_layer.yield(newp);  
         Stone *tmp2 = st_layer.yield(p);  
   
         tmp->play_sound ("st-move");  
   
         SetStone(newp, tmp2);  
         SetStone(p, tmp);  
         tmp->on_move();  
         tmp2->on_move();  
   
         player::IncMoveCounter(2);  
     }  
 }  
 #endif  
   
 void world::MoveStone(GridPos oldPos, GridPos newPos) {  
     display::Model *m = display::YieldModel(GridLoc(GRID_STONES, oldPos));  
1216      SetStone(newPos, YieldStone(oldPos));      SetStone(newPos, YieldStone(oldPos));
     display::SetModel(GridLoc(GRID_STONES, newPos), m);  
1217  }  }
1218    
1219  void  void
# Line 1614  world::addDelayedImpulse(const Impulse& Line 1356  world::addDelayedImpulse(const Impulse&
1356  }  }
1357    
1358    
1359    static void
1360    handle_delayed_impulses (double dtime)
1361    {
1362        // Handle delayed impulses
1363        for (ImpulseList::iterator i = delayed_impulses.begin(); i != delayed_impulses.end(); )
1364        {
1365            // shall the impulse take effect now ?
1366            if (i->tick(dtime)) {
1367                if (Stone *st = GetStone(i->destination()))
1368                    i->send_impulse(st);
1369                i = delayed_impulses.erase(i);
1370            }
1371            else
1372                ++i;
1373        }
1374    
1375    }
1376    
1377  //----------------------------------------  //----------------------------------------
1378  // Tick  // Tick
1379  //----------------------------------------  //----------------------------------------
# Line 1640  world::Tick(double dtime) Line 1400  world::Tick(double dtime)
1400              (*i)->think(timestep);              (*i)->think(timestep);
1401          }          }
1402    
1403          // Handle delayed impulses          handle_delayed_impulses (timestep);
         for (ImpulseList::iterator i = delayed_impulses.begin(); i != delayed_impulses.end(); ) {  
             // should the impulse take effect now ?  
             if (i->tick(timestep)) {  
                 // is there a stone on the destination field ?  
                 if (Stone *st = GetStone(i->destination())) {  
                     i->send_impulse(st);  
                 }  
                 i = delayed_impulses.erase(i);  
             }  
             else  
                 ++i;  
         }  
1404    
1405          // Tell floors and items about new stones.          // Tell floors and items about new stones.
1406          for (unsigned i=0; i<changed_stones.size(); ++i)          for (unsigned i=0; i<changed_stones.size(); ++i)

Legend:
Removed from v.1.72.2.1  
changed lines
  Added in v.1.72.2.2

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26