Rework action for police : finished. master
authorbenblan <benblan@3ce38193-f967-438d-acd5-fc4e68e0da95>
Thu, 19 Feb 2015 06:44:41 +0000 (06:44 +0000)
committerbenblan <benblan@3ce38193-f967-438d-acd5-fc4e68e0da95>
Thu, 19 Feb 2015 06:44:41 +0000 (06:44 +0000)
12 files changed:
freesynd/branches/rework-actions/src/core/gameevent.h
freesynd/branches/rework-actions/src/ia/action.cpp
freesynd/branches/rework-actions/src/ia/actions.h
freesynd/branches/rework-actions/src/ia/behaviour.cpp
freesynd/branches/rework-actions/src/ia/behaviour.h
freesynd/branches/rework-actions/src/mapobject.cpp
freesynd/branches/rework-actions/src/mapobject.h
freesynd/branches/rework-actions/src/menus/gameplaymenu.cpp
freesynd/branches/rework-actions/src/menus/gameplaymenu.h
freesynd/branches/rework-actions/src/mission.cpp
freesynd/branches/rework-actions/src/ped.h
freesynd/branches/rework-actions/src/pedactions.cpp

index a00bf0ac415b0c9d55dee4c216ff6b968674576b..378e2e34afad4b08edfa09f0909e6f336f18b650 100644 (file)
@@ -58,7 +58,9 @@ public:
         /*! Sent when a ped has shown his weapon.*/
         kEvtWeaponOut,
         /*! Sent when a ped cleared his weapon.*/
-        kEvtWeaponCleared
+        kEvtWeaponCleared,
+        /*! Sent when a policeman warns a player agent.*/
+        kEvtWarnAgent
     };
     //! The stream on which the event is posted
     EEventStream stream;
index 86ef5422a2df78495b66cd6d353dc66198028cdd..d7d3f6614b13c7f7089c6ba0dfe071ffc79c4edc 100644 (file)
@@ -41,6 +41,9 @@ using namespace fs_actions;
 //*************************************
 const int FollowAction::kFollowDistance = 192;
 const int WalkBurnHitAction::kTimeToWalkBurning = 1000;
