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

Diff of /enigma/src/objects.cc

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

revision 1.64 by dheck, Thu May 8 19:02:14 2003 UTC revision 1.65 by reallysoft, Thu May 8 23:10:54 2003 UTC
# Line 2650  ShogunStone::actor_hit(const StoneContac Line 2650  ShogunStone::actor_hit(const StoneContac
2650  }  }
2651    
2652  void  void
2653  ShogunStone::on_impulse(Direction dir)  ShogunStone::on_impulse(Direction dir)
2654  {  {
2655      if (transfer_smallest_hole(move(get_pos(), dir)))      if (transfer_smallest_hole(move(get_pos(), dir)))
2656          play_sound("st-move");          play_sound("st-move");
# Line 3809  namespace Line 3809  namespace
3809          void remove_arms (DirectionBits arms);          void remove_arms (DirectionBits arms);
3810    
3811          void animcb() { set_model(model()); }          void animcb() { set_model(model()); }
3812          void warpActorsInRange(bool clockwise);          void handleActorsAndItems(bool clockwise);
3813    
3814          virtual const char *model() const    = 0;          virtual const char *model() const    = 0;
3815          virtual const char *anim() const     = 0;          virtual const char *anim() const     = 0;
# Line 3900  namespace Line 3900  namespace
3900      };      };
3901  }  }
3902    
3903  void  // -------------------------------------
3904  Turnstile_Pivot_Base::warpActorsInRange(bool clockwise) {  //      Turnstile_Arm implementation
3905      // the turnstile itself already has been rotated  // -------------------------------------
     // now handle all actors in Range  
   
     GridPos pv_pos = get_pos();  
     V2      pv_center(pv_pos.x+.5, pv_pos.y+.5);  
   
     const int to_index[3][3] = {  
         { 0, 7, 6 }, // x == 0  
         { 1,-1, 5 }, // x == 1  
         { 2, 3, 4 }  // x == 2  
     };  
   
     // for each field calculate whether an arm has passed by:  
     bool arm_seen[8];  
     {  
         const DirectionBits neededArm[2][8] = {  
             // anticlockwise :  
             { WESTBIT, NORTHBIT, NORTHBIT, EASTBIT, EASTBIT, SOUTHBIT, SOUTHBIT, WESTBIT },  
             // clockwise :  
             { NORTHBIT, NORTHBIT, EASTBIT, EASTBIT, SOUTHBIT, SOUTHBIT, WESTBIT, WESTBIT }  
         };  
         DirectionBits arms = arms_present(); // already the rotated state  
         assert(arms); // pivots w/o arms should not rotate  
   
         for (int i = 0; i<8; ++i) {  
             arm_seen[i] = arms & neededArm[clockwise][i];  
         }  
     }  
   
     vector<Actor*> actorsInRange;  
   
     // tested range is sqrt(sqr(1.5)+sqr(0.5)) ( = radius hit by turnstile) + 19/64 ( = max. actor radius)  
     if (GetActorsInRange(pv_center, 1.879, actorsInRange)) {  
         for (vector<Actor*>::iterator ac = actorsInRange.begin(); ac != actorsInRange.end(); ++ac) {  
             const V2& ac_center = (*ac)->get_pos();  
             GridPos   ac_pos(ac_center);  
             int       dx        = ac_pos.x-pv_pos.x;  
             int       dy        = ac_pos.y-pv_pos.y;  
   
             if (dx<-1 || dx>1 || dy<-1 || dy>1) { // actor is outside of turnstile  
                 // @@@ FIXME: test if actor was hit by turnstile -> set actor speed  
             }  
             else {              // actor is inside the turnstile  
                 const int to_x[8] = { -1, 0, 1, 1, 1, 0, -1, -1 };  
                 const int to_y[8] = { -1, -1, -1, 0, 1, 1, 1, 0 };  
   
                 int idx_source = to_index[dx+1][dy+1];  
                 assert(idx_source != -1); // actor inside pivot -- impossible  
   
                 const int rot_index[4][8] = {  
                     { 6,  0, 0,  2, 2,  4, 4,  6 }, // anticlockwise  
                     { 2,  2, 4,  4, 6,  6, 0,  0 }, // clockwise  
                     { 6, -1, 0, -1, 2, -1, 4, -1 }, // anticlockwise (oxyd-compatible)  
                     { 2, -1, 4, -1, 6, -1, 0, -1 }, // clockwise (oxyd-compatible)  
                 };  
   
                 bool compatible = oxyd_compatible();  
                 int  idx_target = rot_index[clockwise+2*compatible][idx_source]; // destination index  
   
                 enum { STAY, WARP, SHATTER } action = STAY;  
   
                 if (compatible) {  
                     bool is_impulse_sender = (*ac == dynamic_cast<Actor*>(ImpulseSender()));  
   
                     if (is_impulse_sender) {  
                         action = WARP;  
                     }  
                     else { // other actors  
                         if (arm_seen[idx_source]) { // this actor has been hit by an arm  
                             action = SHATTER;  
                         }  
                     }  
                 }  
                 else {          // not oxyd-compatible  
                     if (arm_seen[idx_source]) {  
                         action = WARP;  
                     }  
                     // @@@ FIXME: shattered actors are warped  
                 }  
   
                 switch (action) {  
                 case WARP:  {  
                     GridPos ac_target_pos(pv_pos.x+to_x[idx_target], pv_pos.y+to_y[idx_target]);  
                     world::WarpActor(*ac, ac_target_pos.x+.5, ac_target_pos.y+.5);  
   
                     Stone *st = GetStone(ac_target_pos);  
                     if (!st) break;  
   
                     // destination is blocked  
   
                     Turnstile_Arm *arm = dynamic_cast<Turnstile_Arm*>(st);  
                     if (arm && !compatible) { // if blocking stone is turnstile arm -> hit it!  
                         const int impulse_dir[2][8] = {  
                             // anticlockwise  
                             { SOUTHBIT|WESTBIT, WESTBIT, NORTHBIT|WESTBIT, NORTHBIT,  
                               NORTHBIT|EASTBIT, EASTBIT, SOUTHBIT|EASTBIT, SOUTHBIT },  
                             // clockwise  
                             { NORTHBIT|EASTBIT, EASTBIT, SOUTHBIT|EASTBIT, SOUTHBIT,  
                               SOUTHBIT|WESTBIT, WESTBIT, NORTHBIT|WESTBIT, NORTHBIT }  
                         };  
   
                         DirectionBits possible_impulses =  
                             static_cast<DirectionBits>(impulse_dir[clockwise][idx_target]);  
   
                         for (int d = 0; d<4; ++d) {  
                             if (has_dir(possible_impulses, Direction(d))) {  
                                 SendImpulse(ac_target_pos, Direction(d), *ac);  
                             }  
                         }  
   
                         if (GetStone(ac_target_pos) == 0) { // arm disappeared  
                             break;  
                         }  
                     }  
                     // fall-through (if arm didn't rotate or other stone was blocking)  
                 }  
                 case SHATTER:  
                     SendMessage(*ac, "shatter");  
                     break;  
                 }  
   
                 // @@@ FIXME: it's possible that two actors are moved to the same destination field.  
                 // In that case the second actor is put on top of the first actor  
                 // (happens only in non-oxyd-compat-mode with three balls or pullers/impulsestones)  
                 //  
                 // Note: With black and whiteball it's normally no problem,  
                 // because when one of the actors was moving, it's looking natural.  
                 // Problems occur when small balls come into play.  
             }  
         }  
     }  
   
     // @@@ FIXME: handle items in range (using on_stonehit())  
 }  
