Browse Source

Add PandAI (and contribbase)

rdb 16 years ago
parent
commit
fed12caf68
40 changed files with 4908 additions and 0 deletions
  1. 1463 0
      contrib/src/ai/aiBehaviors.cxx
  2. 193 0
      contrib/src/ai/aiBehaviors.h
  3. 127 0
      contrib/src/ai/aiCharacter.cxx
  4. 76 0
      contrib/src/ai/aiCharacter.h
  5. 28 0
      contrib/src/ai/aiGlobals.h
  6. 53 0
      contrib/src/ai/aiNode.cxx
  7. 85 0
      contrib/src/ai/aiNode.h
  8. 377 0
      contrib/src/ai/aiPathFinder.cxx
  9. 61 0
      contrib/src/ai/aiPathFinder.h
  10. 258 0
      contrib/src/ai/aiWorld.cxx
  11. 87 0
      contrib/src/ai/aiWorld.h
  12. 1 0
      contrib/src/ai/ai_composite.cxx
  13. 20 0
      contrib/src/ai/ai_composite1.cxx
  14. 120 0
      contrib/src/ai/arrival.cxx
  15. 49 0
      contrib/src/ai/arrival.h
  16. 55 0
      contrib/src/ai/config_ai.cxx
  17. 26 0
      contrib/src/ai/config_ai.h
  18. 86 0
      contrib/src/ai/evade.cxx
  19. 48 0
      contrib/src/ai/evade.h
  20. 104 0
      contrib/src/ai/flee.cxx
  21. 52 0
      contrib/src/ai/flee.h
  22. 42 0
      contrib/src/ai/flock.cxx
  23. 62 0
      contrib/src/ai/flock.h
  24. 33 0
      contrib/src/ai/globals.h
  25. 43 0
      contrib/src/ai/meshNode.cxx
  26. 67 0
      contrib/src/ai/meshNode.h
  27. 119 0
      contrib/src/ai/obstacleAvoidance.cxx
  28. 42 0
      contrib/src/ai/obstacleAvoidance.h
  29. 413 0
      contrib/src/ai/pathFind.cxx
  30. 70 0
      contrib/src/ai/pathFind.h
  31. 138 0
      contrib/src/ai/pathFollow.cxx
  32. 50 0
      contrib/src/ai/pathFollow.h
  33. 60 0
      contrib/src/ai/pursue.cxx
  34. 42 0
      contrib/src/ai/pursue.h
  35. 66 0
      contrib/src/ai/seek.cxx
  36. 44 0
      contrib/src/ai/seek.h
  37. 140 0
      contrib/src/ai/wander.cxx
  38. 40 0
      contrib/src/ai/wander.h
  39. 26 0
      contrib/src/contribbase/contribbase.h
  40. 42 0
      contrib/src/contribbase/contribsymbols.h

+ 1463 - 0
contrib/src/ai/aiBehaviors.cxx