+const uint8 ShootAction::kShootActionNotAdded = 0;
+const uint8 ShootAction::kShootActionAutomaticShoot = 1;
+const uint8 ShootAction::kShootActionSingleShoot = 2;
 
 /*!
  * Default constructor.
@@ -370,6 +373,70 @@ bool FollowAction::doExecute(int elapsed, Mission *pMission, PedInstance *pPed)
     return updated;
 }
 
+/*!
+ * Class constructor.
+ * \param pTarget The ped to follow.
+ */
+FollowToShootAction::FollowToShootAction(fs_actions::CreatOrigin origin, PedInstance *pTarget) :
+MovementAction(kActTypeFollow, origin) {
+    pTarget_ = pTarget;
+    targetState_ = PedInstance::pa_smWalking;
+    followDistance_ = 0;
+}
+
+/*!
+ * If the ped's has no weapon, don't follow.
+ * \param pMission Mission data
+ * \param pPed The ped executing the action.
+ */
+void FollowToShootAction::doStart(Mission *pMission, PedInstance *pPed) {
+    if (pPed->selectedWeapon() == NULL) {
+        setFailed();
+        return;
+    } else {
+        followDistance_ = (pPed->selectedWeapon()->range() / 3 ) *2;
+    }
+
+    targetLastPos_.setTileXYZ(0, 0, 0);
+    targetLastPos_.setOffXY(0, 0);
+}
+
+bool FollowToShootAction::doExecute(int elapsed, Mission *pMission, PedInstance *pPed) {
+    bool updated = false;
+
+    if (pTarget_->isDead()) {
+        // target is dead so stop moving and terminate action
+        pPed->clearDestination();
+        setFailed();
+    } else {
+        // target has moved: we use checkCurrPosTileOnly() to give time to ped
+        // to walk away else animation is buggy
+        if (!pTarget_->checkCurrPosTileOnly(targetLastPos_)) {
+            // resetting target position
+            pTarget_->getPosition(&targetLastPos_);
+            if (!pPed->setDestination(pMission, targetLastPos_)) {
+                setFailed();
+                return true;
+            }
+        }
+        
+        toDefineXYZ policeLoc;
+        pPed->convertPosToXYZ(&policeLoc);
+        // police stops walking if the target is in range of fire (ie close enough and not
+        // hiding behing something)
+        if (pPed->isCloseTo(pTarget_, followDistance_) &&
+            pMission->checkBlockedByTile(policeLoc, &targetLastPos_, true, followDistance_) == 1) {
+            // We reached the target so stop moving
+            setSucceeded();
+            pPed->clearDestination();
+        } else {
+            updated = pPed->movementP(pMission, elapsed);
+        }
+        
+    }
+    return updated;
+}
+
 PutdownWeaponAction::PutdownWeaponAction(uint8 weaponIdx) : MovementAction(kActTypeUndefined, kOrigUser, true) {
     weaponIdx_ = weaponIdx;
     targetState_ = PedInstance::pa_smPutDown;
@@ -485,26 +552,89 @@ bool DriveVehicleAction::doExecute(int elapsed, Mission *pMission, PedInstance *
 }
 
 WaitAndWarnAction::WaitAndWarnAction(PedInstance *pPed) : 
-MovementAction(kActTypeUndefined, kOrigDefault, true), waitTimer_(1000) {
+MovementAction(kActTypeUndefined, kOrigDefault, true), waitTimer_(2000) {
     pTarget_ = pPed;
 }
 
+/*!
+ * Select a weapon for the ped if he has no weapon out.
+ * \param pPed The police man.
+ */
+void WaitAndWarnAction::selectWeaponIfNecessary(PedInstance *pPed) {
+    WeaponInstance *pWeapon = pPed->selectedWeapon();
+    if (pWeapon == NULL) {
+        // Select a loaded weapon for ped
+        WeaponHolder::WeaponSelectCriteria crit;
+        crit.desc = WeaponHolder::WeaponSelectCriteria::kCritLoadedShoot;
+        crit.use_ranks = true;
+        pPed->selectRequiredWeapon(&crit);
+    }
+}
+
 void WaitAndWarnAction::doStart(Mission *pMission, PedInstance *pPed) {
-    waitTimer_.reset();
-    pPed->clearDestination();
+    if (pTarget_->isDead()) {
+        setFailed();
+    } else {
+        waitTimer_.reset();
+        pPed->clearDestination();
+        selectWeaponIfNecessary(pPed);
+    }
 }
 
 bool WaitAndWarnAction::doExecute(int elapsed, Mission *pMission, PedInstance *pPed) {
+    // point toward target
+    pPed->setDirectionTowardObject(*pTarget_);
+
     if (waitTimer_.update(elapsed)) {
+        if (pTarget_->isOurAgent()) {
+            // Warn only for player agents
+            GameEvent evt;
+            evt.stream = GameEvent::kMission;
+            evt.type = GameEvent::kEvtWarnAgent;
+            g_gameCtrl.fireGameEvent(evt);
+        }
         setSucceeded();
         return true;
     }
 
-    // TODO : Add warning
-
     return false;
 }
 
+FireWeaponAction::FireWeaponAction(PedInstance *pPed) : 
+MovementAction(kActTypeUndefined, kOrigDefault) {
+    pTarget_ = pPed;
+}
+
+void FireWeaponAction::doStart(Mission *pMission, PedInstance *pPed) {
+    if (pTarget_->isDead()) {
+        setFailed();
+    } else if (pPed->type() == PedInstance::kPedTypePolice && pTarget_->selectedWeapon() == NULL) {
+        // Police man don't shoot on peds that don't have gun out
+        setFailed();
+    } else {
+        PathNode targetLoc;
+        pTarget_->getPosition(&targetLoc);
+
+        shootType_ = pPed->addActionShootAt(targetLoc);
+        if (shootType_ == ShootAction::kShootActionNotAdded) {
+            // failed to shoot because weapon has no ammo
+            setFailed();
+        } else if (shootType_ == ShootAction::kShootActionAutomaticShoot) {
+            // todo :set a timer to controle time shooting
+        }
+    }
+}
+
+bool FireWeaponAction::doExecute(int elapsed, Mission *pMission, PedInstance *pPed) {
+    if (shootType_ == ShootAction::kShootActionSingleShoot) {
+        if (!pPed->isUsingWeapon()) {
+            setSucceeded();
+        }
+    }
+    
+    return true;
+}
+
 HitAction::HitAction(CreatOrigin origin, ShootableMapObject::DamageInflictType &d) : 
 MovementAction(kActTypeHit, origin) {
     damage_.aimedLoc = d.aimedLoc;
index 0937bbc908356aec99f646932d165d3f8dd2596d..f2fb7c280a17ac2eda9fd0f52d0204a4ed706033 100644 (file)
@@ -315,6 +315,29 @@ namespace fs_actions {
         PathNode targetLastPos_;
     };
 
+    /*!
+     * This action is used for a policeman to follow a target and when
+     * the target is in shooting range, the action is finished.
+     * The shooting range is 2/3 of the currently selected weapon range.
+     */
+    class FollowToShootAction : public MovementAction {
+    public:
+        //! Constructor
+        FollowToShootAction(fs_actions::CreatOrigin origin, PedInstance *pTarget);
+        void setTarget(PedInstance *pTarget) { pTarget_ = pTarget; }
+    protected:
+        void doStart(Mission *pMission, PedInstance *pPed);
+        bool doExecute(int elapsed, Mission *pMission, PedInstance *pPed);
+
+    protected:
+        /*! The ped to follow.*/
+        PedInstance *pTarget_;
+        /*! To keep track of target position and see if it has moved.*/
+        PathNode targetLastPos_;
+        /*! The distance.*/
+        int followDistance_;
+    };
+
     /*!
      * This action allows an agent to drop a weapon (identified by its
      * position in the agent's inventory) on the ground.
@@ -392,6 +415,8 @@ namespace fs_actions {
     protected:
         void doStart(Mission *pMission, PedInstance *pPed);
         bool doExecute(int elapsed, Mission *pMission, PedInstance *pPed);
+
+        void selectWeaponIfNecessary(PedInstance *pPed);
     protected:
         /*! The ped watched by this police ped.*/
         PedInstance *pTarget_;
@@ -399,6 +424,23 @@ namespace fs_actions {
         fs_utils::Timer waitTimer_;
     };
 
+    /*!
+     * This action is used to make peds other than the player's agent shoot.
+     */
+    class FireWeaponAction : public MovementAction {
+    public:
+        FireWeaponAction(PedInstance *pPed);
+
+    protected:
+        void doStart(Mission *pMission, PedInstance *pPed);
+        bool doExecute(int elapsed, Mission *pMission, PedInstance *pPed);
+    protected:
+        /*! The ped that is being shot at by the action owner.*/
+        PedInstance *pTarget_;
+        /*! tells if it is a single or automatic shot.*/
+        uint8 shootType_;
+    };
+
     /*!
      * A HitAction is used to implement the reaction of the ped to an impact.
      * When a Ped is hit by a shot, a HitAction is created and inserted directly
@@ -515,6 +557,14 @@ namespace fs_actions {
      * This action is used to shoot with a one shot gun.
      */
     class ShootAction : public UseWeaponAction {
+    public:
+        //! This constant is returned by Ped::addActionShootAt to indicate no action was added
+        static const uint8 kShootActionNotAdded;
+        //! This constant is returned by Ped::addActionShootAt to indicate that an AutomaticShootAction was added
+        static const uint8 kShootActionAutomaticShoot;
+        //! This constant is returned by Ped::addActionShootAt to indicate that a ShootAction was added
+        static const uint8 kShootActionSingleShoot;
+
     public:
         ShootAction(CreatOrigin origin, PathNode &aimedAt, WeaponInstance *pWeapon);
 
index f2f0a8187f1d27c50cd7f6f800bceaf0cbcfb077..3a9b768da778d312e4459c6b99ecc3b01c700265 100644 (file)
@@ -39,6 +39,7 @@ const int PanicComponent::kScoutDistance = 1500;
 const int PanicComponent::kDistanceToRun = 500;
 const double PersuadedBehaviourComponent::kMaxRangeForSearchingWeapon = 500.0;
 const int PoliceBehaviourComponent::kPoliceScoutDistance = 1500;
+const int PoliceBehaviourComponent::kPolicePendingTime = 1500;
 
 Behaviour::~Behaviour() {
     destroyComponents();
@@ -328,7 +329,7 @@ void  PanicComponent::runAway(PedInstance *pPed, PedInstance *pArmedPed, fs_acti
 }
 
 PoliceBehaviourComponent::PoliceBehaviourComponent():
-        BehaviourComponent(), scoutTimer_(134) {
+        BehaviourComponent(), scoutTimer_(200), endFollowTimer_(kPolicePendingTime) {
     status_ = kPoliceStatusOnPatrol;
     pTarget_ = NULL;
 }
@@ -340,6 +341,19 @@ void PoliceBehaviourComponent::execute(int elapsed, Mission *pMission, PedInstan
             status_ = kPoliceStatusFollowAndShoot;
             followAndShootTarget(pPed, pArmedGuy);
         }
+    } else if (status_ == kPoliceStatusPendingEndFollow && endFollowTimer_.update(elapsed)) {
+        if (pMission->numArmedPeds() != 0) {
+            // There are still some armed peds so keep on alert
+            status_ = kPoliceStatusAlert;
+        } else {
+            status_ = kPoliceStatusOnPatrol;
+        }
+        pPed->destroyAllActions(true);
+        pPed->destroyUseWeaponAction();
+        pPed->deselectWeapon();
+        pPed->addMovementAction(
+                new fs_actions::WalkToDirectionAction(fs_actions::kOrigDefault), 
+                true);
     }
 }
 
@@ -352,8 +366,17 @@ void PoliceBehaviourComponent::handleBehaviourEvent(PedInstance *pPed, Behaviour
         }
         break;
     case Behaviour::kBehvEvtWeaponCleared:
-        // When no more enemies have weapons out, patrol again
-        
+        // Someone has dropped his weapon
+        if (pTarget_ == pCtxt) {
+            status_ = kPoliceStatusPendingEndFollow;
+            if (pTarget_->isDead()) {
+                // target dropped his weapon because he's dead
+                // so no need to wait
+                endFollowTimer_.reset(0);
+            } else {
+                endFollowTimer_.reset(kPolicePendingTime);
+            }
+        }
         break;
     }
 }
@@ -373,22 +396,17 @@ PedInstance * PoliceBehaviourComponent::findArmedPedNotPolice(Mission *pMission,
 
 void PoliceBehaviourComponent::followAndShootTarget(PedInstance *pPed, PedInstance *pArmedGuy) {
     pTarget_ = pArmedGuy;
-    // Select a loaded weapon for ped
-    WeaponHolder::WeaponSelectCriteria crit;
-    crit.desc = WeaponHolder::WeaponSelectCriteria::kCritLoadedShoot;
-    crit.use_ranks = true;
-    pPed->selectRequiredWeapon(&crit);
     // stop walking
     pPed->clearDestination();
-    // quit walking now 
-    // TODO : change state management
+    // force quiting walking now because entering standing state does not remove walking state
     pPed->leaveState(PedInstance::pa_smWalking);
     pPed->destroyAllActions(true);
     // Set new actions
-    fs_actions::WaitAndWarnAction *pWarnAction = new fs_actions::WaitAndWarnAction(pPed);
+    fs_actions::WaitAndWarnAction *pWarnAction = new fs_actions::WaitAndWarnAction(pArmedGuy);
     pPed->addMovementAction(pWarnAction, false);
-    //fs_actions::FollowAction *pFollowAction = new fs_actions::FollowAction(fs_actions::kOrigDefault, pPed);
-    //pPed->addMovementAction(pFollowAction, true);
-    //pPed->addActionFollowPed(fs_actions::kOrigDefault, pArmedGuy);
+    fs_actions::FollowToShootAction* pFollowAction = new fs_actions::FollowToShootAction(fs_actions::kOrigDefault, pArmedGuy);
+    pPed->addMovementAction(pFollowAction, true);
+    fs_actions::FireWeaponAction *pFireAction = new fs_actions::FireWeaponAction(pArmedGuy);
+    pPed->addMovementAction(pFireAction, true);
     pPed->addMovementAction(new fs_actions::ResetScriptedAction(), true);
 }
\ No newline at end of file
index 3f38784a6834ce70f211d7b335a979381d088017..4087b7dbcd7e375b5b4a844f5debece81df5b723 100644 (file)
@@ -222,6 +222,7 @@ private:
     void followAndShootTarget(PedInstance *pPed, PedInstance *pArmedGuy);
 private:
     static const int kPoliceScoutDistance;
+    static const int kPolicePendingTime;
     /*!
      * Status of police behaviour.
      */
@@ -231,13 +232,17 @@ private:
         //! Search for someone who pulled his gun
         kPoliceStatusAlert,
         //! Move closer from target to shoot at him
-        kPoliceStatusFollowAndShoot
+        kPoliceStatusFollowAndShoot,
+        //! When target drops his weapon, stop follow him
+        kPoliceStatusPendingEndFollow
     };
 
     PoliceStatus status_;
     /*! This timer is used to delay checking by the ped in order to 
      * not consume too much CPU.*/
     fs_utils::Timer scoutTimer_;
+    /*! Police wait for some time before really stopping following.*/
+    fs_utils::Timer endFollowTimer_;
     /*! The ped that the police officer is watching and eventually shooting at.*/
     PedInstance *pTarget_;
 };
index 381239ceeeb8894068bb837db5e71365cd06f36e..05d4543227965b27e1b4876866a16d6ac692699f 100644 (file)
@@ -191,6 +191,16 @@ void MapObject::setDirection(int posx, int posy, int * dir) {
     }
 }
 