3906    
3907  void  void
3908  Turnstile_Arm::on_impulse(Direction dir) {  Turnstile_Arm::on_impulse(Direction dir) {
# Line 4072  Turnstile_Arm::actor_hit(const StoneCont Line 3939  Turnstile_Arm::actor_hit(const StoneCont
3939      }      }
3940  }  }
3941    
3942  #if 0 //  old code :  // --------------------------------------------
3943    //      Turnstile_Pivot_Base implementation
3944  void  // --------------------------------------------
 Turnstile_Arm::actor_hit(const StoneContact &sc)  
 {  
     Turnstile_Pivot_Base *pivot = get_pivot();  
   
     enum Action { ROTL, ROTR, stay };  
     static Action actions[4][4] = {  
         { stay, ROTL, stay, ROTR }, // west arm  
         { ROTR, stay, ROTL, stay }, // south arm  
         { stay, ROTR, stay, ROTL }, // east arm  
         { ROTL, stay, ROTR, stay } // north arm  
     };  
   
     ActorInfo *ai = sc.actor->get_actorinfo();  
     Direction dir = reverse(contact_face(sc));  
     if (dir!=enigma::NODIR && ai->vel * sc.normal < -4)  
     {  
         if (pivot) {  
             Action a = actions[get_dir()][dir];  
             GridPos pos = move(get_pos(), dir);  
             V2 destpos (pos.x + 0.5, pos.y + 0.5);  
             if (a == ROTL) {  
                 if (pivot->rotate_left ())  
                     world::WarpActor (sc.actor, destpos[0], destpos[1]);  
             }  
             else if (a == ROTR) {  
                 if (pivot->rotate_right ())  
                     world::WarpActor (sc.actor, destpos[0], destpos[1]);  
             }  
         }  
         else {  
             // Move arms not attached to a pivot individually  
             MaybeMoveStone(get_pos(), dir);  
         }  
     }  
 }  
   
 #endif // old code  