@@ -0,0 +1,1463 @@
+// Filename: aiBehaviors.cxx
+// Created by:  Deepak, John, Navin (08Sep09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised 
+// BSD license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "aiBehaviors.h"
+
+static const float _PI = 3.14;
+
+AIBehaviors::AIBehaviors() {
+  _steering_force = LVecBase3f(0.0, 0.0, 0.0);
+  _behaviors_flags = _behaviors_flags & BT_none;
+  _previous_conflict = false;
+  _conflict = false;
+
+  _seek_obj = NULL;
+  _flee_obj = NULL;
+  _pursue_obj = NULL;
+  _evade_obj = NULL;
+  _arrival_obj = NULL;
+  _wander_obj = NULL;
+  _flock_group = NULL;
+  _path_follow_obj = NULL;
+  _path_find_obj = NULL;
+  _obstacle_avoidance_obj = NULL;
+
+  turn_off("seek");
+  turn_off("flee");
+  turn_off("pursue");
+  turn_off("evade");
+  turn_off("arrival");
+  turn_off("flock");
+  turn_off("wander");
+  turn_off("obstacle_avoidance");
+}
+
+AIBehaviors::~AIBehaviors() {
+
+}
+
+///////////////////////////////////////////////////////////////////
+//     Function: is_conflict
+//  Description: Checks for conflict between steering forces.
+//               If there is a conflict it returns 'true'
+//               and sets _conflict to 'true'.
+//               If there is no conflict it returns 'false'
+//               and sets _conflict to 'false'.
+///////////////////////////////////////////////////////////////////
+bool AIBehaviors::is_conflict() {
+  int value = int(is_on(BT_seek)) + int(is_on(BT_flee)) + int(is_on(BT_pursue))
+              + int(is_on(BT_evade)) + int(is_on(BT_wander)) + int(is_on(BT_flock))
+              + int(is_on(BT_obstacle_avoidance));
+
+  if (value > 1) {
+    if (_previous_conflict == false) {
+      if (is_on(BT_seek)) {
+        _seek_force *= _seek_obj->_seek_weight;
+      }
+
+      if (is_on(BT_flee)) {
+        LVecBase3f dirn = _flee_force;
+        dirn.normalize();
+        _flee_force = _steering_force.length() * dirn * _flee_obj->_flee_weight;
+      }
+
+      if (is_on(BT_pursue)) {
+        _pursue_force *= _pursue_obj->_pursue_weight;
+      }
+
+      if (is_on(BT_evade)) {
+        LVecBase3f dirn = _evade_force;
+        dirn.normalize();
+        _evade_force = _steering_force.length() * dirn * _evade_obj->_evade_weight;
+      }
+
+      if (is_on(BT_flock)) {
+        _flock_force *= _flock_weight;
+      }
+
+      if (is_on(BT_wander)) {
+        _wander_force *= _wander_obj->_wander_weight;
+      }
+
+      _previous_conflict = true;
+    }
+
+    _conflict = true;
+    return true;
+  }
+
+  _conflict = false;
+  _previous_conflict = false;
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: accumulate_force
+//  Description: This function updates the individual steering forces 
+//               for each of the ai characters.
+//               These accumulated forces are eventually what 
+//               comprise the resultant steering force of the 
+//               character.
+////////////////////////////////////////////////////////////////////
+void AIBehaviors::accumulate_force(string force_type, LVecBase3f force) {
+
+  LVecBase3f old_force;
+
+  if (force_type == "seek") {
+    old_force = _seek_force;
+    _seek_force = old_force + force;
+  }
+
+  if (force_type == "flee") {
+    old_force = _flee_force;
+    _flee_force = old_force + force;
+  }
+
+  if (force_type == "pursue") {
+    old_force = _pursue_force;
+    double new_force = old_force.length() + force.length();
+    _pursue_force = new_force * _pursue_obj->_pursue_direction;
+  }
+
+  if (force_type == "evade") {
+    old_force = _evade_force;
+    double new_force = old_force.length() + force.length();
+    force.normalize();
+    _evade_force = new_force * force;
+  }
+
+  if (force_type == "arrival") {
+    _arrival_force = force;
+  }
+
+  if (force_type == "flock") {
+    old_force = _flock_force;
+    _flock_force = old_force + force;
+  }
+
+  if (force_type == "wander") {
+    old_force = _wander_force;
+    _wander_force = old_force + force;
+  }
+
+  if (force_type == "obstacle_avoidance") {
+    old_force = _obstacle_avoidance_force;
+    _obstacle_avoidance_force = old_force +force;
+  }
+
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: calculate_prioritized
+//  Description: This function updates the main steering force 
+//               for the ai character using the accumulate function 
+//							 and checks for max force and arrival force.
+//               It finally returns this steering force which is 
+//               accessed by the update function in the AICharacter
+//               class.
+////////////////////////////////////////////////////////////////////
+LVecBase3f AIBehaviors::calculate_prioritized() {
+  LVecBase3f force;
+
+  if (is_on(BT_seek)) {
+    if (_conflict) {
+      force = _seek_obj->do_seek() * _seek_obj->_seek_weight;
+    }
+    else {
+      force = _seek_obj->do_seek();
+    }
+    accumulate_force("seek",force);
+  }
+
+  if (is_on(BT_flee_activate)) {
+    for (_flee_itr = _flee_list.begin(); _flee_itr != _flee_list.end(); _flee_itr++) {
+      _flee_itr->flee_activate();
+    }
+  }
+
+  if (is_on(BT_flee)) {
+    for (_flee_itr = _flee_list.begin(); _flee_itr != _flee_list.end(); _flee_itr++) {
+      if (_flee_itr->_flee_activate_done) {
+        if (_conflict) {
+          force = _flee_itr->do_flee() * _flee_itr->_flee_weight;
+        }
+        else {
+          force = _flee_itr->do_flee();
+        }
+        accumulate_force("flee",force);
+      }
+    }
+  }
+
+  if (is_on(BT_pursue)) {
+    if (_conflict) {
+      force = _pursue_obj->do_pursue() * _pursue_obj->_pursue_weight;
+    }
+    else {
+      force = _pursue_obj->do_pursue();
+    }
+    accumulate_force("pursue",force);
+  }
+
+  if (is_on(BT_evade_activate)) {
+    for (_evade_itr = _evade_list.begin(); _evade_itr != _evade_list.end(); _evade_itr++) {
+      _evade_itr->evade_activate();
+    }
+  }
+
+  if (is_on(BT_evade)) {
+    for (_evade_itr = _evade_list.begin(); _evade_itr != _evade_list.end(); _evade_itr++) {
+      if (_evade_itr->_evade_activate_done) {
+        if (_conflict) {
+          force = (_evade_itr->do_evade()) * (_evade_itr->_evade_weight);
+        }
+        else {
+          force = _evade_itr->do_evade();
+        }
+        accumulate_force("evade",force);
+      }
+    }
+  }
+
+  if (is_on(BT_arrival_activate)) {
+      _arrival_obj->arrival_activate();
+  }
+
+  if (is_on(BT_arrival)) {
+    force = _arrival_obj->do_arrival();
+    accumulate_force("arrival",force);
+  }
+
+  if (is_on(BT_flock_activate)) {
+      flock_activate();
+  }
+
+  if (is_on(BT_flock)) {
+    if (_conflict) {
+      force = do_flock() * _flock_weight;
+    }
+    else {
+      force = do_flock();
+    }
+    accumulate_force("flock",force);
+  }
+
+  if (is_on(BT_wander)) {
+    if (_conflict) {
+      force = _wander_obj->do_wander() * _wander_obj->_wander_weight;
+    }
+    else {
+      force = _wander_obj->do_wander();
+    }
+    accumulate_force("wander", force);
+  }
+
+  if (is_on(BT_obstacle_avoidance_activate)) {
+      _obstacle_avoidance_obj->obstacle_avoidance_activate();
+  }
+
+  if (is_on(BT_obstacle_avoidance)) {
+    if (_conflict) {
+      force = _obstacle_avoidance_obj->do_obstacle_avoidance();
+    }
+    else {
+      force = _obstacle_avoidance_obj->do_obstacle_avoidance();
+    }
+    accumulate_force("obstacle_avoidance", force);
+  }
+
+  if (_path_follow_obj!=NULL) {
+    if (_path_follow_obj->_start) {
+      _path_follow_obj->do_follow();
+    }
+  }
+
+  is_conflict();
+
+  _steering_force += _seek_force * int(is_on(BT_seek)) + _flee_force * int(is_on(BT_flee)) +
+                      _pursue_force * int(is_on(BT_pursue)) + _evade_force * int(is_on(BT_evade)) +
+                      _flock_force * int(is_on(BT_flock)) + _wander_force * int(is_on(BT_wander)) +
+                      _obstacle_avoidance_force * int(is_on(BT_obstacle_avoidance));
+
+  if (_steering_force.length() > _ai_char->get_max_force()) {
+    _steering_force.normalize();
+    _steering_force = _steering_force * _ai_char->get_max_force();
+  }
+
+  if (is_on(BT_arrival)) {
+    if (_seek_obj != NULL) {
+      LVecBase3f dirn = _steering_force;
+      dirn.normalize();
+      _steering_force = ((_steering_force.length() - _arrival_force.length()) * dirn);
+    }
+
+    if (_pursue_obj != NULL) {
+      LVecBase3f dirn = _steering_force;
+      dirn.normalize();
+      _steering_force = ((_steering_force.length() - _arrival_force.length()) * _arrival_obj->_arrival_direction);
+    }
+  }
+  return _steering_force;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: remove_ai
+//  Description: This function removes individual or all the AIs.
+////////////////////////////////////////////////////////////////////
+void AIBehaviors::remove_ai(string ai_type) {
+  switch (char_to_int(ai_type)) {
+    case 0: {
+              remove_ai("seek");
+              remove_ai("flee");
+              remove_ai("pursue");
+              remove_ai("evade");
+              remove_ai("arrival");
+              remove_ai("flock");
+              remove_ai("wander");
+              remove_ai("obstacle_avoidance");
+              remove_ai("pathfollow");
+              break;
+            }
+
+    case 1: {
+              if (_seek_obj != NULL) {
+                turn_off("seek");
+                delete _seek_obj;
+                _seek_obj = NULL;
+              }
+              break;
+            }
+
+    case 2: {
+              while (!_flee_list.empty()) {
+                turn_off("flee");
+                turn_off("flee_activate");
+                _flee_list.pop_front();
+              }
+              break;
+            }
+
+    case 3: {
+              if (_pursue_obj != NULL) {
+                turn_off("pursue");
+                delete _pursue_obj;
+                _pursue_obj = NULL;
+              }
+              break;
+            }
+
+    case 4: {
+              while (!_evade_list.empty()) {
+                turn_off("evade");
+                turn_off("evade_activate");
+                _evade_list.pop_front();
+              }
+              break;
+            }
+
+    case 5: {
+              if (_arrival_obj != NULL) {
+                turn_off("arrival");
+                turn_off("arrival_activate");
+                delete _arrival_obj;
+                _arrival_obj = NULL;
+              }
+              break;
+            }
+
+    case 6: {
+              if (_flock_group != NULL) {
+                turn_off("flock");
+                turn_off("flock_activate");
+                _flock_group = NULL;
+              }
+              break;
+            }
+
+    case 7: {
+              if (_wander_obj != NULL) {
+                turn_off("wander");
+                delete _wander_obj;
+                _wander_obj = NULL;
+              }
+              break;
+            }
+
+    case 8: {
+              if (_obstacle_avoidance_obj !=NULL) {
+                turn_off("obstacle_avoidance");
+                delete _obstacle_avoidance_obj;
+                _obstacle_avoidance_obj = NULL;
+              }
+              break;
+            }
+
+    case 9: {
+              if (_pursue_obj != NULL && _path_follow_obj != NULL) {
+                turn_off("pursue");
+                delete _pursue_obj;
+                _pursue_obj = NULL;
+                delete _path_follow_obj;
+                _path_follow_obj = NULL;
+              }
+              break;
+            }
+
+    case 16: {
+              if (_pursue_obj != NULL && _path_follow_obj != NULL) {
+                turn_off("pursue");
+                delete _pursue_obj;
+                _pursue_obj = NULL;
+                delete _path_follow_obj;
+                _path_follow_obj = NULL;
+              }
+              break;
+              }
+    default:
+            cout << "Invalid option!\n";
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: pause_ai
+//  Description: This function pauses individual or all the AIs.
+////////////////////////////////////////////////////////////////////
+void AIBehaviors::pause_ai(string ai_type) {
+  switch (char_to_int(ai_type)) {
+    case 0: {
+              pause_ai("seek");
+              pause_ai("flee");
+              pause_ai("pursue");
+              pause_ai("evade");
+              pause_ai("arrival");
+              pause_ai("flock");
+              pause_ai("wander");
+              pause_ai("obstacle_avoidance");
+              pause_ai("pathfollow");
+              break;
+            }
+
+    case 1: {
+              if (_seek_obj != NULL) {
+                turn_off("seek");
+              }
+              break;
+            }
+
+    case 2: {
+              for (_flee_itr = _flee_list.begin(); _flee_itr != _flee_list.end(); _flee_itr++) {
+                turn_off("flee");
+                turn_off("flee_activate");
+              }
+              break;
+            }
+
+    case 3: {
+              if (_pursue_obj != NULL) {
+                turn_off("pursue");
+              }
+              break;
+            }
+
+    case 4: {
+              for (_evade_itr = _evade_list.begin(); _evade_itr != _evade_list.end(); _evade_itr++) {
+                turn_off("evade");
+                turn_off("evade_activate");
+              }
+              break;
+            }
+
+    case 5: {
+              if (_arrival_obj != NULL) {
+                turn_off("arrival");
+                turn_off("arrival_activate");
+              }
+              break;
+            }
+
+    case 6: {
+              if (_flock_group != NULL) {
+                turn_off("flock");
+                turn_off("flock_activate");
+              }
+              break;
+            }
+
+    case 7: {
+              if (_wander_obj != NULL) {
+                turn_off("wander");
+              }
+              break;
+            }
+
+    case 8: {
+              if (BT_obstacle_avoidance != NULL) {
+                turn_off("obstacle_avoidance");
+                turn_off("obstacle_avoidance_activate");
+              }
+              break;
+            }
+
+    case 9: {
+              if (_pursue_obj != NULL && _path_follow_obj != NULL) {
+                turn_off("pursue");
+                _path_follow_obj->_start = false;
+              }
+              break;
+            }
+    case 16: {
+              if (_pursue_obj != NULL && _path_follow_obj != NULL) {
+                turn_off("pursue");
+                _path_follow_obj->_start = false;
+              }
+              break;
+             }
+    default:
+            cout << "Invalid option!\n";
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: resume_ai
+//  Description: This function resumes individual or all the AIs
+////////////////////////////////////////////////////////////////////
+void AIBehaviors::resume_ai(string ai_type) {
+  switch (char_to_int(ai_type)) {
+    case 0: {
+              resume_ai("seek");
+              resume_ai("flee");
+              resume_ai("pursue");
+              resume_ai("evade");
+              resume_ai("arrival");
+              resume_ai("flock");
+              resume_ai("wander");
+              resume_ai("obstacle_avoidance");
+              resume_ai("pathfollow");
+              break;
+            }
+
+    case 1: {
+              if (_seek_obj != NULL) {
+                turn_on("seek");
+              }
+              break;
+            }
+
+    case 2: {
+              for (_flee_itr = _flee_list.begin(); _flee_itr != _flee_list.end(); _flee_itr++) {
+                turn_on("flee");
+              }
+              break;
+            }
+
+    case 3: {
+              if (_pursue_obj != NULL) {
+                turn_on("pursue");
+              }
+              break;
+            }
+
+    case 4: {
+              for (_evade_itr = _evade_list.begin(); _evade_itr != _evade_list.end(); _evade_itr++) {
+                turn_on("evade");
+              }
+              break;
+            }
+
+    case 5: {
+              if (_arrival_obj != NULL) {
+                turn_on("arrival");
+              }
+              break;
+            }
+
+    case 6: {
+              if (_flock_group != NULL) {
+                turn_on("flock");
+              }
+              break;
+            }
+
+    case 7: {
+              if (_wander_obj != NULL) {
+                turn_on("wander");
+              }
+              break;
+            }
+
+    case 8: {
+              if (_obstacle_avoidance_obj != NULL) {
+                turn_on("obstacle_avoidance");
+              }
+              break;
+            }
+
+    case 9: {
+              if (_pursue_obj != NULL && _path_follow_obj != NULL) {
+                turn_on("pursue");
+                _path_follow_obj->_start = true;
+              }
+              break;
+            }
+    case 16: {
+              if (_pursue_obj != NULL && _path_follow_obj != NULL) {
+                turn_off("pursue");
+                _path_follow_obj->_start = false;
+              }
+              break;
+             }
+    default:
+            cout << "Invalid option!\n";
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: seek
+//  Description: This function activates seek and makes an object
+//               of the Seek class.
+//               This is the function we want the user to call for
+//               seek to be done.
+//               This function is overloaded to accept a NodePath or 
+//               an LVecBase3f.
+////////////////////////////////////////////////////////////////////
+void AIBehaviors::seek(NodePath target_object, float seek_wt) {
+  _seek_obj = new Seek(_ai_char, target_object, seek_wt);
+  turn_on("seek");
+}
+
+void AIBehaviors::seek(LVecBase3f pos, float seek_wt) {
+  _seek_obj = new Seek(_ai_char, pos, seek_wt);
+  turn_on("seek");
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: flee
+//  Description: This function activates flee_activate and creates
+//               an object of the Flee class.
+//               This function is overloaded to accept a NodePath or
+//               an LVecBase3f.
+////////////////////////////////////////////////////////////////////
+void AIBehaviors::flee(NodePath target_object, double panic_distance,
+                                  double relax_distance, float flee_wt) {
+  _flee_obj = new Flee(_ai_char, target_object, panic_distance, 
+                                                 relax_distance, flee_wt);
+  _flee_list.insert(_flee_list.end(), *_flee_obj);
+
+  turn_on("flee_activate");
+}
+
+void AIBehaviors::flee(LVecBase3f pos, double panic_distance,
+                                    double relax_distance, float flee_wt) {
+  _flee_obj = new Flee(_ai_char, pos, panic_distance,
+                                               relax_distance, flee_wt);
+  _flee_list.insert(_flee_list.end(), *_flee_obj);
+
+  turn_on("flee_activate");
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: pursue
+//  Description: This function activates pursue.
+//               This is the function we want the user to call 
+//							 for pursue to be done.
+////////////////////////////////////////////////////////////////////
+void AIBehaviors::pursue(NodePath target_object, float pursue_wt) {
+  _pursue_obj = new Pursue(_ai_char, target_object, pursue_wt);
+
+  turn_on("pursue");
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: evade
+//  Description: This function activates evade_activate.
+////////////////////////////////////////////////////////////////////
+void AIBehaviors::evade(NodePath target_object, double panic_distance,
+																		double relax_distance, float evade_wt) {
+  _evade_obj = new Evade(_ai_char, target_object, panic_distance, relax_distance, evade_wt);
+  _evade_list.insert(_evade_list.end(), *_evade_obj);
+
+  turn_on("evade_activate");
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: arrival
+//  Description: This function activates arrival.
+//               This is the function we want the user to call for
+//               arrival to be done.
+////////////////////////////////////////////////////////////////////
+void AIBehaviors::arrival(double distance) {
+  if (_pursue_obj) {
+    _arrival_obj = new Arrival(_ai_char, distance);
+    _arrival_obj->_arrival_type = true;
+    turn_on("arrival_activate");
+  }
+  else if (_seek_obj) {
+    _arrival_obj = new Arrival(_ai_char, distance);
+    _arrival_obj->_arrival_type = false;
+    turn_on("arrival_activate");
+  }
+  else {
+    cout << "Note: A Seek or Pursue behavior is required to use Arrival behavior.\n";
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: flock
+//  Description: This function activates flock.
+//               This is the function we want the user to call for 
+//               flock to be done.
+////////////////////////////////////////////////////////////////////
+void AIBehaviors::flock(float flock_wt) {
+  _flock_weight = flock_wt;
+
+  _flock_done = false;
+  turn_on("flock_activate");
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: flock_activate
+//  Description: This function checks whether any other behavior 
+//               exists to work with flock.
+//               When this is true, it calls the do_flock function.
+////////////////////////////////////////////////////////////////////
+void AIBehaviors::flock_activate() {
+  if (is_on(BT_seek) || is_on(BT_flee) || is_on(BT_pursue) || is_on(BT_evade) || is_on(BT_wander)) {
+      turn_off("flock_activate");
+      turn_on("flock");
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: do_flock
+//  Description: This function contains the logic for flocking 
+//               behavior. This is an emergent behavior and is 
+//               obtained by combining three other behaviors which
+//               are separation, cohesion and alignment based on
+//               Craig Reynold's algorithm. Also, this behavior does
+//               not work by itself. It works only when combined with
+//               other steering behaviors such as wander, pursue, 
+//               evade, seek and flee.
+////////////////////////////////////////////////////////////////////
+LVecBase3f AIBehaviors::do_flock() {
+
+  // Initialize variables required to compute the flocking force
+ // on the ai char.
+  unsigned int neighbor_count = 0;
+  LVecBase3f separation_force = LVecBase3f(0.0, 0.0, 0.0);
+  LVecBase3f alignment_force = LVecBase3f(0.0, 0.0, 0.0);
+  LVecBase3f cohesion_force = LVecBase3f(0.0, 0.0, 0.0);
+  LVecBase3f avg_neighbor_heading = LVecBase3f(0.0, 0.0, 0.0);
+  LVecBase3f total_neighbor_heading = LVecBase3f(0.0, 0.0, 0.0);
+  LVecBase3f avg_center_of_mass = LVecBase3f(0.0, 0.0, 0.0);
+  LVecBase3f total_center_of_mass = LVecBase3f(0.0, 0.0, 0.0);
+
+ // Loop through all the other AI units in the flock to check
+ // if they are neigbours.
+  for (unsigned int i = 0; i < _flock_group->_ai_char_list.size(); i++) {
+    if (_flock_group->_ai_char_list[i]->_name != _ai_char->_name) {
+
+      // Using visibilty cone to detect neighbors.
+      LVecBase3f dist_vect = _flock_group->_ai_char_list[i]->_ai_char_np.get_pos()
+                                                     - _ai_char->_ai_char_np.get_pos();
+      LVecBase3f ai_char_heading = _ai_char->get_velocity();
+      ai_char_heading.normalize();
+
+      // Check if the current unit is a neighbor.
+      if (dist_vect.dot(ai_char_heading) > ((dist_vect.length()) * (ai_char_heading.length())
+                                             * cos(_flock_group->_flock_vcone_angle * (_PI / 180)))
+        && (dist_vect.length() < _flock_group->_flock_vcone_radius)) {
+          // Separation force calculation.
+          LVecBase3f ai_char_to_units = _ai_char->_ai_char_np.get_pos() 
+                                            - _flock_group->_ai_char_list[i]->_ai_char_np.get_pos();
+          float to_units_dist = ai_char_to_units.length();
+          ai_char_to_units.normalize();
+          separation_force += (ai_char_to_units / to_units_dist);
+
+          // Calculating the total heading and center of mass of all the neighbors.
+          LVecBase3f neighbor_heading = _flock_group->_ai_char_list[i]->get_velocity();
+          neighbor_heading.normalize();
+          total_neighbor_heading += neighbor_heading;
+          total_center_of_mass += _flock_group->_ai_char_list[i]->_ai_char_np.get_pos();
+
+          // Update the neighbor count.
+          ++neighbor_count;
+      }
+    }
+  }
+
+  if (neighbor_count > 0) {
+    // Alignment force calculation
+    avg_neighbor_heading = total_neighbor_heading / neighbor_count;
+    LVector3f ai_char_heading = _ai_char->get_velocity();
+    ai_char_heading.normalize();
+    avg_neighbor_heading -= ai_char_heading;
+    avg_neighbor_heading.normalize();
+    alignment_force = avg_neighbor_heading;
+
+    // Cohesion force calculation
+    avg_center_of_mass = total_center_of_mass / neighbor_count;
+    LVecBase3f cohesion_dir = avg_center_of_mass - _ai_char->_ai_char_np.get_pos();
+    cohesion_dir.normalize();
+    cohesion_force = cohesion_dir * _ai_char->_movt_force;
+  }
+  else if (is_on(BT_seek) || is_on(BT_flee) || is_on(BT_pursue) || 
+                                         is_on(BT_evade) || is_on(BT_wander)) {
+    _flock_done = true;
+    turn_off("flock");
+    turn_on("flock_activate");
+    return (LVecBase3f(0.0, 0.0, 0.0));
+  }
+
+  // Calculate the resultant force on the ai character by taking into
+ //  account the separation, alignment and cohesion
+ // forces along with their corresponding weights.
+  return (separation_force * _flock_group->_separation_wt + 
+                avg_neighbor_heading * _flock_group->_alignment_wt
+    + cohesion_force * _flock_group->_cohesion_wt);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: wander
+//  Description: This function activates wander.
+//               This is the function we want the user to call 
+//               for flock to be done.
+////////////////////////////////////////////////////////////////////
+void AIBehaviors::wander(double wander_radius, int flag, double aoe, 
+                                                  float wander_weight) {
+  _wander_obj = new Wander(_ai_char, wander_radius, flag, aoe,
+                                                       wander_weight);
+  turn_on("wander");
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: obstacle avoidance
+//  Description: This function activates obstacle avoidance for a 
+//               given character.
+//               This is the function we want the user to call for
+//               obstacle avoidance to be performed.
+////////////////////////////////////////////////////////////////////
+void AIBehaviors::obstacle_avoidance(float obstacle_avoidance_weight) {
+  _obstacle_avoidance_obj = new ObstacleAvoidance(_ai_char, obstacle_avoidance_weight);
+  turn_on("obstacle_avoidance_activate");
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: path_follow
+//  Description: This function activates path following.
+//               This is the function we want the user to call for 
+//               path following.
+////////////////////////////////////////////////////////////////////
+void AIBehaviors::path_follow(float follow_wt) {
+  _path_follow_obj = new PathFollow(_ai_char, follow_wt);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: add_to_path
+//  Description: This function adds positions to the path to follow.
+////////////////////////////////////////////////////////////////////
+void AIBehaviors::add_to_path(LVecBase3f pos) {
+  _path_follow_obj->add_to_path(pos);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: start_follow
+//  Description: This function starts the path follower.
+////////////////////////////////////////////////////////////////////
+void AIBehaviors::start_follow(string type) {
+  _path_follow_obj->start(type);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: init_path_find
+//  Description: This function activates path finding in the character.
+//               This function accepts the meshdata in .csv format.
+////////////////////////////////////////////////////////////////////
+void AIBehaviors::init_path_find(const char* navmesh_filename) {
+  _path_find_obj = new PathFind(_ai_char);
+  _path_find_obj->set_path_find(navmesh_filename);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: path_find_to (for pathfinding towards a 
+//                                                  static position)
+//  Description: This function checks for the source and target in 
+//               the navigation mesh for its availability and then
+//               finds the best path via the A* algorithm
+//               Then it calls the path follower to make the object
+//               follow the path.
+////////////////////////////////////////////////////////////////////
+void AIBehaviors::path_find_to(LVecBase3f pos, string type) {
+  _path_find_obj->path_find(pos, type);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: path_find_to (for pathfinding towards a moving 
+//                                              target (a NodePath))
+//  Description: This function checks for the source and target in 
+//               the navigation mesh for its availability and then
+//               finds the best path via the A* algorithm
+//               Then it calls the path follower to make the object
+//               follow the path.
+////////////////////////////////////////////////////////////////////
+void AIBehaviors::path_find_to(NodePath target, string type) {
+  _path_find_obj->path_find(target, type);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: add_static_obstacle
+//  Description: This function allows the user to dynamically add 
+//               obstacles to the
+//               game environment. The function will update the nodes
+//               within the bounding volume of the obstacle as non-
+//               traversable. Hence will not be considered by the 
+//               pathfinding algorithm.
+////////////////////////////////////////////////////////////////////
+void AIBehaviors::add_static_obstacle(NodePath obstacle) {
+  _path_find_obj->add_obstacle_to_mesh(obstacle);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: add_dynamic_obstacle
+//  Description: This function starts the pathfinding obstacle 
+//               navigation for the passed in obstacle.
+////////////////////////////////////////////////////////////////////
+void AIBehaviors::add_dynamic_obstacle(NodePath obstacle) {
+  _path_find_obj->dynamic_avoid(obstacle);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: behavior_status
+//  Description: This function returns the status of an AI Type 
+//               whether it is active, paused or disabled. It returns
+//               -1 if an invalid string is passed.
+////////////////////////////////////////////////////////////////////
+string AIBehaviors::behavior_status(string ai_type) {
+  switch (char_to_int(ai_type)) {
+    case 1:
+      if (_seek_obj) {
+        if (is_on(BT_seek)) {
+                    return "active";
+        }
+        else {
+            if (_seek_obj->_seek_done) {
+            return "done";
+            }
+          return "paused";
+        }
+      }
+      else {
+        return "disabled";
+      }
+      break;
+
+    case 2:
+      if (_flee_obj) {
+        if (is_on(BT_flee)) {
+          unsigned int i = 0;
+          for (_flee_itr = _flee_list.begin(); _flee_itr != _flee_list.end(); _flee_itr++) {
+            if (_flee_itr->_flee_done == true) {
+              ++i;
+            }
+          }
+          if (i == _flee_list.size()) {
+            return "done";
+          }
+          else {
+            return "active";
+          }
+        }
+        else {
+          return "paused";
+        }
+      }
+      else {
+        return "disabled";
+      }
+      break;
+
+    case 3:
+      if (_pursue_obj) {
+        if (is_on(BT_pursue)) {
+          if (_pursue_obj->_pursue_done) {
+            return "done";
+          }
+          else {
+            return "active";
+          }
+        }
+        else {
+          return "paused";
+        }
+      }
+      else {
+          return "disabled";
+      }
+      break;
+
+    case 4:
+      if (_evade_obj) {
+        if (is_on(BT_evade)) {
+          unsigned int i = 0;
+          for (_evade_itr = _evade_list.begin(); _evade_itr != _evade_list.end(); _evade_itr++) {
+            if (_evade_itr->_evade_done == true) {
+              ++i;
+            }
+          }
+          if (i == _evade_list.size()) {
+            return "done";
+          }
+          else {
+            return "active";
+          }
+        }
+        else {
+          return "paused";
+        }
+      }
+      else {
+        return "disabled";
+      }
+      break;
+
+    case 5:
+      if (_arrival_obj) {
+        if (is_on(BT_arrival)) {
+          if (_arrival_obj->_arrival_done) {
+            return "done";
+          }
+          else {
+            return "active";
+          }
+        }
+        else {
+          return "paused";
+        }
+      }
+      else {
+          return "disabled";
+      }
+      break;
+
+    case 6:
+      if (_flock_group) {
+        if (is_on(BT_flock)) {
+          if (_flock_done) {
+            return "done";
+          }
+          else {
+            return "active";
+          }
+          return "active";
+        }
+        else {
+          return "paused";
+        }
+      }
+      else {
+        return "disabled";
+      }
+      break;
+
+    case 7:
+      if (_wander_obj) {
+        if (is_on(BT_wander)) {
+          return "active";
+        }
+        else {
+          return "paused";
+        }
+      }
+      else {
+        return "disabled";
+      }
+      break;
+
+      case 8:
+        if (_obstacle_avoidance_obj) {
+          if (is_on(BT_obstacle_avoidance)) {
+            return "active";
+          }
+          else {
+            return "paused";
+          }
+        }
+        else {
+          return "disabled";
+        }
+        break;
+
+      case 9:
+        if (_path_follow_obj) {
+          if (is_on("pathfollow")) {
+            if (_pursue_obj->_pursue_done) {
+              return "done";
+            }
+            else {
+              return "active";
+            }
+          }
+          else {
+            return "paused";
+          }
+        }
+        else {
+          return "disabled";
+        }
+        break;
+
+      case 16:
+        if (_path_find_obj) {
+          if (is_on("pathfind")) {
+            if (_pursue_obj->_pursue_done) {
+              return "done";
+            }
+            else {
+              return "active";
+            }
+          }
+          else {
+            return "paused";
+          }
+        }
+        else {
+          return "disabled";
+        }
+        break;
+
+      case 10:
+        if (_seek_obj || _flee_obj || _pursue_obj || _evade_obj || _arrival_obj 
+             || _flock_group || _wander_obj || _obstacle_avoidance_obj || 
+             _path_follow_obj) {
+          if (is_on(BT_seek) || is_on(BT_flee) || is_on(BT_pursue)||
+              is_on(BT_evade) || is_on(BT_arrival) || is_on(BT_flock) 
+              || is_on(BT_wander) || is_on(BT_obstacle_avoidance) || 
+              is_on("pathfollow") || is_on("pathfinding")) {
+            return "active";
+          }
+          else {
+            return "paused";
+          }
+        }
+        else {
+          return "disabled";
+        }
+        break;
+
+      default:
+        cout << "Invalid value!\n";
+    }
+  }
+
+////////////////////////////////////////////////////////////////////
+//     Function: char_to_int
+//  Description: This function is used to derive int values from the
+//               ai types strings.
+//               Returns -1 if an invalid string is passed.
+////////////////////////////////////////////////////////////////////
+int AIBehaviors::char_to_int(string ai_type) {
+  if (ai_type == "all") {
+    return 0;
+  }
+  else if (ai_type == "seek") {
+    return 1;
+  }
+  else if (ai_type == "flee") {
+    return 2;
+  }
+  else if (ai_type == "pursue") {
+    return 3;
+  }
+  else if (ai_type == "evade") {
+    return 4;
+  }
+  else if (ai_type == "arrival") {
+    return 5;
+  }
+  else if (ai_type == "flock") {
+    return 6;
+  }
+  else if (ai_type == "wander") {
+    return 7;
+  }
+  else if (ai_type == "obstacle_avoidance") {
+    return 8;
+  }
+  else if (ai_type == "pathfollow") {
+    return 9;
+  }
+  else if (ai_type == "any") {
+    return 10;
+  }
+  else if (ai_type == "flee_activate") {
+    return 11;
+  }
+  else if (ai_type == "evade_activate") {
+    return 12;
+  }
+  else if (ai_type == "arrival_activate") {
+    return 13;
+  }
+  else if (ai_type == "flock_activate") {
+    return 14;
+  }
+  else if (ai_type == "obstacle_avoidance_activate") {
+    return 15;
+  }
+  else if (ai_type == "path_finding") {
+    return 16;
+  }
+
+  return -1;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: turn_on
+//  Description: This function turns on any aiBehavior which is 
+//               passed as a string.
+////////////////////////////////////////////////////////////////////
+void AIBehaviors::turn_on(string ai_type) {
+  switch (char_to_int(ai_type)) {
+    case 1: {
+              _behaviors_flags |= BT_seek;
+              break;
+            }
+    case 2: {
+              _behaviors_flags |= BT_flee;
+              break;
+            }
+    case 3: {
+              _behaviors_flags |= BT_pursue;
+              break;
+            }
+    case 4: {
+              _behaviors_flags |= BT_evade;
+              break;
+            }
+    case 5: {
+              _behaviors_flags |= BT_arrival;
+              break;
+            }
+    case 6: {
+              _behaviors_flags |= BT_flock;
+              break;
+            }
+    case 7: {
+              _behaviors_flags |= BT_wander;
+              break;
+            }
+    case 8: {
+              _behaviors_flags |= BT_obstacle_avoidance;
+              break;
+            }
+    case 11:{
+              _behaviors_flags |= BT_flee_activate;
+              break;
+            }
+    case 12:{
+              _behaviors_flags |= BT_evade_activate;
+              break;
+            }
+    case 13:{
+              _behaviors_flags |= BT_arrival_activate;
+              break;
+            }
+    case 14:{
+              _behaviors_flags |= BT_flock_activate;
+              break;
+            }
+    case 15:{
+              _behaviors_flags |= BT_obstacle_avoidance_activate;
+              break;
+            }
+    default:
+            cout << "Invalid option!\n";
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: turn_off
+//  Description: This function turns off any aiBehavior which is 
+//               passed as a string.
+////////////////////////////////////////////////////////////////////
+void AIBehaviors::turn_off(string ai_type) {
+switch (char_to_int(ai_type)) {
+    case 1: {
+              if (is_on(BT_seek)) {
+                _behaviors_flags ^= BT_seek;
+              }
+              _seek_force = LVecBase3f(0.0f, 0.0f, 0.0f);
+              break;
+            }
+    case 2: {
+              if (is_on(BT_flee)) {
+                _behaviors_flags ^= BT_flee;
+              }
+              _flee_force = LVecBase3f(0.0f, 0.0f, 0.0f);
+              break;
+            }
+    case 3: {
+              if (is_on(BT_pursue)) {
+                _behaviors_flags ^= BT_pursue;
+              }
+              _pursue_force = LVecBase3f(0.0f, 0.0f, 0.0f);
+              break;
+            }
+    case 4: {
+              if (is_on(BT_evade)) {
+                _behaviors_flags ^= BT_evade;
+              }
+              _evade_force = LVecBase3f(0.0f, 0.0f, 0.0f);
+              break;
+            }
+    case 5: {
+              if (is_on(BT_arrival)) {
+                _behaviors_flags ^= BT_arrival;
+              }
+              _arrival_force = LVecBase3f(0.0f, 0.0f, 0.0f);
+              break;
+            }
+    case 6: {
+              if (is_on(BT_flock)) {
+                _behaviors_flags ^= BT_flock;
+              }
+              _flock_force = LVecBase3f(0.0f, 0.0f, 0.0f);
+              break;
+            }
+    case 7: {
+              if (is_on(BT_wander)) {
+                _behaviors_flags ^= BT_wander;
+              }
+              _wander_force = LVecBase3f(0.0f, 0.0f, 0.0f);
+              break;
+            }
+    case 8: {
+              if (is_on(BT_obstacle_avoidance)) {
+                _behaviors_flags ^= BT_obstacle_avoidance;
+              }
+              _obstacle_avoidance_force = LVecBase3f(0.0f, 0.0f, 0.0f);
+              break;
+            }
+    case 9: {
+              turn_off("pursue");
+              break;
+            }
+    case 11: {
+              if (is_on(BT_flee_activate)) {
+                _behaviors_flags ^= BT_flee_activate;
+              }
+              break;
+             }
+    case 12:{
+              if (is_on(BT_evade_activate)) {
+                _behaviors_flags ^= BT_evade_activate;
+              }
+              break;
+            }
+    case 13:{
+              if (is_on(BT_arrival_activate)) {
+                _behaviors_flags ^= BT_arrival_activate;
+              }
+              break;
+            }
+    case 14:{
+              if (is_on(BT_flock_activate)) {
+                _behaviors_flags ^= BT_flock_activate;
+              }
+              break;
+            }
+    case 15:{
+              if (is_on(BT_obstacle_avoidance_activate)) {
+                _behaviors_flags ^= BT_obstacle_avoidance_activate;
+              }
+              break;
+            }
+    case 16:{
+              turn_off("pathfollow");
+              break;
+            }
+    default:
+            cout << "Invalid option!\n";
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: is_on
+//  Description: This function returns true if an aiBehavior is on
+////////////////////////////////////////////////////////////////////
+bool AIBehaviors::is_on(BehaviorType bt) {
+  return (_behaviors_flags & bt) == bt;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: is_on
+//  Description: This function returns true if pathfollow or 
+//               pathfinding is on
+////////////////////////////////////////////////////////////////////
+bool AIBehaviors::is_on(string ai_type) {
+  if (ai_type == "pathfollow") {
+    if (_path_follow_obj) {
+      return (is_on(BT_pursue) && _path_follow_obj->_start);
+    }
+    else {
+      return false;
+    }
+  }
+
+  if (ai_type == "pathfinding") {
+    if (_path_follow_obj && _path_find_obj) {
+      return (is_on(BT_pursue) && _path_follow_obj->_start);
+    }
+    else {
+      return false;
+    }
+  }
+
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: is_off
+//  Description: This function returns true if an aiBehavior is off
+////////////////////////////////////////////////////////////////////
+bool AIBehaviors::is_off(BehaviorType bt) {
+  return ((_behaviors_flags | bt) == bt);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: is_off
+//  Description: This function returns true if pathfollow or 
+//               pathfinding is off
+////////////////////////////////////////////////////////////////////
+bool AIBehaviors::is_off(string ai_type) {
+  if (ai_type == "pathfollow") {
+    if (_path_follow_obj && _path_follow_obj->_start) {
+      return true;
+    }
+    else {
+      return false;
+    }
+  }
+
+  if (ai_type == "pathfinding") {
+    if (_path_find_obj && _path_follow_obj && _path_follow_obj->_start) {
+      return true;
+    }
+    else {
+      return false;
+    }
+  }
+
+  cout << "You passed an invalid string, defaulting return value to false!\n";
+  return false;
+}

+ 193 - 0
contrib/src/ai/aiBehaviors.h

@@ -0,0 +1,193 @@
+// Filename: aiBehaviors.h
+// Created by:  Deepak, John, Navin (08Sep09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised 
+// BSD license.  You should have received a copy of this license 
+// along with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef AIBEHAVIORS_H
+#define AIBEHAVIORS_H
+
+#include "aiGlobals.h"
+#include "aiCharacter.h"
+
+#include "seek.h"
+#include "flee.h"
+#include "pursue.h"
+#include "evade.h"
+#include "arrival.h"
+#include "flock.h"
+#include "wander.h"
+#include "pathFollow.h"
+#include "pathFind.h"
+#include "obstacleAvoidance.h"
+
+class AICharacter;
+class Seek;
+class Flee;
+class Pursue;
+class Evade;
+class Arrival;
+class Flock;
+class Wander;
+class PathFollow;
+class PathFind;
+class ObstacleAvoidance;
+
+typedef list<Flee, allocator<Flee> > ListFlee;
+typedef list<Evade, allocator<Evade> > ListEvade;
+
+////////////////////////////////////////////////////////////////////
+//       Class : AIBehaviors
+// Description : This class implements all the steering behaviors
+//               of the AI framework, such as seek, flee, pursue,
+//               evade, wander and flock. Each steering behavior
+//               has a weight which is used when more than one type
+//               of steering behavior is acting on the same AI
+//               character. The weight decides the contribution of
+//               each type of steering behavior. The AICharacter
+//               class has a handle to an object of this class and
+//               this allows to invoke the steering behaviors via
+//               the AICharacter. This class also provides
+//               functionality such as pausing, resuming and
+//               removing the AI behaviors of an AI character at
+//               any time.
+///////////////////////////////////////////////////////////////////
+class AIBehaviors {
+
+public:
+  enum BehaviorType {
+    BT_none = 0x00000,
+    BT_seek = 0x00002,
+    BT_flee = 0x00004,
+    BT_flee_activate = 0x00100,
+    BT_arrival = 0x00008,
+    BT_arrival_activate = 0x01000,
+    BT_wander = 0x00010,
+    BT_pursue = 0x00040,
+    BT_evade = 0x00080,
+    BT_evade_activate = 0x00800,
+    BT_flock = 0x00200,
+    BT_flock_activate = 0x00400,
+    BT_obstacle_avoidance = 0x02000,
+    BT_obstacle_avoidance_activate = 0x04000,
+  };
+
+  AICharacter *_ai_char;
+  Flock *_flock_group;
+
+  int _behaviors_flags;
+  LVecBase3f _steering_force;
+
+  Seek *_seek_obj;
+  LVecBase3f _seek_force;
+
+  Flee *_flee_obj;
+  LVecBase3f _flee_force;
+
+  // This list is used if the ai character needs to flee from 
+  // multiple onjects.
+  ListFlee _flee_list;
+  ListFlee::iterator _flee_itr;
+
+  Pursue *_pursue_obj;
+  LVecBase3f _pursue_force;
+
+  Evade *_evade_obj;
+  LVecBase3f _evade_force;
+
+  // This list is used if the ai character needs to evade from
+  // multiple onjects.
+  ListEvade _evade_list;
+  ListEvade::iterator _evade_itr;
+
+  Arrival *_arrival_obj;
+  LVecBase3f _arrival_force;
+
+  // Since Flock is a collective behavior the variables are 
+  // declared within the AIBehaviors class.
+  float _flock_weight;
+  LVecBase3f _flock_force;
+  bool _flock_done;
+
+  Wander * _wander_obj;
+  LVecBase3f _wander_force;
+
+  ObstacleAvoidance *_obstacle_avoidance_obj;
+  LVecBase3f _obstacle_avoidance_force;
+
+  PathFollow *_path_follow_obj;
+
+  PathFind *_path_find_obj;
+
+  bool _conflict, _previous_conflict;
+
+  AIBehaviors();
+  ~AIBehaviors();
+
+  bool is_on(BehaviorType bt);
+  bool is_off(BehaviorType bt);
+  // special cases for pathfollow and pathfinding
+  bool is_on(string ai_type); 
+  bool is_off(string ai_type);
+  void turn_on(string ai_type);
+  void turn_off(string ai_type);
+
+  bool is_conflict();
+
+  void accumulate_force(string force_type, LVecBase3f force);
+  LVecBase3f calculate_prioritized();
+
+  void flock_activate();
+  LVecBase3f do_flock();
+
+  int char_to_int(string ai_type);
+
+PUBLISHED:
+  void seek(NodePath target_object, float seek_wt = 1.0);
+  void seek(LVecBase3f pos, float seek_wt = 1.0);
+
+  void flee(NodePath target_object, double panic_distance = 10.0,
+                   double relax_distance = 10.0, float flee_wt = 1.0);
+  void flee(LVecBase3f pos, double panic_distance = 10.0, 
+                   double relax_distance = 10.0, float flee_wt = 1.0);
+
+  void pursue(NodePath target_object, float pursue_wt = 1.0);
+
+  void evade(NodePath target_object, double panic_distance = 10.0, 
+                  double relax_distance = 10.0, float evade_wt = 1.0);
+
+  void arrival(double distance = 10.0);
+
+  void flock(float flock_wt);
+
+  void wander(double wander_radius = 5.0, int flag =0, 
+                      double aoe = 0.0, float wander_weight = 1.0);
+
+  void obstacle_avoidance(float feeler_length = 1.0);
+
+  void path_follow(float follow_wt = 1.0);
+  void add_to_path(LVecBase3f pos);
+  void start_follow(string type = "normal");
+
+  void init_path_find(const char* navmesh_filename);
+  void path_find_to(LVecBase3f pos, string type = "normal");
+  void path_find_to(NodePath target, string type = "normal");
+  void add_static_obstacle(NodePath obstacle);
+  void add_dynamic_obstacle(NodePath obstacle);
+
+  void remove_ai(string ai_type);
+  void pause_ai(string ai_type);
+  void resume_ai(string ai_type);
+
+  string behavior_status(string ai_type);
+};
+
+#endif

+ 127 - 0
contrib/src/ai/aiCharacter.cxx

@@ -0,0 +1,127 @@
+// Filename: aiCharacter.cxx
+// Created by:  Deepak, John, Navin (08Sep09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised 
+// BSD license.  You should have received a copy of this license 
+// along with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "aiCharacter.h"
+
+AICharacter::AICharacter(string model_name, NodePath model_np, double mass,
+                                          double movt_force, double max_force) {
+  _name = model_name;
+  _ai_char_np = model_np;
+
+  _mass = mass;
+  _max_force = max_force;
+  _movt_force = movt_force;
+
+  _velocity = LVecBase3f(0.0, 0.0, 0.0);
+  _steering_force = LVecBase3f(0.0, 0.0, 0.0);
+
+  _steering = new AIBehaviors();
+  _steering->_ai_char = this;
+
+  _pf_guide = false;
+}
+
+AICharacter::~AICharacter() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: update
+//  Description: Each character's update will update its ai and
+//               physics based on his resultant steering force.
+//               This also makes the character look in the
+//               direction of the force.
+////////////////////////////////////////////////////////////////////
+void AICharacter::update() {
+
+if (!_steering->is_off(_steering->BT_none)) {
+
+    LVecBase3f old_pos = _ai_char_np.get_pos();
+
+    LVecBase3f steering_force = _steering->calculate_prioritized();
+
+    LVecBase3f acceleration = steering_force / _mass;
+
+    _velocity = acceleration;
+
+    LVecBase3f direction = _steering->_steering_force;
+    direction.normalize();
+
+    _ai_char_np.set_pos(old_pos + _velocity) ;
+
+    if (steering_force.length() > 0) {
+      _ai_char_np.look_at(old_pos + (direction * 5));
+      _ai_char_np.set_h(_ai_char_np.get_h() + 180);
+      _ai_char_np.set_p(-_ai_char_np.get_p());
+      _ai_char_np.set_r(-_ai_char_np.get_r());
+    }
+  }
+  else {
+    _steering->_steering_force = LVecBase3f(0.0, 0.0, 0.0);
+    _steering->_seek_force = LVecBase3f(0.0, 0.0, 0.0);
+    _steering->_flee_force = LVecBase3f(0.0, 0.0, 0.0);
+    _steering->_pursue_force = LVecBase3f(0.0, 0.0, 0.0);
+    _steering->_evade_force = LVecBase3f(0.0, 0.0, 0.0);
+    _steering->_arrival_force = LVecBase3f(0.0, 0.0, 0.0);
+    _steering->_flock_force = LVecBase3f(0.0, 0.0, 0.0);
+    _steering->_wander_force = LVecBase3f(0.0, 0.0, 0.0);
+  }
+}
+
+LVecBase3f AICharacter::get_velocity() {
+  return _velocity;
+}
+
+void AICharacter::set_velocity(LVecBase3f velocity) {
+  _velocity = velocity;
+}
+
+double AICharacter::get_mass() {
+  return _mass;
+}
+
+void AICharacter::set_mass(double m) {
+  _mass = m;
+}
+
+double AICharacter::get_max_force() {
+  return _max_force;
+}
+
+void AICharacter::set_max_force(double max_force) {
+  _max_force = max_force;
+}
+
+NodePath AICharacter::get_node_path() {
+  return _ai_char_np;
+}
+
+void AICharacter::set_node_path(NodePath np) {
+  _ai_char_np = np;
+}
+
+AIBehaviors * AICharacter::get_ai_behaviors() {
+  return _steering;
+}
+
+void AICharacter::set_char_render(NodePath render) {
+  _window_render = render;
+}
+
+NodePath AICharacter::get_char_render() {
+  return _window_render;
+}
+
+void AICharacter::set_pf_guide(bool pf_guide) {
+  _pf_guide = pf_guide;
+}

+ 76 - 0
contrib/src/ai/aiCharacter.h

@@ -0,0 +1,76 @@
+// Filename: aiCharacter.h
+// Created by:  Deepak, John, Navin (08Sep09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised 
+// BSD license. You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef AICHARACTER_H
+#define AICHARACTER_H
+
+#include "aiBehaviors.h"
+#include "aiWorld.h"
+
+class AIBehaviors;
+class AIWorld;
+
+////////////////////////////////////////////////////////////////////
+//       Class : AICharacter
+// Description : This class is used for creating the ai characters.
+//               It assigns both physics and ai attributes to the 
+//               character. It also has an update function which 
+//               updates the physics and ai of the character.
+//               This update function is called by the AIWorld 
+//               update.
+////////////////////////////////////////////////////////////////////
+class AICharacter {
+ public:
+  double _mass;
+  double _max_force;
+  LVecBase3f _velocity;
+  LVecBase3f _steering_force;
+  string _name;
+  double _movt_force;
+  unsigned int _ai_char_flock_id;
+  AIWorld *_world;
+  AIBehaviors *_steering;
+  NodePath _window_render;
+  NodePath _ai_char_np;
+  bool _pf_guide;
+
+  void update();
+  void set_velocity(LVecBase3f vel);
+  void set_char_render(NodePath render);
+  NodePath get_char_render();
+
+PUBLISHED:
+    double get_mass();
+    void set_mass(double m);
+
+    LVecBase3f get_velocity();
+
+    double get_max_force();
+    void set_max_force(double max_force);
+
+    NodePath get_node_path();
+    void set_node_path(NodePath np);
+
+    AIBehaviors * get_ai_behaviors();
+
+    // This function is used to enable or disable the guides 
+    // for path finding.
+    void set_pf_guide(bool pf_guide);
+
+    AICharacter(string model_name, NodePath model_np, double mass, 
+                                      double movt_force, double max_force);
+    ~AICharacter();
+};
+
+#endif

+ 28 - 0
contrib/src/ai/aiGlobals.h

@@ -0,0 +1,28 @@
+// Filename: aiGlobals.h
+// Created by:  Deepak, John, Navin (08Sep09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised 
+// BSD license.  You should have received a copy of this license
+// along with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef AIGLOBALS_H
+#define AIGLOBALS_H
+
+#include "pandaFramework.h"
+#include "textNode.h"
+#include "pandaSystem.h"
+
+#include "lvecBase3.h"
+#include "nodePath.h"
+
+#include "genericAsyncTask.h"
+#include "asyncTaskManager.h"
+
+#endif

+ 53 - 0
contrib/src/ai/aiNode.cxx

@@ -0,0 +1,53 @@
+// Filename: aiNode.cxx
+// Created by:  Deepak, John, Navin (19Nov2009)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised 
+// BSD license.  You should have received a copy of this license
+// along with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "aiNode.h"
+
+AINode::AINode(int grid_x, int grid_y, LVecBase3f pos, float w, float l, float h) {
+  for (int i = 0; i < 8; ++i) {
+    _neighbours[i] = NULL;
+  }
+
+  _position = pos;
+  _width = w;
+  _length = l;
+  _height = h;
+  _grid_x = grid_x;
+  _grid_y = grid_y;
+  _status = ST_neutral;
+  _type = true;
+  _score = 0;
+  _cost = 0;
+  _heuristic = 0;
+  _next = NULL;
+  _prv_node =  NULL;
+}
+
+AINode::~AINode() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: contains
+//  Description: This is a handy function which returns true if the
+//               passed position is within the node's dimensions.
+////////////////////////////////////////////////////////////////////
+bool AINode::contains(float x, float y) {
+  if (_position.get_x() - _width / 2 <= x && _position.get_x() + _width / 2 >= x &&
+    _position.get_y() - _length / 2 <= y && _position.get_y() + _length / 2 >= y) {
+    return true;
+  }
+  else {
+    return false;
+  }
+}

+ 85 - 0
contrib/src/ai/aiNode.h

@@ -0,0 +1,85 @@
+// Filename: aiNode.h
+// Created by:  Deepak, John, Navin (18Nov2009)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised 
+// BSD license.  You should have received a copy of this license
+// along with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef AINODE_H
+#define AINODE_H
+
+#include "aiGlobals.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : AINode
+// Description : This class is used to assign the nodes on the mesh.
+//               It holds all the data necessary to compute A*
+//               algorithm. It also maintains a lot of vital
+//               information such as the neighbor nodes of each
+//               node and also its position on the mesh.
+//               Note: The Mesh Generator which is a standalone
+//               tool makes use of this class to generate the nodes
+//               on the mesh.
+////////////////////////////////////////////////////////////////////
+class AINode {
+public:
+  // This variable specifies whether the node is an obtacle or not.
+  // Used for dynamic obstacle addition to the environment.
+  // obstacle = false
+  // navigational = true
+  bool _type;
+
+  // This variable specifies the node status whether open, close
+  // or neutral.
+  // open = belongs to _open_list.
+  // close = belongs to _closed_list.
+  // neutral = unexamined node.
+  enum Status {
+    ST_open,
+    ST_close,
+    ST_neutral
+  };
+  Status _status;
+
+  // The score is used to compute the traversal expense to nodes
+  // when using A*.
+  // _score = _cost + heuristic
+  int _score;
+  int _cost;
+  int _heuristic;
+
+  // Used to trace back the path after it is generated using A*.
+  AINode *_prv_node;
+
+  // Position of the node in the 2d grid.
+  int _grid_x, _grid_y;
+
+  // Position of the node in 3D space.
+  LVecBase3f _position;
+
+  // Dimensions of each face / cell on the mesh.
+  // Height is given in case of expansion to a 3d mesh. Currently
+  // not used.
+  float _width, _length ,_height;
+  AINode *_neighbours[8]; // anti-clockwise from top left corner.
+
+  // The _next pointer is used for traversal during mesh
+  // generation from the model.
+  // Note: The data in this member is discarded when mesh data
+  // is written into navmesh.csv file.
+  AINode *_next;
+
+  AINode(int grid_x, int grid_y, LVecBase3f pos, float w, float l, float h);
+  ~AINode();
+
+  bool contains(float x, float y);
+};
+
+#endif

+ 377 - 0
contrib/src/ai/aiPathFinder.cxx

@@ -0,0 +1,377 @@
+// Filename: aiPathfinder.cxx
+// Created by:  Deepak, John, Navin (08Sep09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised 
+// BSD license. You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "aiPathFinder.h"
+
+PathFinder::PathFinder(NavMesh nav_mesh) {
+  _grid = nav_mesh;
+}
+
+PathFinder::~PathFinder() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: find_path
+//  Description: This function initializes the pathfinding process
+//               by accepting the source and destination nodes.
+//               It then calls the generate_path().
+////////////////////////////////////////////////////////////////////
+void PathFinder::find_path(AINode *src_node, AINode *dest_node) {
+  _src_node = src_node;
+  _dest_node = dest_node;
+
+  // Add a dummy node as the first element of the open list with score
+  // = -1.
+  // Inorder to implement a binary heap the index of the elements
+  // should never be 0.
+  AINode *_dummy_node = new AINode(-1, -1, LVecBase3f(0.0, 0.0, 0.0), 0, 0, 0);
+  _dummy_node->_status = _dummy_node->ST_open;
+  _dummy_node->_score = -1;
+  _open_list.push_back(_dummy_node);
+
+  // Add the source node to the open list.
+  add_to_olist(_src_node);
+
+  // Generate the path.
+  generate_path();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: generate_path
+//  Description: This function performs the pathfinding process
+//               using the A* algorithm.
+//               It updates the openlist and closelist.
+////////////////////////////////////////////////////////////////////
+void PathFinder::generate_path() {
+  // All the A* algorithm is implemented here.
+  // The check is > 1 due to the existence of the dummy node.
+  while (_open_list.size() > 1) {
+    // The first element of the open list will always be the optimal 
+    // node.
+    // This is because the open list is a binary heap with element 
+    // having the smallest score at the top of the heap.
+    AINode* nxt_node = _open_list[1];
+
+    if (nxt_node->_grid_x == _dest_node->_grid_x &&
+              nxt_node->_grid_y == _dest_node->_grid_y) {
+      // Remove the optimal node from the top of the heap.
+      remove_from_olist();
+
+      // add the used node to the closed list.
+      add_to_clist(nxt_node);
+
+      // At this point the destination is reached.
+      return;
+    }
+    else {
+      identify_neighbors(nxt_node);
+
+      // add the used node to the closed list.
+      add_to_clist(nxt_node);
+    }
+  }
+  cout << "DESTINATION NOT REACHABLE MATE!\n";
+  _closed_list.clear();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: identify_neighbors
+//  Description: This function traverses through the 8 neigbors of
+//               the parent node and then adds the neighbors to the
+//               _open_list based on A* criteria.
+////////////////////////////////////////////////////////////////////
+void PathFinder::identify_neighbors(AINode *parent_node) {
+  // Remove the parent node from the open_list so that it is not considered
+  // while adding new nodes to the open list heap.
+  remove_from_olist();
+  for (int i = 0; i < 8; ++i) {
+    if (parent_node->_neighbours[i] != NULL) {
+      if (parent_node->_neighbours[i]->_status == parent_node->_neighbours[i]->ST_neutral
+        && parent_node->_neighbours[i]->_type == true) {
+        // Link the neighbor to the parent node.
+        parent_node->_neighbours[i]->_prv_node = parent_node;
+        // Calculate and update the score for the node.
+        calc_node_score(parent_node->_neighbours[i]);
+        // Add the neighbor to the open list.
+        add_to_olist(parent_node->_neighbours[i]);
+      }
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: calc_node_score
+//  Description: This function calculates the score of each node.
+//               Score = Cost + Heuristics.
+////////////////////////////////////////////////////////////////////
+void PathFinder::calc_node_score(AINode *nd) {
+  nd->_cost = calc_cost_frm_src(nd);
+  nd->_heuristic = calc_heuristic(nd);
+  nd->_score = nd->_cost + nd->_heuristic;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: calc_cost_frm_src
+//  Description: This function calculates the cost of each node by
+//               finding out the number of node traversals required
+//               to reach the source node.
+//               Diagonal traversals have have cost = 14. 
+//               Horizontal / Vertical traversals have cost = 10.
+////////////////////////////////////////////////////////////////////
+int PathFinder::calc_cost_frm_src(AINode *nd) {
+  int cost = 0;
+  AINode *start_node = nd;
+  while (start_node->_prv_node != _src_node) {
+    if (is_diagonal_node(start_node)) {
+      cost += 14;
+    }
+    else {
+      cost += 10;
+    }
+    start_node = start_node->_prv_node;
+  }
+  // Add the cost of traversal to the source node also.
+  if (is_diagonal_node(start_node)) {
+    cost += 14;
+  }
+  else {
+    cost += 10;
+  }
+  return cost;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: calc_heuristic
+//  Description: This function calculates the heuristic of the nodes
+//               using Manhattan method. All it does is predict the
+//               number of node traversals required to reach the
+//               target node. No diagonal traversals are allowed
+//               in this technique.
+////////////////////////////////////////////////////////////////////
+int PathFinder::calc_heuristic(AINode *nd) {
+  int row_diff = abs(_dest_node->_grid_x - nd->_grid_x);
+  int col_diff = abs(_dest_node->_grid_y - nd->_grid_y);
+
+  int heuristic = 10 * (row_diff + col_diff);
+  return heuristic;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: is_diagonal_node
+//  Description: This function checks if the traversal from a
+//               node is diagonal.
+////////////////////////////////////////////////////////////////////
+bool PathFinder::is_diagonal_node(AINode *nd) {
+  // Calculate the row and column differences between child and parent
+  // nodes.
+  float row_diff = nd->_grid_x - nd->_prv_node->_grid_x;
+  float col_diff = nd->_grid_y - nd->_prv_node->_grid_y;
+
+  // Check if the relationship between child and parent node is 
+  // diagonal.
+  if (row_diff == 0 || col_diff == 0) {
+    return false;
+  }
+  else {
+    return true;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: add_to_olist
+//  Description: This function adds a node to the open list heap.
+//               A binay heap is maintained to improve the search.
+////////////////////////////////////////////////////////////////////
+void PathFinder::add_to_olist(AINode *nd) {
+  // Variables required to search the binary heap.
+  AINode *child_node, *parent_node;
+  int child_idx, parent_idx;
+
+  // Set the status as open.
+  nd->_status = nd->ST_open;
+  // Add the node to the open list.
+  _open_list.push_back(nd);
+
+  // Find the parent and child nodes and create temporary nodes out
+  // of them. In a binary heap the children of a parent node are 
+  // always i*2 and i*2 + 1, where i is the index of the parent node
+  // in the heap. And hence, the parent of a node can be easily found
+  // out by dividing by 2 and rounding it.
+  child_idx = _open_list.size() - 1;
+  parent_idx = child_idx / 2;
+  child_node = _open_list[child_idx];
+  parent_node = _open_list[parent_idx];
+
+  // Keep traversing the heap until the lowest element in the list is
+  // bubbled
+  // to the top of the heap.
+  while (_open_list[child_idx]->_score <= _open_list[parent_idx]->_score) {
+    // Swap the parent node and the child node.
+    _open_list[parent_idx] = child_node;
+    _open_list[child_idx] = parent_node;
+
+    // Update the new child and parent indices.
+    child_idx = parent_idx;
+    parent_idx = child_idx / 2;
+
+    // Update the new child and parent nodes.
+    child_node = _open_list[child_idx];
+    parent_node = _open_list[parent_idx];
+  }
+
+  // At this point the AINode with the smallest score will be at the
+  // top of the heap.
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: remove_from_olist
+//  Description: This function removes a node from the open list.
+//               During the removal the binary heap is maintained.
+////////////////////////////////////////////////////////////////////
+void PathFinder::remove_from_olist() {
+  // Variables for maintaining the binary heap.
+  AINode *child_node, *child_node_1, *child_node_2;
+  int child_idx, child_idx_1, child_idx_2;
+
+  // Remove the AINode at index 1 from the open list binary heap.
+  // Note: AINode at index 0 of open list is a dummy node.
+  _open_list.erase(_open_list.begin() + 1);
+
+  if (_open_list.size() > 1) {
+    // Store the last element in the open list to a temp_node.
+    AINode *temp_node = _open_list[_open_list.size() - 1];
+
+    // Shift the elements of the open list to the right by 1 element
+    // circularly, excluding element at 0 index.
+    for (int i = _open_list.size() - 1; i > 1; --i) {
+      _open_list[i] = _open_list[i - 1];
+    }
+
+    // Assign the temp_node to 1st element in the open list.
+    _open_list[1] = temp_node;
+
+    // Set the iterator for traversing the node from index 1 in
+    // the heap.
+    unsigned int k = 1;
+
+    // This loop traverses down the open list till the node reaches
+    // the correct position in the binary heap.
+    while (true) {
+      if ((k * 2 + 1) < _open_list.size()) {
+        // Two children exists for the parent node.
+        child_idx_1 = k * 2;
+        child_idx_2 = k * 2 + 1;
+        child_node_1 = _open_list[child_idx_1];
+        child_node_2 = _open_list[child_idx_2];
+
+        if (_open_list[child_idx_1]->_score < _open_list[child_idx_2]->_score) {
+          if (_open_list[k]->_score > _open_list[child_idx_1]->_score) {
+            // Swap the parent node and the child node.
+            _open_list[child_idx_1] = _open_list[k];
+            _open_list[k] = child_node_1;
+
+            // Update the parent node index.
+            k = child_idx_1;
+          }
+          else {
+            break;
+          }
+        }
+        else {
+          if (_open_list[k]->_score > _open_list[child_idx_2]->_score) {
+            // Swap the parent node and the child node.
+            _open_list[child_idx_2] = _open_list[k];
+            _open_list[k] = child_node_2;
+
+            // Update the parent node index.
+            k = child_idx_2;
+          }
+          else {
+            break;
+          }
+        }
+      }
+      else if ((k * 2) < _open_list.size()) {
+        // Only one child exists for the parent node.
+        child_idx = k * 2;
+        child_node = _open_list[child_idx];
+
+        if (_open_list[k]->_score > _open_list[child_idx]->_score) {
+          // Swap the parent node and the child node.
+          _open_list[child_idx] = _open_list[k];
+          _open_list[k] = child_node;
+
+          // Update the parent node index.
+          k = child_idx;
+        }
+        else {
+          break;
+        }
+      }
+      else {
+        // No children exists.
+        break;
+      }
+    }
+  }
+
+  // At this point the AINode was succesfully removed and the binary
+  // heap re-arranged.
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: add_to_clist
+//  Description: This function adds a node to the closed list.
+////////////////////////////////////////////////////////////////////
+void PathFinder::add_to_clist(AINode *nd) {
+  // Set the status as closed.
+  nd->_status = nd->ST_close;
+  // Add the node to the close list.
+  _closed_list.push_back(nd);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: remove_from_clist
+//  Description: This function removes a node from the closed list.
+////////////////////////////////////////////////////////////////////
+void PathFinder::remove_from_clist(int r, int c) {
+  for (unsigned int i = 0; i < _closed_list.size(); ++i) {
+    if (_closed_list[i]->_grid_x == r && _closed_list[i]->_grid_y == c) {
+      _closed_list.erase(_closed_list.begin() + i);
+      break;
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: find_in_mesh
+//  Description: This function allows the user to pass a position
+//               and it returns the corresponding node on the
+//               navigation mesh. A very useful function as it allows
+//               for dynamic updation of the mesh based on position.
+////////////////////////////////////////////////////////////////////
+AINode* find_in_mesh(NavMesh nav_mesh, LVecBase3f pos, int grid_size) {
+  int size = grid_size;
+  float x = pos[0];
+  float y = pos[1];
+
+  for (int i = 0; i < size; ++i) {
+    for (int j = 0; j < size; ++j) {
+      if (nav_mesh[i][j] != NULL && nav_mesh[i][j]->contains(x, y)) {
+        return (nav_mesh[i][j]);
+      }
+    }
+  }
+  return NULL;
+}

+ 61 - 0
contrib/src/ai/aiPathFinder.h

@@ -0,0 +1,61 @@
+// Filename: aiPathfinder.h
+// Created by:  Deepak, John, Navin (08Sep09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised 
+// BSD license. You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef PATHFINDER_H
+#define PATHFINDER_H
+
+#include "aiNode.h"
+#include "cmath.h"
+#include "lineSegs.h"
+
+typedef vector<AINode *> NodeArray;
+typedef vector<NodeArray> NavMesh;
+
+AINode* find_in_mesh(NavMesh nav_mesh, LVecBase3f pos, int grid_size);
+
+////////////////////////////////////////////////////////////////////
+//       Class : PathFinder
+// Description : This class implements pathfinding using the A*
+//               algorithm. It also uses a Binary Heap search to
+//               search the open list. The heuristics are
+//               calculated using the manhattan method.
+////////////////////////////////////////////////////////////////////
+class PathFinder {
+public:
+  AINode *_src_node;
+  AINode *_dest_node;
+  vector<AINode*> _open_list;
+  vector<AINode*> _closed_list;
+
+  NavMesh _grid;
+
+  void identify_neighbors(AINode *nd);
+  int calc_cost_frm_src(AINode *nd);
+  int calc_heuristic(AINode *nd);
+  void calc_node_score(AINode *nd);
+  bool is_diagonal_node(AINode *nd);
+
+  void add_to_olist(AINode *nd);
+  void remove_from_olist();
+
+  void add_to_clist(AINode *nd);
+  void remove_from_clist(int r, int c);
+
+  void generate_path();
+  void find_path(AINode *src_node, AINode *dest_node);
+  PathFinder(NavMesh nav_mesh);
+  ~PathFinder();
+};
+
+#endif

+ 258 - 0
contrib/src/ai/aiWorld.cxx

@@ -0,0 +1,258 @@
+// Filename: aiWorld.cxx
+// Created by:  Deepak, John, Navin (08Sep09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised 
+// BSD license.  You should have received a copy of this license
+// along with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "aiWorld.h"
+
+AIWorld::AIWorld(NodePath render) {
+  _ai_char_pool = new AICharPool();
+  _render = render;
+}
+
+AIWorld::~AIWorld() {
+}
+
+void AIWorld::add_ai_char(AICharacter *ai_char) {
+  _ai_char_pool->append(ai_char);
+  ai_char->_window_render = _render;
+  ai_char->_world = this;
+}
+
+void AIWorld::remove_ai_char(string name) {
+  _ai_char_pool->del(name);
+  remove_ai_char_from_flock(name);
+}
+
+void AIWorld::remove_ai_char_from_flock(string name) {
+  AICharPool::node *ai_pool;
+  ai_pool = _ai_char_pool->_head;
+  while ((ai_pool) != NULL) {
+    for (unsigned int i = 0; i < _flock_pool.size(); ++i) {
+      if (ai_pool->_ai_char->_ai_char_flock_id == _flock_pool[i]->get_id()) {
+        for (unsigned int j = 0; j<_flock_pool[i]->_ai_char_list.size(); ++j) {
+          if (_flock_pool[i]->_ai_char_list[j]->_name == name) {
+            _flock_pool[i]->_ai_char_list.erase(_flock_pool[i]->_ai_char_list.begin() + j);
+            return;
+          }
+        }
+      }
+    }
+    ai_pool = ai_pool->_next;
+  }
+}
+
+void AIWorld::print_list() {
+  _ai_char_pool->print_list();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: update
+//  Description: The AIWorld update function calls the update 
+//               function of all the AI characters which have been
+//               added to the AIWorld.
+////////////////////////////////////////////////////////////////////
+void AIWorld::update() {
+  AICharPool::node *ai_pool;
+  ai_pool = _ai_char_pool->_head;
+
+  while ((ai_pool)!=NULL) {
+    ai_pool->_ai_char->update();
+    ai_pool = ai_pool->_next;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: add_flock
+//  Description: This function adds all the AI characters in the
+//               Flock object to the AICharPool. This function
+//               allows adding the AI characetrs as part of a flock.
+////////////////////////////////////////////////////////////////////
+void AIWorld::add_flock(Flock *flock) {
+  // Add all the ai_characters in the flock to the AIWorld.
+  for (unsigned int i = 0; i < flock->_ai_char_list.size(); ++i) {
+    this->add_ai_char(flock->_ai_char_list[i]);
+  }
+  // Add the flock to the flock pool.
+  _flock_pool.push_back(flock);
+}
+
+////////////////////////////////////////////////////////////////////
+//
+//     Function: get_flock
+//  Description: This function returns a handle to the Flock whose
+//               id is passed.
+////////////////////////////////////////////////////////////////////
+
+Flock AIWorld::get_flock(unsigned int flock_id) {
+  for (unsigned int i=0; i < _flock_pool.size(); ++i) {
+    if (_flock_pool[i]->get_id() == flock_id) {
+      return *_flock_pool[i];
+    }
+  }
+  Flock *null_flock = NULL;
+  return *null_flock;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: remove_flock
+//  Description: This function removes the flock behavior completely.
+////////////////////////////////////////////////////////////////////
+void AIWorld::remove_flock(unsigned int flock_id) {
+  for (unsigned int i = 0; i < _flock_pool.size(); ++i) {
+    if (_flock_pool[i]->get_id() == flock_id) {
+      for (unsigned int j = 0; j < _flock_pool[i]->_ai_char_list.size(); ++j) {
+        _flock_pool[i]->_ai_char_list[j]->get_ai_behaviors()->turn_off("flock_activate");
+        _flock_pool[i]->_ai_char_list[j]->get_ai_behaviors()->turn_off("flock");
+        _flock_pool[i]->_ai_char_list[j]->get_ai_behaviors()->_flock_group = NULL;
+      }
+      _flock_pool.erase(_flock_pool.begin() + i);
+      break;
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: flock_off
+//  Description: This function turns off the flock behavior
+//               temporarily. Similar to pausing the behavior.
+////////////////////////////////////////////////////////////////////
+void AIWorld::flock_off(unsigned int flock_id) {
+  for (unsigned int i = 0; i < _flock_pool.size(); ++i) {
+    if (_flock_pool[i]->get_id() == flock_id) {
+      for (unsigned int j = 0; j < _flock_pool[i]->_ai_char_list.size(); ++j) {
+         _flock_pool[i]->_ai_char_list[j]->get_ai_behaviors()->turn_off("flock_activate");
+         _flock_pool[i]->_ai_char_list[j]->get_ai_behaviors()->turn_off("flock");
+      }
+      break;
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: flock_on
+//  Description: This function turns on the flock behavior.
+////////////////////////////////////////////////////////////////////
+void AIWorld::flock_on(unsigned int flock_id) {
+  for (unsigned int i = 0; i < _flock_pool.size(); ++i) {
+    if (_flock_pool[i]->get_id() == flock_id) {
+      for (unsigned int j = 0; j < _flock_pool[i]->_ai_char_list.size(); ++j) {
+        _flock_pool[i]->_ai_char_list[j]->get_ai_behaviors()->turn_on("flock_activate");
+      }
+      break;
+    }
+  }
+}
+
+AICharPool::AICharPool() {
+  _head = NULL;
+}
+
+AICharPool::~AICharPool() {
+}
+
+void AICharPool::append(AICharacter *ai_ch) {
+  node *q;
+  node *t;
+
+  if (_head == NULL) {
+    q = new node();
+    q->_ai_char = ai_ch;
+    q->_next = NULL;
+    _head = q;
+  }
+  else {
+    q = _head;
+    while ( q->_next != NULL) {
+      q = q->_next;
+    }
+
+    t = new node();
+    t->_ai_char = ai_ch;
+    t->_next = NULL;
+    q->_next = t;
+  }
+}
+
+void AICharPool::del(string name) {
+  node *q;
+  node *r;
+  q = _head;
+
+  if (_head == NULL) {
+    return;
+  }
+
+  // Only one node in the linked list
+  if (q->_next == NULL) {
+    if (q->_ai_char->_name == name) {
+      _head = NULL;
+      delete q;
+    }
+    return;
+  }
+
+  r = q;
+  while ( q != NULL) {
+    if ( q->_ai_char->_name == name) {
+      // Special case
+      if (q == _head) {
+        _head = q->_next;
+        delete q;
+        return;
+      }
+
+      r->_next = q->_next;
+      delete q;
+      return;
+    }
+    r = q;
+    q = q->_next;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: print_list
+//  Description: This function prints the ai characters in the
+//               AICharPool. Used for debugging purposes.
+////////////////////////////////////////////////////////////////////
+void AICharPool::print_list() {
+  node* q;
+  q = _head;
+  while (q != NULL) {
+    cout << q->_ai_char->_name << "\n";
+    q = q->_next;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: add_obstacle
+//  Description: This function adds the nodepath as an obstacle that
+//               is needed by the obstacle avoidance behavior.
+////////////////////////////////////////////////////////////////////
+void AIWorld::add_obstacle(NodePath obstacle) {
+  _obstacles.push_back(obstacle);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: remove_obstacle
+//  Description: This function removes the nodepath from the
+//               obstacles list that is needed by the obstacle
+//               avoidance behavior.
+////////////////////////////////////////////////////////////////////
+void AIWorld::remove_obstacle(NodePath obstacle) {
+  for (unsigned int i = 0; i <= _obstacles.size(); ++i) {
+    if (_obstacles[i] == obstacle) {
+      _obstacles.erase(_obstacles.begin() + i);
+    }
+  }
+}

+ 87 - 0
contrib/src/ai/aiWorld.h

@@ -0,0 +1,87 @@
+// Filename: aiWorld.h
+// Created by:  Deepak, John, Navin (08Sep09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised 
+// BSD license. You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef AIWORLD_H
+#define AIWORLD_H
+
+#include "aiGlobals.h"
+#include "aiCharacter.h"
+#include "flock.h"
+
+class AICharacter;
+class Flock;
+
+////////////////////////////////////////////////////////////////////
+//       Class : AICharPool
+// Description : This class implements a linked list of AI
+//               Characters allowing the user to add and delete 
+//               characters from the linked list.
+//               This will be used in the AIWorld class.
+////////////////////////////////////////////////////////////////////
+class AICharPool {
+public:
+  struct node {
+    AICharacter * _ai_char;
+    node * _next;
+  };
+
+  node* _head;
+  AICharPool();
+  ~AICharPool();
+  void append(AICharacter *ai_ch);
+  void del(string name);
+  void print_list();
+};
+
+////////////////////////////////////////////////////////////////////
+//       Class : AIWorld
+// Description : A class that implements the virtual AI world which
+//               keeps track of the AI characters active at any
+//               given time. It contains a linked list of AI
+//               characters, obstactle data and unique name for each
+//               character. It also updates each characters state.
+//               The AI characters can also be added to the world
+//               as flocks.
+////////////////////////////////////////////////////////////////////
+class AIWorld {
+private:
+    AICharPool * _ai_char_pool;
+    NodePath _render;
+public:
+  vector<NodePath> _obstacles;
+  typedef std::vector<Flock*> FlockPool;
+  FlockPool _flock_pool;
+  void remove_ai_char_from_flock(string name);
+
+PUBLISHED:
+  AIWorld(NodePath render);
+  ~AIWorld();
+
+  void add_ai_char(AICharacter *ai_ch);
+  void remove_ai_char(string name);
+
+  void add_flock(Flock *flock);
+  void flock_off(unsigned int flock_id);
+  void flock_on(unsigned int flock_id);
+  void remove_flock(unsigned int flock_id);
+  Flock get_flock(unsigned int flock_id);
+
+  void add_obstacle(NodePath obstacle);
+  void remove_obstacle(NodePath obstacle);
+
+  void print_list();
+  void update();
+};
+
+#endif

+ 1 - 0
contrib/src/ai/ai_composite.cxx

@@ -0,0 +1 @@
+#include "ai_composite1.cxx"

+ 20 - 0
contrib/src/ai/ai_composite1.cxx

@@ -0,0 +1,20 @@
+#include "config_ai.cxx"
+#include "aiWorld.cxx"
+#include "aiCharacter.cxx"
+#include "aiBehaviors.cxx"
+#include "seek.cxx"
+#include "flee.cxx"
+#include "pursue.cxx"
+#include "evade.cxx"
+#include "arrival.cxx"
+#include "flock.cxx"
+#include "wander.cxx"
+
+#include "pathFollow.cxx"
+#include "obstacleAvoidance.cxx"
+
+#include "pathFind.cxx"
+
+#include "aiNode.cxx"
+
+#include "aiPathFinder.cxx"

+ 120 - 0
contrib/src/ai/arrival.cxx

@@ -0,0 +1,120 @@
+// Filename: arrival.cxx
+// Created by:  Deepak, John, Navin (24Oct09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised 
+// BSD license.  You should have received a copy of this license
+// along with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "arrival.h"
+
+Arrival::Arrival(AICharacter *ai_ch, double distance) {
+  _ai_char = ai_ch;
+
+  _arrival_distance = distance;
+  _arrival_done = false;
+}
+
+Arrival::~Arrival() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: do_arrival
+//  Description: This function performs the arrival and returns an
+//               arrival force which is used in the
+//               calculate_prioritized function. In case the steering
+//               force is zero, it resets to arrival_activate. The
+//               arrival behavior works only when seek or pursue is
+//               active. This function is not to be used by the user.
+////////////////////////////////////////////////////////////////////
+LVecBase3f Arrival::do_arrival() {
+  LVecBase3f direction_to_target;
+  double distance;
+
+  if (_arrival_type) {
+    direction_to_target = _ai_char->get_ai_behaviors()->_pursue_obj->_pursue_target.get_pos(_ai_char->_window_render) 
+                                                            - _ai_char->_ai_char_np.get_pos(_ai_char->_window_render);
+  }
+  else {
+    direction_to_target = _ai_char->get_ai_behaviors()->_seek_obj->_seek_position
+                                                  - _ai_char->_ai_char_np.get_pos(_ai_char->_window_render);
+  }
+  distance = direction_to_target.length();
+
+  _arrival_direction = direction_to_target;
+  _arrival_direction.normalize();
+
+  if (int(distance) == 0) {
+    _ai_char->_steering->_steering_force = LVecBase3f(0.0, 0.0, 0.0);
+    _ai_char->_steering->_arrival_force = LVecBase3f(0.0, 0.0, 0.0);
+
+    if (_ai_char->_steering->_seek_obj != NULL) {
+      _ai_char->_steering->turn_off("arrival");
+      _ai_char->_steering->turn_on("arrival_activate");
+    }
+    _arrival_done = true;
+    return (LVecBase3f(0.0, 0.0, 0.0));
+  }
+  else {
+    _arrival_done = false;
+  }
+
+  double u = _ai_char->get_velocity().length();
+  LVecBase3f desired_force = ((u * u) / (2 * distance)) * _ai_char->get_mass();
+
+  if (_ai_char->_steering->_seek_obj != NULL) {
+    return (desired_force);
+  }
+
+  if (_ai_char->_steering->_pursue_obj != NULL) {
+
+    if (distance > _arrival_distance) {
+      _ai_char->_steering->turn_off("arrival");
+      _ai_char->_steering->turn_on("arrival_activate");
+      _ai_char->_steering->resume_ai("pursue");
+    }
+
+    return (desired_force);
+  }
+
+  cout << "Arrival works only with seek and pursue\n";
+  return (LVecBase3f(0.0, 0.0, 0.0));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: arrival_activate
+//  Description: This function checks for whether the target is
+//               within the arrival distance. When this is true,
+//               it calls the do_arrival function and sets the
+//               arrival direction.
+//               This function is not to be used by the user.
+////////////////////////////////////////////////////////////////////
+void Arrival::arrival_activate() {
+  LVecBase3f dirn;
+  if (_arrival_type) {
+    dirn = (_ai_char->_ai_char_np.get_pos(_ai_char->_window_render) - _ai_char->get_ai_behaviors()->_pursue_obj->_pursue_target.get_pos(_ai_char->_window_render));
+  }
+  else {
+    dirn = (_ai_char->_ai_char_np.get_pos(_ai_char->_window_render) - _ai_char->get_ai_behaviors()->_seek_obj->_seek_position);
+  }
+  double distance = dirn.length();
+
+  if (distance < _arrival_distance && _ai_char->_steering->_steering_force.length() > 0) {
+    _ai_char->_steering->turn_off("arrival_activate");
+    _ai_char->_steering->turn_on("arrival");
+
+    if (_ai_char->_steering->is_on(_ai_char->_steering->BT_seek)) {
+      _ai_char->_steering->turn_off("seek");
+    }
+
+    if (_ai_char->_steering->is_on(_ai_char->_steering->BT_pursue)) {
+      _ai_char->_steering->pause_ai("pursue");
+    }
+  }
+}

+ 49 - 0
contrib/src/ai/arrival.h

@@ -0,0 +1,49 @@
+// Filename: arrival.h
+// Created by:  Deepak, John, Navin (24Oct09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised 
+// BSD license.  You should have received a copy of this license
+// along with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+#ifndef ARRIVAL_H
+#define ARRIVAL_H
+
+#include "aiGlobals.h"
+#include "aiCharacter.h"
+
+class AICharacter;
+
+////////////////////////////////////////////////////////////////////
+//       Class : Arrival
+// Description : This class handles all calls to the arrival behavior
+////////////////////////////////////////////////////////////////////
+class Arrival {
+
+public:
+  AICharacter *_ai_char;
+
+  NodePath _arrival_target;
+  LVecBase3f _arrival_target_pos;
+  double _arrival_distance;
+  LVecBase3f _arrival_direction;
+  bool _arrival_done;
+
+  // This flag specifies if the arrival behavior is being used with
+  // seek or pursue behavior.
+  // True = used with pursue.
+  // False = used with seek.
+  bool _arrival_type;
+
+  Arrival(AICharacter *ai_ch, double distance = 10.0);
+  ~Arrival();
+  LVecBase3f do_arrival();
+  void arrival_activate();
+};
+
+#endif

+ 55 - 0
contrib/src/ai/config_ai.cxx

@@ -0,0 +1,55 @@
+// Filename: config_ai.cxx
+// Created by:  Pandai (13Sep09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "config_ai.h"
+#include "aiWorld.h"
+#include "aiCharacter.h"
+#include "aiBehaviors.h"
+#include "seek.h"
+#include "flee.h"
+#include "pursue.h"
+#include "evade.h"
+#include "arrival.h"
+#include "flock.h"
+#include "wander.h"
+#include "pathFollow.h"
+#include "obstacleAvoidance.h"
+#include "pathFind.h"
+#include "aiNode.h"
+#include "aiPathFinder.h"
+#include "dconfig.h"
+
+Configure(config_ai);
+NotifyCategoryDef(ai, "");
+
+ConfigureFn(config_ai) {
+  init_libai();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: init_libai
+//  Description: Initializes the library.  This must be called at
+//               least once before any of the functions or classes in
+//               this library can be used.  Normally it will be
+//               called by the static initializers and need not be
+//               called explicitly, but special cases exist.
+////////////////////////////////////////////////////////////////////
+void
+init_libai() {
+  static bool initialized = false;
+  if (initialized) {
+    return;
+  }
+  initialized = true;
+}

+ 26 - 0
contrib/src/ai/config_ai.h

@@ -0,0 +1,26 @@
+// Filename: config_ai.h
+// Created by:  Pandai (13Sep09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef CONFIG_AI_H
+#define CONFIG_AI_H
+
+#include "contribbase.h"
+#include "notifyCategoryProxy.h"
+
+NotifyCategoryDecl(ai, EXPCL_PANDAAI, EXPTP_PANDAAI);
+
+extern EXPCL_PANDAAI void init_libai();
+
+#endif
+

+ 86 - 0
contrib/src/ai/evade.cxx

@@ -0,0 +1,86 @@
+// Filename: evade.cxx
+// Created by:  Deepak, John, Navin (24Oct09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised 
+// BSD license.  You should have received a copy of this license
+// along with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "evade.h"
+
+Evade::
+Evade(AICharacter *ai_ch, NodePath target_object,
+      double panic_distance, double relax_distance, float evade_wt) {
+  _ai_char = ai_ch;
+
+  _evade_target = target_object;
+  _evade_distance = panic_distance;
+  _evade_relax_distance = relax_distance;
+  _evade_weight = evade_wt;
+
+  _evade_done = true;
+  _evade_activate_done = false;
+}
+
+Evade::~Evade() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: do_evade
+//  Description: This function performs the evade and returns an
+//               evade force which is used in the
+//               calculate_prioritized function. In case the
+//               AICharacter is past the (panic + relax) distance,
+//               it resets to evade_activate. This function is not
+//               to be used by the user.
+////////////////////////////////////////////////////////////////////
+LVecBase3f Evade::do_evade() {
+  assert(_evade_target && "evade target not assigned");
+
+  _evade_direction = _ai_char->_ai_char_np.get_pos(_ai_char->_window_render)
+                            - _evade_target.get_pos(_ai_char->_window_render);
+  double distance = _evade_direction.length();
+
+  _evade_direction.normalize();
+  LVecBase3f desired_force = _evade_direction * _ai_char->_movt_force;
+
+  if (distance > (_evade_distance + _evade_relax_distance)) {
+    if ((_ai_char->_steering->_behaviors_flags |
+           _ai_char->_steering->BT_evade) == _ai_char->_steering->BT_evade) {
+      _ai_char->_steering->_steering_force = LVecBase3f(0.0, 0.0, 0.0);
+    }
+    _ai_char->_steering->turn_off("evade");
+    _ai_char->_steering->turn_on("evade_activate");
+    _evade_done = true;
+    return (LVecBase3f(0.0, 0.0, 0.0));
+  } else {
+    _evade_done = false;
+    return (desired_force);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: evade_activate
+//  Description: This function checks for whether the target is
+//               within the panic distance.
+//               When this is true, it calls the do_evade function
+//               and sets the evade direction.
+//               This function is not to be used by the user.
+////////////////////////////////////////////////////////////////////
+void Evade::evade_activate() {
+  _evade_direction = (_ai_char->_ai_char_np.get_pos(_ai_char->_window_render) - _evade_target.get_pos(_ai_char->_window_render));
+  double distance = _evade_direction.length();
+  _evade_activate_done = false;
+
+  if (distance < _evade_distance) {
+    _ai_char->_steering->turn_off("evade_activate");
+    _ai_char->_steering->turn_on("evade");
+    _evade_activate_done = true;
+  }
+}

+ 48 - 0
contrib/src/ai/evade.h

@@ -0,0 +1,48 @@
+// Filename: evade.h
+// Created by:  Deepak, John, Navin (24Oct09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised 
+// BSD license.  You should have received a copy of this license
+// along with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef EVADE_H
+#define EVADE_H
+
+#include "aiGlobals.h"
+#include "aiCharacter.h"
+
+class AICharacter;
+
+////////////////////////////////////////////////////////////////////
+//       Class : Evade
+// Description : This class handles all calls to the evade behavior
+////////////////////////////////////////////////////////////////////
+class Evade {
+
+public:
+  AICharacter *_ai_char;
+
+  NodePath _evade_target;
+  float _evade_weight;
+  LVecBase3f _evade_direction;
+  double _evade_distance;
+  double _evade_relax_distance;
+  bool _evade_done;
+  bool _evade_activate_done;
+
+  Evade(AICharacter *ai_ch, NodePath target_object, double panic_distance,
+                                          double relax_distance, float evade_wt);
+
+  ~Evade();
+  LVecBase3f do_evade();
+  void evade_activate();
+};
+
+#endif

+ 104 - 0
contrib/src/ai/flee.cxx

@@ -0,0 +1,104 @@
+// Filename: flee.cxx
+// Created by:  Deepak, John, Navin (24Oct09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised 
+// BSD license.  You should have received a copy of this license
+// along with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "flee.h"
+
+Flee::Flee(AICharacter *ai_ch, NodePath target_object, double panic_distance,
+                                      double relax_distance, float flee_wt){
+
+  _ai_char = ai_ch;
+
+  _flee_position = target_object.get_pos(_ai_char->_window_render);
+  _flee_distance = panic_distance;
+  _flee_weight = flee_wt;
+  _flee_relax_distance = relax_distance;
+
+  _flee_done = false;
+  _flee_activate_done = false;
+}
+
+Flee::Flee(AICharacter *ai_ch, LVecBase3f pos, double panic_distance,
+                                double relax_distance, float flee_wt){
+
+  _ai_char = ai_ch;
+
+  _flee_position = pos;
+  _flee_distance = panic_distance;
+  _flee_weight = flee_wt;
+  _flee_relax_distance = relax_distance;
+
+  _flee_done = false;
+  _flee_activate_done = false;
+}
+
+Flee::~Flee() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: do_flee
+//  Description: This function performs the flee and returns a flee
+//               force which is used in the calculate_prioritized
+//               function. In case the AICharacter is past the
+//               (panic + relax) distance, it resets to flee_activate.
+//               This function is not to be used by the user.
+////////////////////////////////////////////////////////////////////
+LVecBase3f Flee::do_flee() {
+  LVecBase3f dirn;
+  double distance;
+  LVecBase3f desired_force;
+
+  dirn = _ai_char->_ai_char_np.get_pos(_ai_char->_window_render) - _flee_present_pos;
+  distance = dirn.length();
+  desired_force = _flee_direction * _ai_char->_movt_force;
+
+  if (distance > (_flee_distance + _flee_relax_distance)) {
+    if ((_ai_char->_steering->_behaviors_flags | _ai_char->_steering->BT_flee) == _ai_char->_steering->BT_flee) {
+      _ai_char->_steering->_steering_force = LVecBase3f(0.0, 0.0, 0.0);
+    }
+    _flee_done = true;
+    _ai_char->_steering->turn_off("flee");
+    _ai_char->_steering->turn_on("flee_activate");
+    return (LVecBase3f(0.0, 0.0, 0.0));
+  }
+  else {
+    return (desired_force);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: flee_activate
+//  Description: This function checks for whether the target is
+//               within the panic distance. When this is true,
+//               it calls the do_flee function and sets the flee
+//               direction.
+//               This function is not to be used by the user.
+////////////////////////////////////////////////////////////////////
+void Flee::flee_activate() {
+  LVecBase3f dirn;
+  double distance;
+
+  _flee_activate_done = false;
+
+  dirn = (_ai_char->_ai_char_np.get_pos(_ai_char->_window_render) - _flee_position);
+  distance = dirn.length();
+
+  if (distance < _flee_distance) {
+    _flee_direction = _ai_char->_ai_char_np.get_pos(_ai_char->_window_render) - _flee_position;
+    _flee_direction.normalize();
+    _flee_present_pos = _ai_char->_ai_char_np.get_pos(_ai_char->_window_render);
+    _ai_char->_steering->turn_off("flee_activate");
+    _ai_char->_steering->turn_on("flee");
+    _flee_activate_done = true;
+  }
+}

+ 52 - 0
contrib/src/ai/flee.h

@@ -0,0 +1,52 @@
+// Filename: flee.h
+// Created by:  Deepak, John, Navin (24Oct09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised 
+// BSD license.  You should have received a copy of this license
+// along with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef FLEE_H
+#define FLEE_H
+
+#include "aiGlobals.h"
+#include "aiCharacter.h"
+
+class AICharacter;
+
+////////////////////////////////////////////////////////////////////
+//       Class : Flee
+// Description : This class handles all calls to the flee behavior
+////////////////////////////////////////////////////////////////////
+class Flee {
+
+public:
+  AICharacter *_ai_char;
+
+  LVecBase3f _flee_position;
+  float _flee_weight;
+  LVecBase3f _flee_direction;
+  double _flee_distance;
+  double _flee_relax_distance;
+  LVecBase3f _flee_present_pos;
+  bool _flee_done;
+  bool _flee_activate_done;
+
+  Flee(AICharacter *ai_ch, NodePath target_object, double panic_distance = 10.0,
+                              double relax_distance = 10.0, float flee_wt = 1.0);
+
+  Flee(AICharacter *ai_ch, LVecBase3f pos, double panic_distance = 10.0,
+                              double relax_distance = 10.0, float flee_wt = 1.0);
+
+  ~Flee();
+  LVecBase3f do_flee();
+  void flee_activate();
+};
+
+#endif

+ 42 - 0
contrib/src/ai/flock.cxx

@@ -0,0 +1,42 @@
+// Filename: flock.cxx
+// Created by:  Deepak, John, Navin (12Oct09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "flock.h"
+
+Flock::Flock(unsigned int flock_id, double vcone_angle, double vcone_radius, unsigned int separation_wt,
+      unsigned int cohesion_wt, unsigned int alignment_wt) {
+        _flock_id = flock_id;
+        _flock_vcone_angle = vcone_angle;
+        _flock_vcone_radius = vcone_radius;
+        _separation_wt = separation_wt;
+        _cohesion_wt = cohesion_wt;
+        _alignment_wt = alignment_wt;
+}
+
+Flock::~Flock() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: add_ai_char
+//  Description: This function adds AI characters to the flock.
+////////////////////////////////////////////////////////////////////
+void Flock::add_ai_char(AICharacter *ai_char) {
+  ai_char->_ai_char_flock_id = _flock_id;
+  ai_char->_steering->_flock_group = this;
+  _ai_char_list.push_back(ai_char);
+}
+
+unsigned int Flock::get_id() {
+  return _flock_id;
+}

+ 62 - 0
contrib/src/ai/flock.h

@@ -0,0 +1,62 @@
+// Filename: flock.h
+// Created by:  Deepak, John, Navin (12Oct09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised 
+// BSD license.  You should have received a copy of this license
+// along with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef FLOCK_H
+#define FLOCK_H
+
+#include "aiGlobals.h"
+#include "aiCharacter.h"
+
+class AICharacter;
+
+////////////////////////////////////////////////////////////////////
+//       Class : Flock
+// Description : This class is used to define the flock attributes
+//               and the AI characters which are part of the flock.
+////////////////////////////////////////////////////////////////////
+class Flock {
+private:
+  unsigned int _flock_id;
+
+public:
+  // Variables which will hold the parameters of the ai character's
+  // visibility cone.
+  double _flock_vcone_angle;
+  double _flock_vcone_radius;
+
+  // Variables to specify weights of separation, cohesion and
+  // alignment behaviors and thus create variable flock behavior.
+  unsigned int _separation_wt;
+  unsigned int _cohesion_wt;
+  unsigned int _alignment_wt;
+
+  // This vector will hold all the ai characters which belong to 
+  // this flock.
+  typedef std::vector<AICharacter*> AICharList;
+  AICharList _ai_char_list;
+
+PUBLISHED:
+  Flock(unsigned int flock_id, double vcone_angle, double vcone_radius,
+        unsigned int separation_wt = 2, unsigned int cohesion_wt = 4,
+        unsigned int alignment_wt = 1);
+  ~Flock();
+
+  // Function to add the ai characters to _ai_char_list.
+  void add_ai_char(AICharacter *ai_char);
+
+  // Function to access the private member flock_id.
+  unsigned int get_id();
+};
+
+#endif

+ 33 - 0
contrib/src/ai/globals.h

@@ -0,0 +1,33 @@
+////////////////////////////////////////////////////////////////////////
+//! Filename :		globals.h 
+//! Created by :	Deepak, John, Navin
+//! Date:					8 Sep 09
+//!
+////////////////////////////////////////////////////////////////////////
+//!
+//! PANDA3D SOFTWARE
+//! Copyright(c) Carnegie Mellon University. All rights reserved.
+//!
+//!	All use of this software is subjest to the terms of the revised BSD
+//!	license. You should have received a copy of this license along with this source code in a file named "LICENSE"
+			
+////////////////////////////////////////////////////////////////////////
+
+#pragma warning (disable:4996)
+#pragma warning (disable:4005)
+#pragma warning(disable:4275)
+
+#ifndef _GLOBALS_H
+#define _GLOBALS_H
+
+#include "pandaFramework.h"
+#include "textNode.h"
+#include "pandaSystem.h"
+
+#include "lvecBase3.h"
+#include "nodePath.h"
+
+#include "genericAsyncTask.h"
+#include "asyncTaskManager.h"
+
+#endif

+ 43 - 0
contrib/src/ai/meshNode.cxx

@@ -0,0 +1,43 @@
+
+#include "meshNode.h"
+
+Node::Node(int grid_x, int grid_y, LVecBase3f pos, float w, float l, float h) {
+	for(int i = 0; i < 8; ++i) {
+		_neighbours[i] = NULL;
+	}
+
+	_position = pos;
+	_width = w;
+	_length = l;
+	_height = h;
+	_grid_x = grid_x;
+	_grid_y = grid_y;
+  _status = neutral;
+	_type = true;
+	_score = 0;
+	_cost = 0;
+	_heuristic = 0;
+  _next = NULL;
+	_prv_node =  NULL;
+}
+
+Node::~Node() {
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+//!
+//! Function : contains
+//! Description : This is a handy function which returns true if the passed position is
+//!               within the node's dimensions.
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+bool Node::contains(float x, float y) {
+  if(_position.get_x() - _width / 2 <= x && _position.get_x() + _width / 2 >= x &&
+    _position.get_y() - _length / 2 <= y && _position.get_y() + _length / 2 >= y) {
+		return true;
+  }
+  else {
+	  return false;
+  }
+}

+ 67 - 0
contrib/src/ai/meshNode.h

@@ -0,0 +1,67 @@
+
+#ifndef _MESHNODE_H
+#define _MESHNODE_H
+
+#include "globals.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//!
+//! Class : Node
+//!	Description : This class is used to assign the nodes on the mesh. It holds all the data necessary to
+//!               compute A* algorithm. It also maintains a lot of vital information such as the neighbor
+//!               nodes of each node and also its position on the mesh.
+//! Note: The Mesh Generator which is a stand alone tool makes use of this class to generate the nodes on the
+//!       mesh.
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+class Node {
+public:
+		// This variable specifies whether the node is an obtacle or not.
+		// Used for dynamic obstacle addition to the environment.
+		// obstacle = false
+		// navigational = true
+		bool _type;
+
+		// This variable specifies the node status whether open, close or neutral.
+		// open = belongs to _open_list.
+		// close = belongs to _closed_list.
+		// neutral = unexamined node.
+		enum Status {
+			open,
+			close,
+			neutral
+		};
+		Status _status; 
+
+		// The score is used to compute the traversal expense to nodes when using A*.
+		// _score = _cost + heuristic
+		int _score;
+		int _cost;
+		int _heuristic;
+
+		// Used to trace back the path after it is generated using A*.
+		Node *_prv_node;
+
+		// Position of the node in the 2d grid.
+		int _grid_x, _grid_y;
+
+		// Position of the node in 3D space.
+		LVecBase3f _position;
+
+		// Dimensions of each face / cell on the mesh.
+		// Height is given in case of expansion to a 3d mesh. Currently not used. 
+		float _width, _length ,_height;
+		Node *_neighbours[8]; // anti-clockwise from top left corner.
+
+    // The _next pointer is used for traversal during mesh generation from the model.
+		// Note: The data in this member is discarded when mesh data is written into navmesh.csv file.
+		Node *_next;
+
+		Node(int grid_x, int grid_y, LVecBase3f pos, float w, float l, float h);
+		~Node();
+
+		bool contains(float x, float y);
+};
+
+#endif

+ 119 - 0
contrib/src/ai/obstacleAvoidance.cxx

@@ -0,0 +1,119 @@
+// Filename: obstacleAvoidance.cxx
+// Created by:  Deepak, John, Navin (10Nov09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised 
+// BSD license.  You should have received a copy of this license
+// along with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "obstacleAvoidance.h"
+
+ObstacleAvoidance::ObstacleAvoidance(AICharacter *ai_char, float feeler_length) {
+  _ai_char = ai_char;
+  _feeler = feeler_length;
+}
+
+ObstacleAvoidance::~ObstacleAvoidance() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: obstacle_detection
+//  Description: This function checks if an obstacle is near to the
+//               AICharacter and if an obstacle is detected returns
+//               true.
+////////////////////////////////////////////////////////////////////
+bool ObstacleAvoidance::obstacle_detection() {
+  // Calculate the volume of the AICharacter with respect to render
+  PT(BoundingVolume) np_bounds = _ai_char->get_node_path().get_bounds();
+  CPT(BoundingSphere) np_sphere = np_bounds->as_bounding_sphere();
+  LVecBase3f avoidance(0.0, 0.0, 0.0);
+  double distance = 0x7fff ;
+  double expanded_radius;
+  LVecBase3f to_obstacle;
+  LVecBase3f prev_avoidance;
+  for (unsigned int i = 0; i < _ai_char->_world->_obstacles.size(); ++i) {
+    PT(BoundingVolume) bounds = _ai_char->_world->_obstacles[i].get_bounds();
+    CPT(BoundingSphere) bsphere = bounds->as_bounding_sphere();
+    LVecBase3f near_obstacle = _ai_char->_world->_obstacles[i].get_pos() 
+                                         - _ai_char->get_node_path().get_pos();
+    // Check if it's the nearest obstacle, If so initialize as the nearest
+    // obstacle
+    if ((near_obstacle.length() < distance) &&
+        (_ai_char->_world->_obstacles[i].get_pos() != _ai_char->get_node_path().get_pos())) {
+      _nearest_obstacle = _ai_char->_world->_obstacles[i];
+      distance = near_obstacle.length();
+      expanded_radius = bsphere->get_radius() + np_sphere->get_radius();
+    }
+  }
+     LVecBase3f feeler = _feeler * _ai_char->get_char_render().get_relative_vector(_ai_char->get_node_path(), LVector3f::forward());
+     feeler.normalize();
+     feeler *= (expanded_radius + np_sphere->get_radius()) ;
+     to_obstacle = _nearest_obstacle.get_pos() - _ai_char->get_node_path().get_pos();
+     LVector3f line_vector = _ai_char->get_char_render().get_relative_vector(_ai_char->get_node_path(), LVector3f::forward());
+     LVecBase3f project = (to_obstacle.dot(line_vector) * line_vector) / line_vector.length_squared();
+     LVecBase3f perp = project - to_obstacle;
+     // If the nearest obstacle will collide with our AICharacter then
+     // send obstacle detection as true
+     if ((_nearest_obstacle) && 
+         (perp.length() < expanded_radius - np_sphere->get_radius()) &&
+         (project.length() < feeler.length())) {
+       return true;
+     }
+     return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: obstacle_avoidance_activate
+//  Description: This function activates obstacle_avoidance if an
+//               obstacle is detected
+////////////////////////////////////////////////////////////////////
+void ObstacleAvoidance::obstacle_avoidance_activate() {
+  if (obstacle_detection()) {
+    _ai_char->_steering->turn_off("obstacle_avoidance_activate");
+    _ai_char->_steering->turn_on("obstacle_avoidance");
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: do_obstacle_avoidance
+//  Description: This function returns the force necessary by the
+//               AICharacter to avoid the nearest obstacle detected
+//               by obstacle_detection function
+//               NOTE : This assumes the obstacles are spherical
+////////////////////////////////////////////////////////////////////
+LVecBase3f ObstacleAvoidance::do_obstacle_avoidance() {
+  LVecBase3f offset = _ai_char->get_node_path().get_pos()
+                                     - _nearest_obstacle.get_pos();
+  PT(BoundingVolume) bounds =_nearest_obstacle.get_bounds();
+  CPT(BoundingSphere) bsphere = bounds->as_bounding_sphere();
+  PT(BoundingVolume) np_bounds = _ai_char->get_node_path().get_bounds();
+  CPT(BoundingSphere) np_sphere = np_bounds->as_bounding_sphere();
+  double distance_needed = offset.length() - bsphere->get_radius()
+                                            - np_sphere->get_radius();
+  
+  if (obstacle_detection()) {
+    LVecBase3f direction = _ai_char->get_char_render().get_relative_vector(
+                             _ai_char->get_node_path(), LVector3f::forward());
+    direction.normalize();
+    float forward_component = offset.dot(direction);
+    LVecBase3f projection = forward_component * direction;
+    LVecBase3f perpendicular_component = offset - projection;
+    double p = perpendicular_component.length();
+    perpendicular_component.normalize();
+    LVecBase3f avoidance = perpendicular_component;
+    
+    // The closer the obstacle, the more force it generates
+    avoidance = (avoidance * _ai_char->get_max_force() *
+                                 _ai_char->_movt_force) / (p + 0.01);
+    return avoidance;
+  }
+  _ai_char->_steering->turn_on("obstacle_avoidance_activate");
+  _ai_char->_steering->turn_off("obstacle_avoidance");
+  return LVecBase3f(0, 0, 0);
+}

+ 42 - 0
contrib/src/ai/obstacleAvoidance.h

@@ -0,0 +1,42 @@
+// Filename: obstacleAvoidance.h
+// Created by:  Deepak, John, Navin (10Nov2009)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised 
+// BSD license.  You should have received a copy of this license
+// along with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+#ifndef OBSTACLE_AVOIDANCE_H
+#define OBSTACLE_AVOIDANCE_H
+
+#include "aiCharacter.h"
+#include "boundingSphere.h"
+
+class AICharacter;
+
+////////////////////////////////////////////////////////////////////
+//       Class : ObstacleAvoidance
+// Description : This class handles all calls to the obstacle
+//               avoidance behavior
+////////////////////////////////////////////////////////////////////
+class ObstacleAvoidance {
+  public :
+    AICharacter *_ai_char;
+    float _obstacle_avoidance_weight;
+    NodePath _nearest_obstacle;
+    bool _obstacle_avoidance_done;
+    float _feeler;
+
+    ObstacleAvoidance(AICharacter *ai_char, float feeler_length);
+    LVecBase3f do_obstacle_avoidance();
+    ~ObstacleAvoidance();
+    void obstacle_avoidance_activate();
+    bool obstacle_detection();
+};
+
+#endif

+ 413 - 0
contrib/src/ai/pathFind.cxx

@@ -0,0 +1,413 @@
+
+// Filename: pathFind.cxx
+// Created by:  Deepak, John, Navin (12Oct09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised 
+// BSD license.  You should have received a copy of this license
+// along with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "pathFind.h"
+
+PathFind::PathFind(AICharacter *ai_ch) {
+  _ai_char = ai_ch;
+
+  _parent = new GeomNode("parent");
+  _ai_char->_window_render.attach_new_node(_parent);
+
+  _pen = new LineSegs("pen");
+  _pen->set_color(1.0, 0.0, 0.0);
+  _pen->set_thickness(2.0);
+
+  _path_finder_obj = NULL;
+  _dynamic_avoid = false;
+}
+
+PathFind::~PathFind() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: create_nav_mesh
+//  Description: This function recreates the navigation mesh from
+//               the .csv file.
+////////////////////////////////////////////////////////////////////
+void PathFind::create_nav_mesh(const char* navmesh_filename) {
+  // Stage variables.
+  int grid_x, grid_y;
+  float l, w, h;
+  LVecBase3f position;
+
+  // Variable to hold line data read from file.
+  string line;
+
+  // Array for storing data members obtained from each line of the
+  // file.
+  string fields[10];
+
+  // Open data file for reading.
+  ifstream nav_mesh_file (navmesh_filename);
+
+  if (nav_mesh_file.is_open()) {
+    // Capture the grid size from the file.
+    getline(nav_mesh_file, line);
+    int pos = line.find(",");
+    _grid_size = atoi((line.substr(pos + 1)).c_str());
+
+    // Initialize the stage mesh with NULL nodes.
+    for (int r = 0; r < _grid_size; ++r) {
+      _nav_mesh.push_back(vector<AINode*>());
+      for (int c = 0; c < _grid_size; ++c) {
+        _nav_mesh[r].push_back(NULL);
+      }
+    }
+
+    // Ignore the header of the navmesh.csv file.
+    getline(nav_mesh_file, line);
+
+    // Begin reading data from the file.
+    while (!nav_mesh_file.eof()) {
+      getline(nav_mesh_file, line);
+      stringstream linestream (line);
+
+      // Stores all the data members in the line to the array.
+      // Data structure: NULL,NodeType,GridX,GridY,Length,Width,
+      // Height,PosX,PosY,PosZ
+      for (int i = 0; i < 10; ++i) {
+        getline(linestream, fields[i], ',');
+      }
+
+      // Populate the main nodes into stage mesh.
+      if (fields[0] == "0" && fields[1] == "0") {
+        grid_x = atoi(fields[2].c_str());
+        grid_y = atoi(fields[3].c_str());
+        l = atof(fields[4].c_str());
+        w = atof(fields[5].c_str());
+        h = atof(fields[6].c_str());
+        position = LVecBase3f(atof(fields[7].c_str()), 
+                    atof(fields[8].c_str()), atof(fields[9].c_str()));
+
+        AINode *stage_node = new AINode(grid_x, grid_y, position, w, l, h);
+
+        _nav_mesh[grid_y][grid_x] = stage_node;
+      }
+      else if (fields[0] == "") {
+        // End of file reached at this point.
+        nav_mesh_file.close();
+
+        // Assign the neighbor nodes for each of the main nodes
+        // that just got populated into the stage mesh.
+        assign_neighbor_nodes(navmesh_filename);
+      }
+    }
+  }
+  else {
+    cout << "error opening navmesh.csv file!\n";
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: assign_neighbor_nodes
+//  Description: This function assigns the neighbor nodes for each
+//               main node present in _nav_mesh.
+////////////////////////////////////////////////////////////////////
+void PathFind::assign_neighbor_nodes(const char* navmesh_filename){
+  ifstream nav_mesh_file (navmesh_filename);
+
+  // Stage variables.
+  int gd_x, gd_y, gd_xn, gd_yn;
+  string ln;
+  string fields[10];
+  string fields_n[10];
+
+  if (nav_mesh_file.is_open()) {
+    getline(nav_mesh_file, ln); // Get rid of grid size line.
+    getline(nav_mesh_file, ln); // Get rid of the header.
+
+    while (!nav_mesh_file.eof()) {
+      getline(nav_mesh_file, ln); // Gets main node data only. No neighbor nodes.
+      stringstream linestream (ln);
+      for (int i = 0; i < 10; ++i) {
+        getline(linestream, fields[i], ',');
+      }
+      if (fields[0] == "0" && fields[1] == "0") {
+        // Usable main node.
+        gd_x = atoi(fields[2].c_str());
+        gd_y = atoi(fields[3].c_str());
+        for (int i = 0; i < 8; ++i) {
+          getline(nav_mesh_file, ln); // Gets neighbor node data only. No main nodes.
+          stringstream linestream_n (ln);
+          for (int j = 0; j < 10; ++j) {
+            getline(linestream_n, fields_n[j], ',');
+          }
+          gd_xn = atoi(fields_n[2].c_str());
+          gd_yn = atoi(fields_n[3].c_str());
+
+          if (fields_n[0] == "0" && fields_n[1] == "1") {
+            // Usable neighbor for main node.
+            // Note: The indices of the vector are inverted
+            // when compared to the values of the nodes on actual grid.
+            _nav_mesh[gd_y][gd_x]->_neighbours[i] = _nav_mesh[gd_yn][gd_xn];
+          }
+          else if (fields_n[0] == "1" && fields_n[1] == "1") {
+            // NULL neighbor.
+            _nav_mesh[gd_y][gd_x]->_neighbours[i] = NULL;
+          }
+          else {
+            cout << "Warning: Corrupt data!\n";
+          }
+        }
+      }
+      else if (fields[0] == "") {
+        // End of file reached at this point.
+        nav_mesh_file.close();
+      }
+    }
+  }
+  else {
+    cout << "error opening navmesh.csv file!\n";
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: set_path_find
+//  Description: This function starts the path finding process after
+//               reading the given navigation mesh.
+////////////////////////////////////////////////////////////////////
+void PathFind::set_path_find(const char* navmesh_filename) {
+  create_nav_mesh(navmesh_filename);
+
+  if (_ai_char->_steering->_path_follow_obj) {
+    _ai_char->_steering->remove_ai("pathfollow");
+  }
+
+  _ai_char->_steering->path_follow(1.0f);
+
+  if (_path_finder_obj) {
+    delete _path_finder_obj;
+    _path_finder_obj = NULL;
+  }
+
+  _path_finder_obj = new PathFinder(_nav_mesh);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: path_find (for pathfinding towards a static position)
+//  Description: This function checks for the source and target in
+//               the navigation mesh for its availability and then 
+//               finds the best path via the A* algorithm Then it
+//               calls the path follower to make the object follow
+//               the path.
+////////////////////////////////////////////////////////////////////
+void PathFind::path_find(LVecBase3f pos, string type) {
+  if (type == "addPath") {
+    if (_ai_char->_steering->_path_follow_obj) {
+      _ai_char->_steering->remove_ai("pathfollow");
+    }
+
+    _ai_char->_steering->path_follow(1.0f);
+  }
+
+  clear_path();
+
+  AINode* src = find_in_mesh(_nav_mesh,
+        _ai_char->_ai_char_np.get_pos(_ai_char->_window_render), _grid_size);
+
+  if (src == NULL) {
+    cout << "couldnt find source\n";
+  }
+
+  AINode* dst = find_in_mesh(_nav_mesh, pos, _grid_size);
+
+  if (dst == NULL) {
+    cout << "couldnt find destination\n";
+  }
+
+  if (src != NULL && dst != NULL) {
+    _path_finder_obj->find_path(src, dst);
+    trace_path(src);
+  }
+
+  if (!_ai_char->_steering->_path_follow_obj->_start) {
+    _ai_char->_steering->start_follow();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: path_find (for pathfinding towards a moving target
+//              (a NodePath))
+//  Description: This function checks for the source and target in
+//               the navigation mesh for its availability and then
+//               finds the best path via the A* algorithm
+//               Then it calls the path follower to make the object
+//               follow the path.
+////////////////////////////////////////////////////////////////////
+void PathFind::path_find(NodePath target, string type) {
+  if (type == "addPath") {
+    if (_ai_char->_steering->_path_follow_obj) {
+      _ai_char->_steering->remove_ai("pathfollow");
+    }
+
+    _ai_char->_steering->path_follow(1.0f);
+  }
+
+  clear_path();
+
+  _path_find_target = target;
+  _prev_position = target.get_pos(_ai_char->_window_render);
+
+  AINode* src = find_in_mesh(_nav_mesh,
+             _ai_char->_ai_char_np.get_pos(_ai_char->_window_render), _grid_size);
+
+  if (src == NULL) {
+    cout << "couldnt find source\n";
+  }
+
+  AINode* dst = find_in_mesh(_nav_mesh, _prev_position, _grid_size);
+
+  if (dst == NULL) {
+    cout << "couldnt find destination\n";
+  }
+
+  if (src != NULL && dst != NULL) {
+    _path_finder_obj->find_path(src, dst);
+    trace_path(src);
+  }
+
+  if (_ai_char->_steering->_path_follow_obj!=NULL) {
+    if (!_ai_char->_steering->_path_follow_obj->_start) {
+      _ai_char->_steering->start_follow("pathfind");
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: clear_path
+//  Description: Helper function to restore the path and mesh
+//               to its initial state
+////////////////////////////////////////////////////////////////////
+void PathFind::clear_path() {
+  // Initialize to zero
+  for (int i = 0; i < _grid_size; ++i) {
+    for (int j = 0; j < _grid_size; ++j) {
+      if (_nav_mesh[i][j] != NULL) {
+        _nav_mesh[i][j]->_status = _nav_mesh[i][j]->ST_neutral;
+        _nav_mesh[i][j]->_cost = 0;
+        _nav_mesh[i][j]->_heuristic = 0;
+        _nav_mesh[i][j]->_score = 0;
+        _nav_mesh[i][j]->_prv_node = NULL;
+      }
+    }
+  }
+
+  if (_path_finder_obj) {
+    _path_finder_obj->_open_list.clear();
+    _path_finder_obj->_closed_list.clear();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: trace_path
+//  Description: This function is the function which sends the path
+//               information one by one to the path follower so that
+//               it can store the path needed to be
+//               traversed by the pathfinding object
+////////////////////////////////////////////////////////////////////
+void PathFind::trace_path(AINode* src) {
+    if (_ai_char->_pf_guide) {
+      _parent->remove_all_children();
+    }
+    else {
+      _parent->remove_all_children();
+    }
+
+    if (_path_finder_obj->_closed_list.size() > 0) {
+      AINode *traversor = _path_finder_obj->_closed_list[_path_finder_obj->_closed_list.size() - 0.5];
+      while (traversor != src) {
+        if (_ai_char->_pf_guide) {
+          _pen->move_to(traversor->_position.get_x(), traversor->_position.get_y(), 1);
+          _pen->draw_to(traversor->_prv_node->_position.get_x(),
+                                         traversor->_prv_node->_position.get_y(), 0.5);
+          PT(GeomNode) gnode = _pen->create();
+          _parent->add_child(gnode);
+        }
+        _ai_char->_steering->add_to_path(traversor->_position);
+        traversor = traversor->_prv_node;
+      }
+    }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: add_obstacle_to_mesh
+//  Description: This function allows the user to dynamically add
+//               obstacles to the game environment. The function
+//               will update the nodes within the
+//               bounding volume of the obstacle as non-traversable.
+//               Hence will not be considered by the pathfinding
+//               algorithm.
+////////////////////////////////////////////////////////////////////
+void PathFind::add_obstacle_to_mesh(NodePath obstacle) {
+  PT(BoundingVolume) np_bounds = obstacle.get_bounds();
+  CPT(BoundingSphere) np_sphere = np_bounds->as_bounding_sphere();
+
+  AINode* temp = find_in_mesh(_nav_mesh, obstacle.get_pos(), _grid_size);
+
+  if (temp != NULL) {
+    float left = temp->_position.get_x() - np_sphere->get_radius();
+    float right = temp->_position.get_x() + np_sphere->get_radius();
+    float top = temp->_position.get_y() + np_sphere->get_radius();
+    float down = temp->_position.get_y() - np_sphere->get_radius();
+
+    for (int i = 0; i < _grid_size; ++i) {
+        for (int j = 0; j < _grid_size; ++j) {
+          if (_nav_mesh[i][j] != NULL && _nav_mesh[i][j]->_type == true) {
+            if (_nav_mesh[i][j]->_position.get_x() >= left && _nav_mesh[i][j]->_position.get_x() <= right &&
+              _nav_mesh[i][j]->_position.get_y() >= down && _nav_mesh[i][j]->_position.get_y() <= top) {
+              _nav_mesh[i][j]->_type = false;
+              _previous_obstacles.insert(_previous_obstacles.end(), i);
+              _previous_obstacles.insert(_previous_obstacles.end(), j);
+            }
+          }
+        }
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: do_dynamic_avoid()
+//  Description: This function does the updation of the collisions to
+//               the mesh based on the new positions of the obstacles.
+////////////////////////////////////////////////////////////////////
+void PathFind::do_dynamic_avoid() {
+  clear_previous_obstacles();
+  _previous_obstacles.clear();
+  for (unsigned int i = 0; i < _dynamic_obstacle.size(); ++i) {
+    add_obstacle_to_mesh(_dynamic_obstacle[i]);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: clear_previous_obstacles()
+//  Description: Helper function to reset the collisions if the
+//               obstacle is not on the node anymore.
+////////////////////////////////////////////////////////////////////
+void PathFind::clear_previous_obstacles(){
+  for (unsigned int i = 0; i < _previous_obstacles.size(); i = i + 2) {
+      _nav_mesh[_previous_obstacles[i]][_previous_obstacles[i + 1]]->_type = true;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: dynamic_avoid
+//  Description: This function starts the pathfinding obstacle
+//               navigation for the passed in obstacle.
+////////////////////////////////////////////////////////////////////
+void PathFind::dynamic_avoid(NodePath obstacle) {
+  _dynamic_avoid = true;
+  _dynamic_obstacle.insert(_dynamic_obstacle.end(), obstacle);
+}

+ 70 - 0
contrib/src/ai/pathFind.h

@@ -0,0 +1,70 @@
+// Filename: pathFind.h
+// Created by:  Deepak, John, Navin (12Oct09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised 
+// BSD license.  You should have received a copy of this license
+// along with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef PATHFIND_H
+#define PATHFIND_H
+
+#include "aiGlobals.h"
+#include "aiCharacter.h"
+#include "aiPathFinder.h"
+#include "boundingSphere.h"
+
+class AICharacter;
+
+////////////////////////////////////////////////////////////////////
+//       Class : PathFind
+// Description : This class contains all the members and functions
+//               that are required to form an interface between
+//               the AIBehaviors class and the PathFinder class.
+//               An object (pointer) of this class is provided in
+//               the AIBehaviors class. It is only via this object
+//               that the user can activate pathfinding.
+////////////////////////////////////////////////////////////////////
+class PathFind {
+public:
+  AICharacter *_ai_char;
+  PathFinder *_path_finder_obj;
+
+  NavMesh _nav_mesh;
+  NavMesh _stage_mesh;
+
+  int _grid_size;
+  NodePath _path_find_target;
+  LVecBase3f _prev_position;
+  PT(GeomNode) _parent;
+  LineSegs *_pen;
+  vector<int> _previous_obstacles;
+  bool _dynamic_avoid;
+  vector<NodePath> _dynamic_obstacle;
+
+  PathFind(AICharacter *ai_ch);
+  ~PathFind();
+
+  void clear_path();
+  void trace_path(AINode* src);
+
+  void create_nav_mesh(const char* navmesh_filename);
+  void assign_neighbor_nodes(const char* navmesh_filename);
+  void do_dynamic_avoid();
+  void clear_previous_obstacles();
+
+  void set_path_find(const char* navmesh_filename);
+  void path_find(LVecBase3f pos, string type = "normal");
+  void path_find(NodePath target, string type = "normal");
+  void add_obstacle_to_mesh(NodePath obstacle);
+  void dynamic_avoid(NodePath obstacle);
+};
+
+#endif
+

+ 138 - 0
contrib/src/ai/pathFollow.cxx

@@ -0,0 +1,138 @@
+// Filename: pathFollow.cxx
+// Created by:  Deepak, John, Navin (24Oct09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised 
+// BSD license.  You should have received a copy of this license
+// along with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "pathFollow.h"
+
+PathFollow::PathFollow(AICharacter *ai_ch, float follow_wt) {
+    _follow_weight = follow_wt;
+  _curr_path_waypoint = -1;
+  _start = false;
+  _ai_char = ai_ch;
+  _myClock = ClockObject::get_global_clock();
+}
+
+PathFollow::~PathFollow() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: add_to_path
+//  Description: This function adds the positions generated from a
+//               pathfind or a simple path follow behavior to the
+//               _path list.
+////////////////////////////////////////////////////////////////////
+void PathFollow::add_to_path(LVecBase3f pos) {
+    _path.push_back(pos);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: start
+//  Description: This function initiates the path follow behavior.
+////////////////////////////////////////////////////////////////////
+void PathFollow::start(string type) {
+    _type = type;
+  _start = true;
+  if (_path.size() > 0) {
+    _curr_path_waypoint = _path.size() - 1;
+    _dummy = _ai_char->_window_render.attach_new_node("dummy");
+    _dummy.set_pos(_path[_curr_path_waypoint]);
+    _ai_char->_steering->pursue(_dummy, _follow_weight);
+    _time = _myClock->get_real_time();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: do_follow
+//  Description: This function allows continuous path finding by AI
+//               chars. There are 2 ways in which this is implemented.
+//               1. The character re-calculates the optimal path
+//               everytime the target changes its position.
+//               Less computationally expensive.
+//               2. The character continuosly re-calculates its
+//               optimal path to the target. This is used in a
+//               scenario where the ai chars have to avoid other AI
+//               chars. More computationally expensive.
+////////////////////////////////////////////////////////////////////
+void PathFollow::do_follow() {
+  if ((_myClock->get_real_time() - _time) > 0.5) {
+    if (_type == "pathfind") {
+      // This 'if' statement when 'true' causes the path to be 
+      // re-calculated irrespective of target position.
+      // This is done when _dynamice_avoid is active. More 
+      // computationally expensive.
+      if (_ai_char->_steering->_path_find_obj->_dynamic_avoid) {
+        _ai_char->_steering->_path_find_obj->do_dynamic_avoid();
+        if (check_if_possible()) {
+          _path.clear();
+          _ai_char->_steering->_path_find_obj->path_find(_ai_char->_steering->_path_find_obj->_path_find_target);
+          // Ensure that the path size is not 0.
+          if (_path.size() > 0) {
+            _curr_path_waypoint = _path.size() - 1;
+            _dummy.set_pos(_path[_curr_path_waypoint]);
+          }
+          else {
+          // Refresh the _curr_path_waypoint value if path size is <= 0.
+          _curr_path_waypoint = -1;
+          }
+        }
+      }
+      // This 'if' statement causes the path to be re-calculated only
+      // when there is a change in target position.
+      // Less computationally expensive.
+      else if (_ai_char->_steering->_path_find_obj->_path_find_target.get_pos(_ai_char->_window_render)
+        != _ai_char->_steering->_path_find_obj->_prev_position) {
+        if (check_if_possible()) {
+          _path.clear();
+          _ai_char->_steering->_path_find_obj->path_find(_ai_char->_steering->_path_find_obj->_path_find_target);
+          // Ensure that the path size is not 0.
+          if (_path.size() > 0) {
+            _curr_path_waypoint = _path.size() - 1;
+            _dummy.set_pos(_path[_curr_path_waypoint]);
+          }
+          else {
+            // Refresh the _curr_path_waypoint value if path size is 0.
+            _curr_path_waypoint = -1;
+          }
+        }
+      }
+      _time = _myClock->get_real_time();
+    }
+  }
+
+  if (_curr_path_waypoint > 0) {
+    double distance = (_path[_curr_path_waypoint] -
+                           _ai_char->_ai_char_np.get_pos(_ai_char->_window_render)).length();
+
+    if (distance < 5) {
+      _curr_path_waypoint--;
+      _dummy.set_pos(_path[_curr_path_waypoint]);
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: check_if_possible
+//  Description: This function checks if the current positions of
+//               the ai char and the target char can be used to
+//               generate an optimal path.
+////////////////////////////////////////////////////////////////////
+bool PathFollow::check_if_possible() {
+  AINode* src = find_in_mesh(_ai_char->_steering->_path_find_obj->_nav_mesh,
+                           _ai_char->_ai_char_np.get_pos(_ai_char->_window_render),
+                           _ai_char->_steering->_path_find_obj->_grid_size);
+  LVecBase3f _prev_position = _ai_char->_steering->_path_find_obj->_path_find_target.get_pos(_ai_char->_window_render);
+  AINode* dst = find_in_mesh(_ai_char->_steering->_path_find_obj->_nav_mesh,
+                           _prev_position, _ai_char->_steering->_path_find_obj->_grid_size);
+
+  return (src && dst);
+}

+ 50 - 0
contrib/src/ai/pathFollow.h

@@ -0,0 +1,50 @@
+// Filename: pathFollow.h
+// Created by:  Deepak, John, Navin (24Oct09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised 
+// BSD license.  You should have received a copy of this license
+// along with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef PATHFOLLOW_H
+#define PATHFOLLOW_H
+
+#include "aiGlobals.h"
+#include "aiCharacter.h"
+#include "aiNode.h"
+
+class AICharacter;
+
+////////////////////////////////////////////////////////////////////
+//       Class : PathFollow
+// Description : This class handles all calls to the path follow
+//               behavior and has functions to handle pathfinding
+////////////////////////////////////////////////////////////////////
+class PathFollow {
+
+public:
+  AICharacter *_ai_char;
+  float _follow_weight;
+  vector<LVecBase3f> _path;
+  int _curr_path_waypoint;
+  bool _start;
+  NodePath _dummy;
+  string _type;
+  ClockObject *_myClock;
+  float _time;
+
+  PathFollow(AICharacter *ai_ch, float follow_wt);
+  ~PathFollow();
+  void add_to_path(LVecBase3f pos);
+  void start(string type);
+  void do_follow();
+  bool check_if_possible();
+};
+
+#endif

+ 60 - 0
contrib/src/ai/pursue.cxx

@@ -0,0 +1,60 @@
+// Filename: pursue.cxx
+// Created by:  Deepak, John, Navin (24Oct09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised 
+// BSD license.  You should have received a copy of this license
+// along with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "pursue.h"
+
+Pursue::Pursue(AICharacter *ai_ch, NodePath target_object, float pursue_wt) {
+  _ai_char = ai_ch;
+
+  _pursue_target = target_object;
+  _pursue_weight = pursue_wt;
+
+  _pursue_done = false;
+}
+
+Pursue::~Pursue() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: do_pursue
+//  Description: This function performs the pursue and returns a
+//               pursue force which is used
+//               in the calculate_prioritized function.
+//               In case the target has been reached it resets the
+//               forces to 0 so that the character stops.
+//               This function is not to be used by the user.
+////////////////////////////////////////////////////////////////////
+LVecBase3f Pursue::do_pursue() {
+  assert(_pursue_target && "pursue target not assigned");
+
+  LVecBase3f present_pos = _ai_char->_ai_char_np.get_pos(_ai_char->_window_render);
+  double target_distance = (_pursue_target.get_pos(_ai_char->_window_render) -
+                                                           present_pos).length();
+
+  if (int(target_distance) == 0) {
+    _pursue_done = true;
+    _ai_char->_steering->_steering_force = LVecBase3f(0.0, 0.0, 0.0);
+    _ai_char->_steering->_pursue_force = LVecBase3f(0.0, 0.0, 0.0);
+    return (LVecBase3f(0.0, 0.0, 0.0));
+  }
+  else {
+    _pursue_done = false;
+  }
+
+  _pursue_direction = _pursue_target.get_pos(_ai_char->_window_render) - present_pos;
+  _pursue_direction.normalize();
+
+  LVecBase3f desired_force = _pursue_direction * _ai_char->_movt_force;
+  return (desired_force);
+}

+ 42 - 0
contrib/src/ai/pursue.h

@@ -0,0 +1,42 @@
+// Filename: pursue.h
+// Created by:  Deepak, John, Navin (24Oct09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised 
+// BSD license.  You should have received a copy of this license
+// along with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef PURSUE_H
+#define PURSUE_H
+
+#include "aiGlobals.h"
+#include "aiCharacter.h"
+
+class AICharacter;
+
+////////////////////////////////////////////////////////////////////
+//       Class : Pursue
+// Description : This class handles all calls to the pursue
+//               behavior
+////////////////////////////////////////////////////////////////////
+class Pursue {
+
+public:
+  AICharacter *_ai_char;
+
+  NodePath _pursue_target;
+  float _pursue_weight;
+  LVecBase3f _pursue_direction;
+  bool _pursue_done;
+
+  Pursue(AICharacter *ai_ch, NodePath target_object, float pursue_wt);
+  ~Pursue();
+  LVecBase3f do_pursue();
+};
+#endif

+ 66 - 0
contrib/src/ai/seek.cxx

@@ -0,0 +1,66 @@
+// Filename: seek.cxx
+// Created by:  Deepak, John, Navin (24Oct09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised 
+// BSD license.  You should have received a copy of this license
+// along with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "seek.h"
+
+Seek::Seek(AICharacter *ai_ch, NodePath target_object, float seek_wt) {
+  _ai_char = ai_ch;
+
+  _seek_position = target_object.get_pos(_ai_char->_window_render);
+  _seek_weight = seek_wt;
+
+  _seek_direction = _seek_position - 
+                  _ai_char->_ai_char_np.get_pos(_ai_char->_window_render);
+  _seek_direction.normalize();
+
+  _seek_done = false;
+}
+
+Seek::Seek(AICharacter *ai_ch, LVecBase3f pos, float seek_wt) {
+  _ai_char = ai_ch;
+
+  _seek_position = pos;
+  _seek_weight = seek_wt;
+
+  _seek_direction = _seek_position -
+            _ai_char->_ai_char_np.get_pos(_ai_char->_window_render);
+  _seek_direction.normalize();
+
+  _seek_done = false;
+}
+
+Seek::~Seek() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: do_seek
+//  Description: This function performs the seek and returns a seek
+//               force which is used
+//               in the calculate_prioritized function.
+//               This function is not to be used by the user.
+////////////////////////////////////////////////////////////////////
+LVecBase3f Seek::do_seek() {
+  double target_distance = (_seek_position - 
+      _ai_char->_ai_char_np.get_pos(_ai_char->_window_render)).length();
+
+    if (int(target_distance) == 0) {
+        _seek_done = true;
+  _ai_char->_steering->_steering_force = LVecBase3f(0.0, 0.0, 0.0);
+  _ai_char->_steering->turn_off("seek");
+  return (LVecBase3f(0.0, 0.0, 0.0));
+  }
+
+  LVecBase3f desired_force = _seek_direction * _ai_char->_movt_force;
+  return (desired_force);
+}

+ 44 - 0
contrib/src/ai/seek.h

@@ -0,0 +1,44 @@
+// Filename: seek.h
+// Created by:  Deepak, John, Navin (24Oct09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised 
+// BSD license.  You should have received a copy of this license
+// along with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef SEEK_H
+#define SEEK_H
+
+#include "aiGlobals.h"
+#include "aiCharacter.h"
+
+class AICharacter;
+
+////////////////////////////////////////////////////////////////////
+//       Class : Seek
+// Description : This class handles all calls to the seek behavior
+////////////////////////////////////////////////////////////////////
+class Seek {
+
+public:
+  AICharacter *_ai_char;
+
+  LVecBase3f _seek_position;
+  float _seek_weight;
+  LVecBase3f _seek_direction;
+  bool _seek_done;
+  LVecBase3f _seek_accum_force;
+
+  Seek(AICharacter *ai_ch, NodePath target_object, float seek_wt = 1.0);
+  Seek(AICharacter *ai_ch, LVecBase3f pos, float seek_wt = 1.0);
+  ~Seek();
+  LVecBase3f do_seek();
+};
+
+#endif

+ 140 - 0
contrib/src/ai/wander.cxx

@@ -0,0 +1,140 @@
+// Filename: wander.cxx
+// Created by:  Deepak, John, Navin (24Oct09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised 
+// BSD license.  You should have received a copy of this license
+// along with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "wander.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: rand_float
+//  Description: This function creates a random float point number
+////////////////////////////////////////////////////////////////////
+double rand_float() {
+  const static double rand_max = 0x7fff;
+  return ((rand()) / (rand_max + 1.0));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: random_clamped
+//  Description: This function returns a random floating point number
+//               in the range -1 to 1.
+////////////////////////////////////////////////////////////////////
+double random_clamped() {
+  return (rand_float() - rand_float());
+}
+
+Wander::Wander(AICharacter *ai_ch, double wander_radius,int flag,
+                                     double aoe, float wander_weight) {
+  _ai_char = ai_ch;
+  _wander_radius = wander_radius ;
+  _wander_weight = wander_weight;
+  double theta = rand_float() * 2 * 3.14159;
+  double si = rand_float() * 3.14159;
+  _flag = flag;
+  // Area around which the character should wander
+  _area_of_effect = aoe;
+  _init_pos = _ai_char->get_node_path().get_pos(_ai_char->get_char_render());
+  // _flag is used by Wander to wander in a given axis
+  // Value 0 - XY axes wander
+  // Value 1 - YZ axes wander
+  // Value 2 - XZ axes wander
+  // Value 3 - XYZ axes wander
+  // default is XY axes
+  switch (_flag) {
+    case 0: {
+              _wander_target = LVecBase3f(_wander_radius * cos(theta),
+                                             _wander_radius * sin(theta),0);
+              break;
+            }
+    case 1: {
+              _wander_target = LVecBase3f(0, _wander_radius * cos(theta),
+                                                _wander_radius * sin(theta));
+              break;
+            }
+    case 2: {
+              _wander_target = LVecBase3f(_wander_radius * cos(theta), 0,
+                                                 _wander_radius * sin(theta));
+              break;
+            }
+    case 3: {
+              _wander_target = LVecBase3f(_wander_radius * sin(theta) * cos(si),
+                    _wander_radius * sin(theta) * sin(si), _wander_radius * cos(theta));
+              break;
+            }
+    default: {
+              _wander_target = LVecBase3f(_wander_radius * cos(theta),
+                                              _wander_radius * sin(theta),0);
+              break;
+             }
+  }
+}
+
+Wander::~Wander() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: do_wander
+//  Description: This function performs the wander and returns the
+//               wander force which is used
+//               in the calculate_prioritized function.
+//               This function is not to be used by the user.
+////////////////////////////////////////////////////////////////////
+LVecBase3f Wander::do_wander() {
+  LVecBase3f present_pos = _ai_char->get_node_path().get_pos(_ai_char->get_char_render());
+  // Create the random slices to enable random movement of wander
+  // for x,y,z respectively
+  double time_slice_1 = random_clamped() * 1.5;
+  double time_slice_2 = random_clamped() * 1.5;
+  double time_slice_3 = random_clamped() * 1.5;
+  switch (_flag) {
+  case 0: {
+            _wander_target += LVecBase3f(time_slice_1, time_slice_2, 0);
+            break;
+          }
+  case 1: {
+            _wander_target += LVecBase3f(0, time_slice_1, time_slice_2);
+            break;
+          }
+  case 2: {
+            _wander_target += LVecBase3f(time_slice_1, 0, time_slice_2);
+            break;
+          }
+  case 3: {
+            _wander_target += LVecBase3f(time_slice_1, time_slice_2, time_slice_3);
+            break;
+          }
+
+  default: {
+            _wander_target = LVecBase3f(time_slice_1, time_slice_2, 0);
+           }
+  }
+  _wander_target.normalize();
+  _wander_target *= _wander_radius;
+  LVecBase3f target = _ai_char->get_char_render().get_relative_vector(_ai_char->get_node_path(), LVector3f::forward());
+  target.normalize();
+  // Project wander target onto global space
+  target = _wander_target + target;
+  LVecBase3f desired_target = present_pos + target;
+  LVecBase3f desired_force = desired_target - _ai_char->get_node_path().get_pos() ;
+  desired_force.normalize();
+  desired_force *= _ai_char->_movt_force;
+  double distance = (present_pos - _init_pos).length();
+  if (_area_of_effect > 0 && distance > _area_of_effect) {
+  LVecBase3f direction = present_pos - _init_pos;
+  direction.normalize();
+  desired_force =  - direction * _ai_char->_movt_force;
+  LVecBase3f dirn = _ai_char->_steering->_steering_force;
+  dirn.normalize();
+  _ai_char->_steering->_steering_force = LVecBase3f(0.0, 0.0, 0.0);
+  }
+  return desired_force;
+}

+ 40 - 0
contrib/src/ai/wander.h

@@ -0,0 +1,40 @@
+// Filename: wander.h
+// Created by:  Deepak, John, Navin (24Oct09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised 
+// BSD license.  You should have received a copy of this license
+// along with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+#ifndef WANDER_H
+#define WANDER_H
+
+#include "aiCharacter.h"
+
+class AICharacter;
+
+////////////////////////////////////////////////////////////////////
+//       Class : Wander
+// Description : This class handles all calls to the wander behavior
+////////////////////////////////////////////////////////////////////
+class Wander {
+public:
+  AICharacter *_ai_char;
+  double _wander_radius;
+  LVecBase3f _wander_target;
+  float _wander_weight;
+  int _flag;
+  LVecBase3f _init_pos;
+  double _area_of_effect;
+
+  Wander(AICharacter *ai_ch, double wander_radius, int flag, double aoe, float wander_weight);
+  LVecBase3f do_wander();
+  ~Wander();
+};
+
+#endif

+ 26 - 0
contrib/src/contribbase/contribbase.h

@@ -0,0 +1,26 @@
+/* Filename: contribbase.h
+ * Created by:  rdb (30Dec09)
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ * PANDA 3D SOFTWARE
+ * Copyright (c) Carnegie Mellon University.  All rights reserved.
+ *
+ * All use of this software is subject to the terms of the revised BSD
+ * license.  You should have received a copy of this license along
+ * with this source code in a file named "LICENSE."
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* This file is included at the beginning of every header file and/or
+   C or C++ file.  It must be compilable for C as well as C++ files,
+   so no C++-specific code or syntax can be put here. */
+
+#ifndef CONTRIBBASE_H
+#define CONTRIBBASE_H
+
+#include "pandabase.h"
+#include "contribsymbols.h"
+
+#endif
+

+ 42 - 0
contrib/src/contribbase/contribsymbols.h

@@ -0,0 +1,42 @@
+/* Filename: contribsymbols.h
+ * Created by:  rdb (30Dec09)
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ * PANDA 3D SOFTWARE
+ * Copyright (c) Carnegie Mellon University.  All rights reserved.
+ *
+ * All use of this software is subject to the terms of the revised BSD
+ * license.  You should have received a copy of this license along
+ * with this source code in a file named "LICENSE."
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#ifndef CONTRIBSYMBOLS_H
+#define CONTRIBSYMBOLS_H
+
+/* See dtoolsymbols.h for a rant on the purpose of this file.  */
+
+/* Note that the symbols declared in this file appear in alphabetical
+   order.  Also note that we must use C-style comments only here, not
+   C++-style comments, since this file is occasionally included by a C
+   file. */
+
+#if defined(WIN32_VC) && !defined(CPPPARSER) && !defined(LINK_ALL_STATIC)
+
+#ifdef BUILDING_PANDAAI
+  #define EXPCL_PANDAAI __declspec(dllexport)
+  #define EXPTP_PANDAAI
+#else
+  #define EXPCL_PANDAAI __declspec(dllimport)
+  #define EXPTP_PANDAAI extern
+#endif
+
+#else   /* !WIN32_VC */
+
+#define EXPCL_PANDAAI
+#define EXPTP_PANDAAI
+
+#endif  /* WIN32_VC */
+
+#endif