+void MapObject::setDirectionTowardObject(const MapObject &object) {
+    int xb = this->tileX() * 256 + this->offX();
+    int yb = this->tileY() * 256 + this->offY();
+    
+    int txb = object.tileX() * 256 + object.offX();
+    int tyb = object.tileY() * 256 + object.offY();
+
+    this->setDirection(txb - xb, tyb - yb);
+}
+
 /*!
  * @returns direction for selected number of surfaces
  */
index 534e061436232843ec7677f97fd27c055967fb4e..b379b7d7c25e327210dc97c83dae956374b787aa 100644 (file)
@@ -124,17 +124,29 @@ public:
                     pos.y % 256, pos.z % 128 );
     }
 
-    int tileX() { return tile_x_; }
-    int tileY() { return tile_y_; }
-    int tileZ() { return tile_z_; }
+    /*!
+     * Set the given position to the ped's position.
+     */
+    void getPosition(PathNode *pn) {
+        pn->setTileX(tile_x_);
+        pn->setTileY(tile_y_);
+        pn->setTileZ(tile_z_);
+        pn->setOffX(off_x_);
+        pn->setOffY(off_y_);
+        pn->setOffZ(off_z_);
+    }
+
+    int tileX() const { return tile_x_; }
+    int tileY() const { return tile_y_; }
+    int tileZ() const { return tile_z_; }
 
     void setTileX(int x) { tile_x_ = x; }
     void setTileY(int y) { tile_y_ = y; }
     void setTileZ(int z) { tile_z_ = z; }
 
