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
dev-time-step
krzys-h 2016-04-08 20:56:09 +02:00
parent c6c01c332f
commit 4c8da2c503
4 changed files with 123 additions and 109 deletions

View File

@ -1236,8 +1236,12 @@ void CRobotMain::ExecuteCmd(const std::string& cmd)
if (cmd == "controller")
{
if (m_controller != nullptr)
if (m_controller == nullptr)
{
GetLogger()->Error("No LevelController on the map to select\n");
return;
}
// Don't use SelectObject because it checks if the object is selectable
if (m_camera->GetType() == Gfx::CAM_TYPE_VISIT)
StopDisplayVisit();
@ -1248,7 +1252,6 @@ void CRobotMain::ExecuteCmd(const std::string& cmd)
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,20 +3635,22 @@ 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;
@ -5008,17 +5020,16 @@ void CRobotMain::UpdateAudio(bool frame)
}
}
void CRobotMain::SetEndMission(Error result, float delay)
{
if (m_controller != nullptr)
//! Set mission result from LevelController script
void CRobotMain::SetMissionResultFromScript(Error result, float delay)
{
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,21 +5056,12 @@ Error CRobotMain::CheckEndMissionForGroup(std::vector<CSceneEndCondition*>& endT
return finalResult;
}
//! Checks if the mission is over
Error CRobotMain::CheckEndMission(bool frame)
{
bool isImmediat = false;
// Process EndMissionTake, unless we are using MissionController
if (m_controller == nullptr)
Error CRobotMain::ProcessEndMissionTake()
{
// 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 teamCount = 0;
bool usesTeamConditions = false;
@ -5074,7 +5076,7 @@ Error CRobotMain::CheckEndMission(bool frame)
if (!usesTeamConditions)
{
m_missionResult = CheckEndMissionForGroup(teams[0]);
m_missionResult = ProcessEndMissionTakeForGroup(teams[0]);
}
else
{
@ -5094,7 +5096,7 @@ Error CRobotMain::CheckEndMission(bool frame)
if (team == 0) continue;
if (!m_objMan->TeamExists(team)) continue;
Error result = CheckEndMissionForGroup(it.second);
Error result = ProcessEndMissionTakeForGroup(it.second);
if (result == INFO_LOST || result == INFO_LOSTq)
{
GetLogger()->Info("Team %d lost\n", team);
@ -5140,6 +5142,12 @@ Error CRobotMain::CheckEndMission(bool frame)
}
}
//! 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)
@ -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())

View File

@ -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];

View File

@ -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

View File

@ -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;
}