[colobot] 56/145: LevelController improvements; minor EndMissionTake cleanup

Didier Raboud odyx at moszumanska.debian.org
Mon Jul 11 12:56:17 UTC 2016


This is an automated email from the git hooks/post-receive script.

odyx pushed a commit to branch debian/master
in repository colobot.

commit 4c8da2c5036fc8a9ab0123b7f0a29a2a15eb260d
Author: krzys-h <krzys_h at interia.pl>
Date:   Fri Apr 8 20:56:09 2016 +0200

    LevelController improvements; minor EndMissionTake cleanup
    
    * using LevelController script in the level doesn't forcefully disable EndMissionTake and AudioChange anymore
    * cleaned up some code related to processing EndMissionTake commands
---
 src/level/robotmain.cpp      | 202 ++++++++++++++++++++++---------------------
 src/level/robotmain.h        |   9 +-
 src/level/scene_conditions.h |   1 +
 src/script/scriptfunc.cpp    |   2 +-
 4 files changed, 114 insertions(+), 100 deletions(-)

diff --git a/src/level/robotmain.cpp b/src/level/robotmain.cpp
index 274118b..b3c34de 100644
--- a/src/level/robotmain.cpp
+++ b/src/level/robotmain.cpp
@@ -1236,19 +1236,22 @@ void CRobotMain::ExecuteCmd(const std::string& cmd)
 
         if (cmd == "controller")
         {
-            if (m_controller != nullptr)
+            if (m_controller == nullptr)
             {
-                // Don't use SelectObject because it checks if the object is selectable
-                if (m_camera->GetType() == Gfx::CAM_TYPE_VISIT)
-                    StopDisplayVisit();
+                GetLogger()->Error("No LevelController on the map to select\n");
+                return;
+            }
 
-                CObject* prev = DeselectAll();
-                if (prev != nullptr && prev != m_controller)
-                    PushToSelectionHistory(prev);
+            // Don't use SelectObject because it checks if the object is selectable
+            if (m_camera->GetType() == Gfx::CAM_TYPE_VISIT)
+                StopDisplayVisit();
 
-                SelectOneObject(m_controller, true);
-                m_short->UpdateShortcuts();
-            }
+            CObject* prev = DeselectAll();
+            if (prev != nullptr && prev != m_controller)
+                PushToSelectionHistory(prev);
+
+            SelectOneObject(m_controller, true);
+            m_short->UpdateShortcuts();
             return;
         }
 
@@ -2831,6 +2834,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
         m_endingLostRank  = 0;
         m_audioChange.clear();
         m_endTake.clear();
+        m_endTakeImmediat = false;
         m_endTakeResearch = 0;
         m_endTakeWinDelay = 2.0f;
         m_endTakeLostDelay = 2.0f;
@@ -2870,6 +2874,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
         m_teamNames.clear();
 
         m_missionResult = ERR_MISSION_NOTERM;
+        m_missionResultFromScript = false;
     }
 
     //NOTE: Reset timer always, even when only resetting object positions
@@ -2999,7 +3004,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
                 continue;
             }
 
-            if (line->GetCommand() == "AudioChange" && !resetObject && m_controller == nullptr)
+            if (line->GetCommand() == "AudioChange" && !resetObject)
             {
                 auto audioChange = MakeUnique<CAudioChangeCondition>();
                 audioChange->Read(line.get());
@@ -3009,7 +3014,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
                 continue;
             }
 