-    int offX() { return off_x_; }
-    int offY() { return off_y_; }
-    int offZ() { return off_z_; }
+    int offX() const { return off_x_; }
+    int offY() const { return off_y_; }
+    int offZ() const { return off_z_; }
 
     void setOffX(int n);
     void setOffY(int n);
@@ -261,6 +273,8 @@ public:
 
     void setDirection(int dir);
     void setDirection(int posx, int posy, int * dir = NULL);
+    //! Set this ped's direction so that he looks at the given object.
+    void setDirectionTowardObject(const MapObject &object);
 
     int direction() { return dir_;}
     int getDirection(int snum = 8);
index cc207744e2d8ce183f18286dc6a9ffdd8caf6a47..d1bc6845549a342e299ea23cbddc04cd9da92ac4 100644 (file)
@@ -56,11 +56,12 @@ last_motion_x_(320), last_motion_y_(240), mission_hint_ticks_(0),
 mission_hint_(0), mission_(NULL), world_x_(0),
 world_y_(0), selection_(),
 target_(NULL),
-mm_renderer_()
+mm_renderer_(), warningTimer_(20000)
 {
     scroll_x_ = 0;
     scroll_y_ = 0;
     ipa_chng_.ipa_chng = -1;
+    canPlayPoliceWarnSound_ = true;
     g_gameCtrl.addListener(this, GameEvent::kMission);
 }
 
