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