src/ai/ai_movement_module.cpp

Go to the documentation of this file.
00001 /******************************************************************************
00002  *  Wormux is a convivial mass murder game.
00003  *  Copyright (C) 2001-2004 Lawrence Azzoug.
00004  *
00005  *  This program is free software; you can redistribute it and/or modify
00006  *  it under the terms of the GNU General Public License as published by
00007  *  the Free Software Foundation; either version 2 of the License, or
00008  *  (at your option) any later version.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with this program; if not, write to the Free Software
00017  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
00018  ******************************************************************************
00019  * Artificial intelligence Movement module
00020  *****************************************************************************/
00021 
00022 #include <iostream>
00023 #include "../include/action_handler.h"
00024 #include "../character/body.h"
00025 #include "../character/move.h"
00026 #include "../interface/game_msg.h"
00027 #include "../map/map.h"
00028 #include "../team/macro.h"
00029 #include "../team/teams_list.h"
00030 #include "../tool/error.h"
00031 #include "../tool/math_tools.h"
00032 #include "../tool/string_tools.h"
00033 
00034 #include "ai_movement_module.h"
00035 
00036 // TODO: 
00037 // - Be sure to not go out of the map
00038 // - Fix hole detection
00039 // - Do not go back on the shoot position !
00040 
00041 
00042 // =================================================
00043 // Go on !
00044 // =================================================
00045 void AIMovementModule::MakeStep()
00046 {
00047   if(ActiveCharacter().IsImmobile()) {
00048     if (ActiveCharacter().GetDirection() == Body::DIRECTION_RIGHT) {
00049       MoveCharacterRight(ActiveCharacter());
00050     }  else {
00051       MoveCharacterLeft(ActiveCharacter());
00052     }
00053   }
00054 }
00055 
00056 // =================================================
00057 // Compute obstacle height (barrier or hole)
00058 // Return true if sure that it does not need to jump
00059 // or to use parachute
00060 // =================================================
00061 bool AIMovementModule::ObstacleHeight(int& height)
00062 {
00063   if (ComputeHeightMovement(ActiveCharacter(), height, false))
00064     return true;
00065 
00066   int y_floor=ActiveCharacter().GetY();
00067   if (height < 0) {
00068 
00069     for (height = -15; height >= -150 ; height--) {
00070       if ( ActiveCharacter().IsInVacuum( Point2i(ActiveCharacter().GetDirection(), height) ) ) {
00071         break;
00072       }
00073     }
00074 
00075   } else {
00076 
00077     // Compute exact whole size
00078     for (height = 15; height <= 150 ; height++){
00079       if ( !ActiveCharacter().IsInVacuum(Point2i(ActiveCharacter().GetDirection(), height))
00080           ||  ActiveCharacter().FootsOnFloor(y_floor+height)){
00081         break;
00082       }
00083     }
00084 
00085   }
00086   return false;
00087 }
00088 
00089 bool AIMovementModule::RiskGoingOutOfMap()
00090 {
00091   if ( ActiveCharacter().GetDirection() == Body::DIRECTION_LEFT &&
00092        ActiveCharacter().GetX() <= 5 ) {
00093     return true;
00094   } else if ( ActiveCharacter().GetDirection() == Body::DIRECTION_RIGHT &&
00095               world.GetWidth() - 5 <= ActiveCharacter().GetX() + ActiveCharacter().GetSize().GetX() ) {
00096     return true;
00097   }
00098 
00099   return false;
00100 }
00101 
00102 // =================================================
00103 // A jump is made of many movement :
00104 // 1) Decect collision and prepare to go back
00105 // 2) Go back, then when far enought of the obstacle
00106 // 3) Jump!
00107 // 4) Detect when on the ground! 
00108 // =================================================
00109 
00110 void AIMovementModule::PrepareJump()
00111 {
00112   ActiveCharacter().body->StartWalk();
00113   
00114   current_movement = BACK_TO_JUMP;
00115   time_at_last_position = m_current_time;
00116 
00117   InverseDirection();
00118 }
00119 
00120 void AIMovementModule::GoBackToJump()
00121 {
00122   assert(current_movement = BACK_TO_JUMP);
00123 
00124   MakeStep();
00125 
00126   int height;
00127   bool blocked = !(ObstacleHeight(height));
00128 
00129   if ( abs(last_position.GetX() - ActiveCharacter().GetPosition().GetX()) >= 20
00130        || time_at_last_position +1 < m_current_time
00131        || blocked) {
00132     //it's time to jump!
00133     InverseDirection();
00134     Jump();
00135   }
00136 }
00137 
00138 void AIMovementModule::Jump()
00139 {
00140   //  GameMessages::GetInstance()->Add("try to jump!");
00141   current_movement = JUMPING;
00142   ActionHandler::GetInstance()->NewAction (new Action(Action::ACTION_HIGH_JUMP));
00143 }
00144 
00145 void AIMovementModule::EndOfJump()
00146 {
00147   assert(current_movement = JUMPING);
00148 
00149   //GameMessages::GetInstance()->Add("finished to jump");
00150   
00151   
00152   if ( last_position.GetX() == ActiveCharacter().GetPosition().GetX() ) {
00153     // we have not moved since last movement
00154     StopMoving();
00155     
00156   } else {
00157     // No more blocked !!
00158     current_movement = WALKING;
00159   }  
00160 }
00161 
00162 
00163 // =================================================
00164 // The walking methods
00165 // Walk() is responsible to detect obstacles
00166 // =================================================
00167 
00168 void AIMovementModule::Walk()
00169 {
00170   // Animate skin
00171   if ( current_movement != WALKING ) {
00172     ActiveCharacter().InitMouvementDG(100);
00173     ActiveCharacter().body->StartWalk();
00174     current_movement = WALKING;
00175   }
00176 
00177   MakeStep();
00178 
00179   int height;
00180   bool blocked = !(ObstacleHeight(height));
00181 
00182   // we are blocked, what next ?
00183   if ( blocked ) {
00184 
00185     if ( last_blocked_position.GetX() != ActiveCharacter().GetPosition().GetX() ) {
00186       
00187       last_blocked_position = ActiveCharacter().GetPosition();
00188       
00189       if (height < 0 ) {
00190         // There's a barrier
00191         
00192         if (height >= -80) { // we can try to jump!
00193           PrepareJump();
00194           return; // do not update position
00195         } else { // it's too high!
00196           //      GameMessages::GetInstance()->Add("It's too high!!");
00197           InverseDirection();
00198         }
00199       } else {
00200         // There's a hole
00201         
00202         if (height >= 100) { // it's too deep, go back!!
00203           //      GameMessages::GetInstance()->Add("It's too deep!" + ulong2str(height));
00204           InverseDirection();
00205         }
00206       }
00207     } else {
00208       // already have been blocked here...
00209       InverseDirection();
00210     }
00211   }
00212 
00213   // Inverse direction if there is a risk to go out of the map
00214   if (RiskGoingOutOfMap()) {
00215     InverseDirection();
00216   }
00217 
00218   // Update position if we are not jumping
00219   last_position = ActiveCharacter().GetPosition();
00220   time_at_last_position = m_current_time;
00221 }
00222 
00223 void AIMovementModule::StopWalking()
00224 {
00225   current_movement = NO_MOVEMENT;
00226   ActiveCharacter().body->StopWalk();
00227 }
00228 
00229 
00230 // =================================================
00231 // Invert walking direction
00232 // =================================================
00233 void AIMovementModule::InverseDirection()
00234 {
00235   if (ActiveCharacter().GetDirection() == Body::DIRECTION_RIGHT) {
00236     ActiveCharacter().SetDirection(Body::DIRECTION_LEFT);
00237   } else {
00238     ActiveCharacter().SetDirection(Body::DIRECTION_RIGHT);
00239   }
00240 }
00241 
00242 // =================================================
00243 // Public method updating the movement
00244 // =================================================
00245 void AIMovementModule::Move(uint current_time)
00246 {
00247   m_current_time = current_time;
00248 
00249   // are we on the ground ?
00250   if ( ActiveCharacter().FootsInVacuum() ) { // No!
00251     return;
00252   }
00253 
00254   switch (current_movement) {
00255 
00256   case NO_MOVEMENT:
00257     // Begin to walk
00258     Walk();
00259     break;
00260 
00261   case WALKING:
00262     // Continue to walk
00263     Walk();
00264     break;
00265 
00266   case BACK_TO_JUMP:
00267     // Go back to have enough place to jump
00268     GoBackToJump();
00269     break;
00270 
00271   case JUMPING:
00272     EndOfJump();
00273  
00274     break;
00275   default:
00276     break;
00277   }
00278 }
00279 
00280 void AIMovementModule::StopMoving()
00281 {
00282   //  GameMessages::GetInstance()->Add("stop moving");
00283   StopWalking();
00284   //m_step++;
00285 }
00286 
00287 // =================================================
00288 // Initialize Movement module when changing 
00289 // character to control
00290 // =================================================
00291 void AIMovementModule::BeginTurn()
00292 {
00293   current_movement = NO_MOVEMENT;
00294   time_at_last_position = 0;
00295   last_position = Point2i(0,0);
00296   last_blocked_position = Point2i(0,0);
00297 }
00298 
00299 AIMovementModule::AIMovementModule()
00300 {
00301   std::cout << "o Artificial Intelligence Movement module initialization" << std::endl;
00302 }
00303 
00304 

Generated on Mon Jan 1 13:10:55 2007 for Wormux by  doxygen 1.4.7