@@ -330,6 +331,11 @@ void GameplayMenu::handleTick(int elapsed)
         mission_->checkObjectives();
     }
 
+    if (!canPlayPoliceWarnSound_ && warningTimer_.update(elapsed)) {
+        // wait an amount of time before allowing another warning
+        canPlayPoliceWarnSound_ = true;
+    }
+
     // Scroll the map
     if (scroll_x_ != 0) {
         change = scrollOnX();
@@ -1491,5 +1497,11 @@ void GameplayMenu::handleGameEvent(GameEvent evt) {
                 pPed->behaviour().handleBehaviourEvent(Behaviour::kBehvEvtWeaponCleared, pPedSource);
             }
         }
+    } else if (evt.type == GameEvent::kEvtWarnAgent) {
+        if (canPlayPoliceWarnSound_) {
+            // warn
+            g_App.gameSounds().play(snd::PUTDOWN_WEAPON);
+            canPlayPoliceWarnSound_ = false;
+        }
     }
 }
index 45f1d28de0620643969f77405511dde79c19dae3..4f3db404c8132fc2d4d93e618e7b67bb8494cefb 100644 (file)
@@ -130,6 +130,10 @@ protected:
     bool isButtonSelectAllPressed_;
     /*! Flag to store the fact that player is currently shooting.*/
     bool isPlayerShooting_;