3945    
3946  DirectionBits  DirectionBits
3947  Turnstile_Pivot_Base::arms_present()  Turnstile_Pivot_Base::arms_present()
# Line 4199  Turnstile_Pivot_Base::rotate_left() Line 4029  Turnstile_Pivot_Base::rotate_left()
4029      if (can_rotate) {      if (can_rotate) {
4030  //        play_sound("rotate-left");  //        play_sound("rotate-left");
4031          play_sound("st-magic");          play_sound("st-magic");
 //         set_anim("st-turnstile-anim");  
4032          set_anim(anim());          set_anim(anim());
4033    
4034          remove_arms(arms);          remove_arms(arms);
4035          set_arms(rotate(arms, false));          set_arms(rotate(arms, false));
4036          warpActorsInRange(false);          handleActorsAndItems(false);
4037    
4038          player::IncMoveCounter();          player::IncMoveCounter();
4039      }      }
# Line 4237  Turnstile_Pivot_Base::rotate_right() Line 4066  Turnstile_Pivot_Base::rotate_right()
4066      if (can_rotate) {      if (can_rotate) {
4067  //        play_sound("rotate-right");  //        play_sound("rotate-right");
4068          play_sound("st-magic");          play_sound("st-magic");
 //         set_anim("st-turnstile-anim");  
4069          set_anim(anim());          set_anim(anim());
4070    
4071          remove_arms(arms);          remove_arms(arms);
4072          set_arms(rotate(arms, true));          set_arms(rotate(arms, true));
4073          warpActorsInRange(true);          handleActorsAndItems(true);
4074    
4075          player::IncMoveCounter();          player::IncMoveCounter();
4076      }      }
4077      return can_rotate;      return can_rotate;
4078  }  }
4079    
4080    void
4081    Turnstile_Pivot_Base::handleActorsAndItems(bool clockwise) {
4082        GridPos pv_pos = get_pos();
4083        V2      pv_center(pv_pos.x+.5, pv_pos.y+.5);
4084    
4085        const int to_index[3][3] = {
4086            { 0, 7, 6 }, // x == 0
4087            { 1,-1, 5 }, // x == 1
4088            { 2, 3, 4 }  // x == 2
4089        };
4090        const int to_x[8] = { -1, 0, 1, 1, 1, 0, -1, -1 };
4091        const int to_y[8] = { -1, -1, -1, 0, 1, 1, 1, 0 };
4092    
4093        // for each field calculate whether an arm has passed by:
4094        bool arm_seen[8];
4095        {
4096            const DirectionBits neededArm[2][8] = {
4097                // anticlockwise :
4098                { WESTBIT, NORTHBIT, NORTHBIT, EASTBIT, EASTBIT, SOUTHBIT, SOUTHBIT, WESTBIT },
4099                // clockwise :
4100                { NORTHBIT, NORTHBIT, EASTBIT, EASTBIT, SOUTHBIT, SOUTHBIT, WESTBIT, WESTBIT }
4101            };
4102            DirectionBits arms = arms_present(); // already the rotated state
4103            assert(arms); // pivots w/o arms should not rotate
4104    
4105            for (int i = 0; i<8; ++i) {
4106                arm_seen[i] = arms & neededArm[clockwise][i];
4107            }
4108        }
4109    
4110        // The turnstile itself already has been rotated.
4111    
4112        // Handle items in range :
4113        for (int i = 0; i<8; ++i) {
4114            if (arm_seen[i]) {
4115                GridPos pos(pv_pos.x+to_x[i], pv_pos.y+to_y[i]);
4116                if (Item *it = GetItem(pos)) it->on_stonehit(this); // hit with pivot (shouldn't matter)
4117            }
4118        }
4119    
4120        // Now handle all actors in range :
4121        vector<Actor*> actorsInRange;
4122    
4123        // tested range is sqrt(sqr(1.5)+sqr(0.5)) ( = radius hit by turnstile) + 19/64 ( = max. actor radius)
4124        if (GetActorsInRange(pv_center, 1.879, actorsInRange)) {
4125            for (vector<Actor*>::iterator ac = actorsInRange.begin(); ac != actorsInRange.end(); ++ac) {
4126                const V2& ac_center = (*ac)->get_pos();
4127                GridPos   ac_pos(ac_center);
4128                int       dx        = ac_pos.x-pv_pos.x;
4129                int       dy        = ac_pos.y-pv_pos.y;
4130    
4131                if (dx<-1 || dx>1 || dy<-1 || dy>1) { // actor is outside of turnstile
4132                    // @@@ FIXME: test if actor was hit by turnstile -> set actor speed
4133                }
4134                else {              // actor is inside the turnstile
4135                    int idx_source = to_index[dx+1][dy+1];
4136                    assert(idx_source != -1); // actor inside pivot -- impossible
4137    
4138                    const int rot_index[4][8] = {
4139                        { 6,  0, 0,  2, 2,  4, 4,  6 }, // anticlockwise
4140                        { 2,  2, 4,  4, 6,  6, 0,  0 }, // clockwise
4141                        { 6, -1, 0, -1, 2, -1, 4, -1 }, // anticlockwise (oxyd-compatible)
4142                        { 2, -1, 4, -1, 6, -1, 0, -1 }, // clockwise (oxyd-compatible)
4143                    };
4144    
4145                    bool compatible = oxyd_compatible();
4146                    int  idx_target = rot_index[clockwise+2*compatible][idx_source]; // destination index
4147    
4148                    enum { STAY, WARP, SHATTER } action = STAY;
4149    
4150                    if (compatible) {
4151                        bool is_impulse_sender = (*ac == dynamic_cast<Actor*>(ImpulseSender()));
4152    
4153                        if (is_impulse_sender) {
4154                            action = WARP;
4155                        }
4156                        else { // other actors
4157                            if (arm_seen[idx_source]) { // this actor has been hit by an arm
4158                                action = SHATTER;
4159                            }
4160                        }
4161                    }
4162                    else {          // not oxyd-compatible
4163                        if (arm_seen[idx_source]) {
4164                            action = WARP;
4165                        }
4166                        // @@@ FIXME: shattered actors are warped
4167                    }
4168    
4169                    switch (action) {
4170                        case WARP:  {
4171                            GridPos ac_target_pos(pv_pos.x+to_x[idx_target], pv_pos.y+to_y[idx_target]);
4172                            world::WarpActor(*ac, ac_target_pos.x+.5, ac_target_pos.y+.5);
4173    
4174                            Stone *st = GetStone(ac_target_pos);
4175                            if (!st) break;
4176    
4177                            // destination is blocked
4178    
4179                            Turnstile_Arm *arm = dynamic_cast<Turnstile_Arm*>(st);
4180                            if (arm && !compatible) { // if blocking stone is turnstile arm -> hit it!
4181                                const int impulse_dir[2][8] = {
4182                                    // anticlockwise
4183                                    { SOUTHBIT|WESTBIT, WESTBIT, NORTHBIT|WESTBIT, NORTHBIT,
4184                                      NORTHBIT|EASTBIT, EASTBIT, SOUTHBIT|EASTBIT, SOUTHBIT },
4185                                    // clockwise
4186                                    { NORTHBIT|EASTBIT, EASTBIT, SOUTHBIT|EASTBIT, SOUTHBIT,
4187                                      SOUTHBIT|WESTBIT, WESTBIT, NORTHBIT|WESTBIT, NORTHBIT }
4188                                };
4189    
4190                                DirectionBits possible_impulses =
4191                                    static_cast<DirectionBits>(impulse_dir[clockwise][idx_target]);
4192    
4193                                for (int d = 0; d<4; ++d) {
4194                                    if (has_dir(possible_impulses, Direction(d))) {
4195                                        SendImpulse(ac_target_pos, Direction(d), *ac);
4196                                    }
4197                                }
4198    
4199                                if (GetStone(ac_target_pos) == 0) { // arm disappeared
4200                                    break;
4201                                }
4202                            }
4203                            // fall-through (if arm didn't rotate or other stone was blocking)
4204                        }
4205                        case SHATTER: {
4206                            SendMessage(*ac, "shatter");
4207                            break;
4208                        }
4209                    }
4210    
4211                    // @@@ FIXME: it's possible that two actors are moved to the same destination field.
4212                    // In that case the second actor is put on top of the first actor
4213                    // (happens only in non-oxyd-compat-mode with three balls or pullers/impulsestones)
4214                    //
4215                    // Note: With black and whiteball it's normally no problem,
4216                    // because when one of the actors was moving, it's looking natural.
4217                    // Problems occur when small balls come into play.
4218                }
4219            }
4220        }
4221    
4222    }
4223    
4224  //----------------------------------------  //----------------------------------------
4225  // EasyModeStone  // EasyModeStone
4226  //  //

Legend:
Removed from v.1.64  
changed lines
  Added in v.1.65

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