-            if (line->GetCommand() == "Audio" && !resetObject && m_controller == nullptr)
+            if (line->GetCommand() == "Audio" && !resetObject)
             {
                 if (line->GetParam("track")->IsDefined())
                 {
@@ -3410,6 +3415,11 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
 
             if (line->GetCommand() == "LevelController" && m_sceneReadPath.empty())
             {
+                if (m_controller != nullptr)
+                {
+                    throw CLevelParserException("There can be only one LevelController in the level");
+                }
+
                 m_controller = m_objMan->CreateObject(Math::Vector(0.0f, 0.0f, 0.0f), 0.0f, OBJECT_CONTROLLER);
                 assert(m_controller->Implements(ObjectInterfaceType::Programmable));
                 assert(m_controller->Implements(ObjectInterfaceType::ProgramStorage));
@@ -3625,26 +3635,28 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
                 continue;
             }
 
-            if (line->GetCommand() == "EndMissionTake" && !resetObject && m_controller == nullptr)
+            if (line->GetCommand() == "EndMissionTake" && !resetObject)
             {
                 auto endTake = MakeUnique<CSceneEndCondition>();
                 endTake->Read(line.get());
+                if (endTake->immediat)
+                    m_endTakeImmediat = true;
                 m_endTake.push_back(std::move(endTake));
                 continue;
             }
-            if (line->GetCommand() == "EndMissionDelay" && !resetObject && m_controller == nullptr)
+            if (line->GetCommand() == "EndMissionDelay" && !resetObject)
             {
                 m_endTakeWinDelay  = line->GetParam("win")->AsFloat(2.0f);
                 m_endTakeLostDelay = line->GetParam("lost")->AsFloat(2.0f);
                 continue;
             }
-            if (line->GetCommand() == "EndMissionResearch" && !resetObject && m_controller == nullptr) //TODO: Is this used anywhere?
+            if (line->GetCommand() == "EndMissionResearch" && !resetObject) // This is not used in any original Colobot levels, but we'll keep it for userlevel creators
             {
                 m_endTakeResearch |= line->GetParam("type")->AsResearchFlag();
                 continue;
             }
 
-            if (line->GetCommand() == "ObligatoryToken" && !resetObject) //NOTE: This was used only in CeeBot, maybe we should add this to some Colobot exercises?
+            if (line->GetCommand() == "ObligatoryToken" && !resetObject) // NOTE: This was used only in CeeBot, maybe we should add this to some Colobot exercises?
             {
                 int i = m_obligatoryTotal;
                 if (i < 100) //TODO: remove the limit
@@ -3655,7 +3667,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
                 continue;
             }
 
-            if (line->GetCommand() == "ProhibitedToken" && !resetObject) //NOTE: This was used only in CeeBot, maybe we should add this to some Colobot exercises?
+            if (line->GetCommand() == "ProhibitedToken" && !resetObject) // NOTE: This was used only in CeeBot, maybe we should add this to some Colobot exercises?
             {
                 int i = m_prohibitedTotal;
                 if (i < 100) //TODO: remove the limit
@@ -5008,17 +5020,16 @@ void CRobotMain::UpdateAudio(bool frame)
     }
 }
 
-void CRobotMain::SetEndMission(Error result, float delay)
+//! Set mission result from LevelController script
+void CRobotMain::SetMissionResultFromScript(Error result, float delay)
 {
-    if (m_controller != nullptr)
-    {
-        m_endTakeWinDelay = delay;
-        m_endTakeLostDelay = delay;
-        m_missionResult = result;
-    }
+    m_endTakeWinDelay = delay;
+    m_endTakeLostDelay = delay;
+    m_missionResult = result;
+    m_missionResultFromScript = true;
 }
 
-Error CRobotMain::CheckEndMissionForGroup(std::vector<CSceneEndCondition*>& endTakes)
+Error CRobotMain::ProcessEndMissionTakeForGroup(std::vector<CSceneEndCondition*>& endTakes)
 {
     Error finalResult = ERR_OK;
     bool hasWinningConditions = false;
@@ -5045,104 +5056,101 @@ Error CRobotMain::CheckEndMissionForGroup(std::vector<CSceneEndCondition*>& endT
     return finalResult;
 }
 
-//! Checks if the mission is over
-Error CRobotMain::CheckEndMission(bool frame)
+Error CRobotMain::ProcessEndMissionTake()
 {
-    bool isImmediat = false;
-    // Process EndMissionTake, unless we are using MissionController
-    if (m_controller == nullptr)
+    // Sort end conditions by teams
+    std::map<int, std::vector<CSceneEndCondition*>> teams;
+    for (std::unique_ptr<CSceneEndCondition>& endTake : m_endTake)
+        teams[endTake->winTeam].push_back(endTake.get());
+
+    int teamCount = 0;
+    bool usesTeamConditions = false;
+    for (auto it : teams)
     {
-        // Sort end conditions by teams
-        std::map<int, std::vector<CSceneEndCondition*>> teams;
-        for (std::unique_ptr<CSceneEndCondition>& endTake : m_endTake)
-        {
-            teams[endTake->winTeam].push_back(endTake.get());
-            if(endTake->immediat)
-                isImmediat = true;
-        }
+        int team = it.first;
+        if (team == 0) continue;
+        usesTeamConditions = true;
+        if (!m_objMan->TeamExists(team)) continue;
+        teamCount++;
+    }
 
-        int teamCount = 0;
-        bool usesTeamConditions = false;
-        for (auto it : teams)
-        {
-            int team = it.first;
-            if(team == 0) continue;
-            usesTeamConditions = true;
-            if(!m_objMan->TeamExists(team)) continue;
-            teamCount++;
-        }
+    if (!usesTeamConditions)
+    {
+        m_missionResult = ProcessEndMissionTakeForGroup(teams[0]);
+    }
+    else
+    {
+        // Special handling for teams
+        m_missionResult = ERR_MISSION_NOTERM;
 
-        if (!usesTeamConditions)
+        if (teamCount == 0)
         {
-            m_missionResult = CheckEndMissionForGroup(teams[0]);
+            GetLogger()->Info("All teams died, mission ended with failure\n");
+            m_missionResult = INFO_LOST;
         }
         else
         {
-            // Special handling for teams
-            m_missionResult = ERR_MISSION_NOTERM;
-
-            if (teamCount == 0)
+            for (auto it : teams)
             {
-                GetLogger()->Info("All teams died, mission ended with failure\n");
-                m_missionResult = INFO_LOST;
-            }
-            else
-            {
-                for (auto it : teams)
+                int team = it.first;
+                if (team == 0) continue;
+                if (!m_objMan->TeamExists(team)) continue;
+
+                Error result = ProcessEndMissionTakeForGroup(it.second);
+                if (result == INFO_LOST || result == INFO_LOSTq)
                 {
-                    int team = it.first;
-                    if (team == 0) continue;
-                    if (!m_objMan->TeamExists(team)) continue;
+                    GetLogger()->Info("Team %d lost\n", team);
+                    m_displayText->DisplayText(("<<< Team "+boost::lexical_cast<std::string>(team)+" lost! >>>").c_str(), Math::Vector(0.0f,0.0f,0.0f), 15.0f, 60.0f, 10.0f, Ui::TT_ERROR);
 
-                    Error result = CheckEndMissionForGroup(it.second);
-                    if (result == INFO_LOST || result == INFO_LOSTq)
+                    m_displayText->SetEnable(false); // To prevent "bot destroyed" messages
+                    m_objMan->DestroyTeam(team);
+                    m_displayText->SetEnable(true);
+                }
+                else if (result == ERR_OK)
+                {
+                    if (m_winDelay == 0.0f)
                     {
-                        GetLogger()->Info("Team %d lost\n", team);
-                        m_displayText->DisplayText(("<<< Team "+boost::lexical_cast<std::string>(team)+" lost! >>>").c_str(), Math::Vector(0.0f,0.0f,0.0f), 15.0f, 60.0f, 10.0f, Ui::TT_ERROR);
+                        GetLogger()->Info("Team %d won\n", team);
 
-                        m_displayText->SetEnable(false); // To prevent "bot destroyed" messages
-                        m_objMan->DestroyTeam(team);
-                        m_displayText->SetEnable(true);
-                    }
-                    else if(result == ERR_OK)
-                    {
-                        if (m_winDelay == 0.0f)
+                        m_displayText->DisplayText(("<<< Team "+boost::lexical_cast<std::string>(team)+" won the game >>>").c_str(), Math::Vector(0.0f,0.0f,0.0f));
+                        if (m_missionTimerEnabled && m_missionTimerStarted)
                         {
-                            GetLogger()->Info("Team %d won\n", team);
-
-                            m_displayText->DisplayText(("<<< Team "+boost::lexical_cast<std::string>(team)+" won the game >>>").c_str(), Math::Vector(0.0f,0.0f,0.0f));
-                            if (m_missionTimerEnabled && m_missionTimerStarted)
-                            {
-                                GetLogger()->Info("Mission time: %s\n", TimeFormat(m_missionTimer).c_str());
-                                m_displayText->DisplayText(("Time: " + TimeFormat(m_missionTimer)).c_str(), Math::Vector(0.0f,0.0f,0.0f));
-                            }
-                            m_missionTimerEnabled = m_missionTimerStarted = false;
-                            m_winDelay  = m_endTakeWinDelay;  // wins in two seconds
-                            m_lostDelay = 0.0f;
-                            m_displayText->SetEnable(false);
+                            GetLogger()->Info("Mission time: %s\n", TimeFormat(m_missionTimer).c_str());
+                            m_displayText->DisplayText(("Time: " + TimeFormat(m_missionTimer)).c_str(), Math::Vector(0.0f,0.0f,0.0f));
                         }
-                        m_missionResult = ERR_OK;
-                        return ERR_OK;
+                        m_missionTimerEnabled = m_missionTimerStarted = false;
+                        m_winDelay  = m_endTakeWinDelay;  // wins in two seconds
+                        m_lostDelay = 0.0f;
+                        m_displayText->SetEnable(false);
                     }
+                    m_missionResult = ERR_OK;
+                    return ERR_OK;
                 }
             }
         }
+    }
 
-        if (m_missionResult != INFO_LOST && m_missionResult != INFO_LOSTq)
+    if (m_missionResult != INFO_LOST && m_missionResult != INFO_LOSTq)
+    {
+        if (m_endTakeResearch != 0)
         {
-            if (m_endTakeResearch != 0)
+            if (m_endTakeResearch != (m_endTakeResearch&m_researchDone[0]))
             {
-                if (m_endTakeResearch != (m_endTakeResearch&m_researchDone[0]))
-                {
-                    m_missionResult = ERR_MISSION_NOTERM;
-                }
+                m_missionResult = ERR_MISSION_NOTERM;
             }
         }
     }
+}
+
+//! Checks if the mission is over
+Error CRobotMain::CheckEndMission(bool frame)
+{
+    // Process EndMissionTake, unless we are using LevelController script for processing ending conditions
+    if (!m_missionResultFromScript) ProcessEndMissionTake();
 
     // Take action depending on m_missionResult
 
-    if(m_missionResult == INFO_LOSTq)
+    if (m_missionResult == INFO_LOSTq)
     {
         if (m_lostDelay == 0.0f)
         {
@@ -5154,7 +5162,7 @@ Error CRobotMain::CheckEndMission(bool frame)
         return INFO_LOSTq;
     }
 
-    if(m_missionResult == INFO_LOST)
+    if (m_missionResult == INFO_LOST)
     {
         if (m_lostDelay == 0.0f)
         {
@@ -5180,7 +5188,7 @@ Error CRobotMain::CheckEndMission(bool frame)
 
         if (frame)
         {
-            if(m_base != nullptr && !isImmediat)
+            if (m_base != nullptr && !m_endTakeImmediat)
             {
                 assert(m_base->Implements(ObjectInterfaceType::Controllable));
                 if(dynamic_cast<CControllableObject*>(m_base)->GetSelectable())
diff --git a/src/level/robotmain.h b/src/level/robotmain.h
index deea9e8..4f78df3 100644
--- a/src/level/robotmain.h
+++ b/src/level/robotmain.h
@@ -195,9 +195,10 @@ public:
 
     void        ResetObject();
     void        UpdateAudio(bool frame);
-    void        SetEndMission(Error result, float delay);
+    void        SetMissionResultFromScript(Error result, float delay);
     Error       CheckEndMission(bool frame);
-    Error       CheckEndMissionForGroup(std::vector<CSceneEndCondition*>& endTakes);
+    Error       ProcessEndMissionTake();
+    Error       ProcessEndMissionTakeForGroup(std::vector<CSceneEndCondition*>& endTakes);
     int         GetObligatoryToken();
     char*       GetObligatoryToken(int i);
     int         IsObligatoryToken(const char* token);
@@ -543,6 +544,8 @@ protected:
     ActivePause*    m_visitPause = nullptr;
 
     std::vector<std::unique_ptr<CSceneEndCondition>> m_endTake;
+    //! If true, the mission ends immediately after completing the requirements without requiring SpaceShip takeoff
+    bool            m_endTakeImmediat = false;
     long            m_endTakeResearch = 0;
     float           m_endTakeWinDelay = 0.0f;
     float           m_endTakeLostDelay = 0.0f;
@@ -562,6 +565,8 @@ protected:
     std::map<int, int>  m_researchDone;
 
     Error           m_missionResult = ERR_OK;
+    //! true if m_missionResult has been set by LevelController script, this disables normal EndMissionTake processing
+    bool            m_missionResultFromScript = false;
 
     ShowLimit       m_showLimit[MAXSHOWLIMIT];
 
diff --git a/src/level/scene_conditions.h b/src/level/scene_conditions.h
index 33a6508..258cc7e 100644
--- a/src/level/scene_conditions.h
+++ b/src/level/scene_conditions.h
@@ -77,6 +77,7 @@ public:
 
     int lost = -1; // lost if <=
 
+    //! If this is true, the mission ends as soon as this requirement is met, without having to complete the others
     bool immediat = false;
 
     //! Read from line in scene file
diff --git a/src/script/scriptfunc.cpp b/src/script/scriptfunc.cpp
index d072c79..e4da1f1 100644
--- a/src/script/scriptfunc.cpp
+++ b/src/script/scriptfunc.cpp
@@ -204,7 +204,7 @@ bool CScriptFunctions::rEndMission(CBotVar* var, CBotVar* result, int& exception
 
     delay = var->GetValFloat();
 
-    CRobotMain::GetInstancePointer()->SetEndMission(ended, delay);
+    CRobotMain::GetInstancePointer()->SetMissionResultFromScript(ended, delay);
     return true;
 }
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/colobot.git



More information about the Pkg-games-commits mailing list