+    /*! Flag to play the sound of police warning an agent.*/
+    bool canPlayPoliceWarnSound_;
+    /*! Delay between 2 police warnings.*/
+    fs_utils::Timer warningTimer_;
 
     // when ipa is manipulated this represents
     struct IPA_manipulation {
index 4c141fee5b31c9a0b86b8d0959ea517bada2e1c8..0fae07caf902e377542853c09d94dbb791355162 100644 (file)
@@ -2535,8 +2535,8 @@ void Mission::blockerExists(toDefineXYZ * startXYZ, toDefineXYZ * endXYZ,
         }
     }
     for (unsigned int i = 0; i < peds_.size(); ++i) {
-        MapObject * p_blocker = peds_[i];
-        if (p_blocker->isIgnored())
+        PedInstance * p_blocker = peds_[i];
+        if (p_blocker->isDead() || p_blocker->isIgnored())
             continue;
         if (p_blocker->isBlocker(&copyStartXYZ, &copyEndXYZ, inc_xyz)) {
             int cx = startXYZ->x - copyStartXYZ.x;
index 430ad35aa5e66e1fac2215048d0d7042a057699a..0b98cbaaafe43e83ad7b63ca073312aeaf59eb9d 100644 (file)
@@ -340,7 +340,7 @@ public:
     //! Return true if ped can use a weapon
     bool canAddUseWeaponAction(WeaponInstance *pWeapon = NULL);
     //! Adds action to shoot somewhere
-    void addActionShootAt(const PathNode &aimedPt);
+    uint8 addActionShootAt(const PathNode &aimedPt);
     //! Adds action to use medikit
     void addActionUseMedikit();
     //! Creates and insert a HitAction for the ped
index 41d39e6bfb7a5427cf5f81e30141f370bd26b4a2..4b42e47ee29df6bd7db06854625af30e2eff099e 100644 (file)
@@ -255,17 +255,22 @@ void PedInstance::insertHitAction(DamageInflictType &d) {
  * Adds an action of shooting at something/somewhere.
  * Also adds a shooting action for persuaded if this is an agent.
  * \param aimedPt Where the ped must shoot
+ * \return kShootActionNotAdded if no action (see canAddUseWeaponAction()),
+ *         
  */
-void PedInstance::addActionShootAt(const PathNode &aimedPt) {
+uint8 PedInstance::addActionShootAt(const PathNode &aimedPt) {
     if (canAddUseWeaponAction()) {
+        uint8 res;
         // adds precision to the shoot
         PathNode adjAimedPt = aimedPt;
         WeaponInstance *pWeapon = selectedWeapon();
         adjustAimedPtWithRangeAndAccuracy(pWeapon->getWeaponClass(), adjAimedPt);
         if (pWeapon->getWeaponClass()->isAutomatic()) {
             pUseWeaponAction_ = new fs_actions::AutomaticShootAction(fs_actions::kOrigUser, adjAimedPt, pWeapon);
+            res = fs_actions::ShootAction::kShootActionAutomaticShoot;
         } else {
             pUseWeaponAction_ = new fs_actions::ShootAction(fs_actions::kOrigUser, adjAimedPt, pWeapon);
+            res = fs_actions::ShootAction::kShootActionSingleShoot;
         }
 
         // notify persuadeds to shoot
@@ -273,7 +278,11 @@ void PedInstance::addActionShootAt(const PathNode &aimedPt) {
                 it != persuadedSet_.end(); it++) {
                     (*it)->addActionShootAt(aimedPt);
         }
+
+        return res;
     }
+
+    return fs_actions::ShootAction::kShootActionNotAdded;
 }
 
 /*!