diff --git a/src/level/robotmain.cpp b/src/level/robotmain.cpp index ceb8daa9..441b244d 100644 --- a/src/level/robotmain.cpp +++ b/src/level/robotmain.cpp @@ -2527,6 +2527,8 @@ bool CRobotMain::EventFrame(const Event &event) { CheckEndMission(true); UpdateAudio(true); + if (m_scoreboard) + m_scoreboard->UpdateObjectCount(); } if (m_winDelay > 0.0f && !m_editLock) @@ -3608,6 +3610,15 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) m_scoreboard->AddKillRule(std::move(rule)); continue; } + if (line->GetCommand() == "ScoreboardObjectRule" && !resetObject) + { + if (!m_scoreboard) + throw CLevelParserException("ScoreboardObjectRule encountered but scoreboard is not enabled"); + auto rule = MakeUnique(); + rule->Read(line.get()); + m_scoreboard->AddObjectRule(std::move(rule)); + continue; + } if (line->GetCommand() == "ScoreboardEndTakeRule" && !resetObject) { if (!m_scoreboard) diff --git a/src/level/scene_conditions.cpp b/src/level/scene_conditions.cpp index 3ab32dac..263ee399 100644 --- a/src/level/scene_conditions.cpp +++ b/src/level/scene_conditions.cpp @@ -112,6 +112,18 @@ bool CObjectCondition::CheckForObject(CObject* obj) return false; } +int CObjectCondition::CountObjects() +{ + int nb = 0; + for (CObject* obj : CObjectManager::GetInstancePointer()->GetAllObjects()) + { + if (!obj->GetActive()) continue; + if (!CheckForObject(obj)) continue; + nb ++; + } + return nb; +} + void CSceneCondition::Read(CLevelParserLine* line) { CObjectCondition::Read(line); @@ -124,18 +136,6 @@ void CSceneCondition::Read(CLevelParserLine* line) this->max = line->GetParam("max")->AsInt(9999); } -int CSceneCondition::CountObjects() -{ - int nb = 0; - for (CObject* obj : CObjectManager::GetInstancePointer()->GetAllObjects()) - { - if (!obj->GetActive()) continue; - if (!CheckForObject(obj)) continue; - nb ++; - } - return nb; -} - bool CSceneCondition::Check() { int nb = CountObjects(); diff --git a/src/level/scene_conditions.h b/src/level/scene_conditions.h index 412a45b3..218c668d 100644 --- a/src/level/scene_conditions.h +++ b/src/level/scene_conditions.h @@ -58,6 +58,9 @@ public: //! Checks if this condition is met bool CheckForObject(CObject* obj); + + //! Count all object matching the conditions + int CountObjects(); }; /** @@ -75,10 +78,6 @@ public: //! Checks if this condition is met bool Check(); - -protected: - //! Count all object matching the conditions - int CountObjects(); }; /** diff --git a/src/level/scoreboard.cpp b/src/level/scoreboard.cpp index bfadc4d0..0c2f5d87 100644 --- a/src/level/scoreboard.cpp +++ b/src/level/scoreboard.cpp @@ -43,6 +43,13 @@ void CScoreboard::CScoreboardKillRule::Read(CLevelParserLine* line) CObjectCondition::Read(line); } +void CScoreboard::CScoreboardObjectRule::Read(CLevelParserLine* line) +{ + CScoreboardRule::Read(line); + CObjectCondition::Read(line); + this->winTeam = line->GetParam("winTeam")->AsInt(); +} + void CScoreboard::CScoreboardEndTakeRule::Read(CLevelParserLine* line) { CScoreboardRule::Read(line); @@ -55,6 +62,11 @@ void CScoreboard::AddKillRule(std::unique_ptr rule) m_rulesKill.push_back(std::move(rule)); } +void CScoreboard::AddObjectRule(std::unique_ptr rule) +{ + m_rulesObject.push_back(std::move(rule)); +} + void CScoreboard::AddEndTakeRule(std::unique_ptr rule) { m_rulesEndTake.push_back(std::move(rule)); @@ -75,6 +87,22 @@ void CScoreboard::ProcessKill(CObject* target, CObject* killer) } } +void CScoreboard::UpdateObjectCount() +{ + for (auto& rule : m_rulesObject) + { + assert(rule->winTeam != 0); + int count = rule->CountObjects(); + int countDiff = count - rule->lastCount; + printf("%d %d\n", count, countDiff); + if (countDiff != 0) + { + rule->lastCount = count; + AddPoints(rule->winTeam, rule->score * countDiff); + } + } +} + void CScoreboard::ProcessEndTake(int team) { if (team == 0) return; diff --git a/src/level/scoreboard.h b/src/level/scoreboard.h index 7ed67ad1..313e326c 100644 --- a/src/level/scoreboard.h +++ b/src/level/scoreboard.h @@ -64,6 +64,7 @@ enum class SortType * ScoreboardSortType sort=Name // sort teams alphabetically, another option is sort=Points, sorting teams in order of points * ScoreboardKillRule type=WheeledShooter team=1 score=500 // destruction of team 1's WheeledShooter gives 100 points to the team that destroyed it * ScoreboardKillRule type=TargetBot score=100 // destruction of TargetBot (any team) gives 100 points + * ScoreboardObjectRule pos=0.0;0.5 dist=5.0 type=Titanium winTeam=1 score=5 // each Titanium within 5 meters of 0;0 gives team 1 5 points, losing Titanium gives -5 * ScoreboardEndTakeRule score=1000 // completion of EndMissionTake objectives for any team results in 1000 points for that team * \endcode */ @@ -102,6 +103,22 @@ public: void Read(CLevelParserLine* line) override; }; + /** + * \class CScoreboardObjectRule + * \brief Scoreboard rule for counting objects + * \see CScoreboard::AddObjectRule() + */ + class CScoreboardObjectRule final : public CScoreboardRule, public CObjectCondition + { + public: + int winTeam = 0; + + //! Read from line in scene file + void Read(CLevelParserLine* line) override; + + int lastCount = 0; + }; + /** * \class CScoreboardEndTakeRule * \brief Scoreboard rule for EndMissionTake rewards @@ -120,6 +137,8 @@ public: public: //! Add ScoreboardKillRule void AddKillRule(std::unique_ptr rule); + //! Add ScoreboardObjectRule + void AddObjectRule(std::unique_ptr rule); //! Add ScoreboardEndTakeRule void AddEndTakeRule(std::unique_ptr rule); @@ -127,6 +146,8 @@ public: //! \param target The object that has just been destroyed //! \param killer The object that caused the destruction, can be null void ProcessKill(CObject* target, CObject* killer = nullptr); + //! Updates the object count rules + void UpdateObjectCount(); //! Called after EndTake contition has been met, used to handle ScoreboardEndTakeRule void ProcessEndTake(int team); @@ -139,6 +160,7 @@ public: private: std::vector> m_rulesKill = {}; + std::vector> m_rulesObject = {}; std::vector> m_rulesEndTake = {}; std::map m_score; int m_finishCounter = 0;