Add basics of scoreboard implementation; better support for multiple teams
parent
6cd72543c4
commit
880f31a7c6
|
@ -241,6 +241,8 @@ set(BASE_SOURCES
|
||||||
level/robotmain.h
|
level/robotmain.h
|
||||||
level/scene_conditions.cpp
|
level/scene_conditions.cpp
|
||||||
level/scene_conditions.h
|
level/scene_conditions.h
|
||||||
|
level/scoreboard.cpp
|
||||||
|
level/scoreboard.h
|
||||||
math/all.h
|
math/all.h
|
||||||
math/const.h
|
math/const.h
|
||||||
math/func.h
|
math/func.h
|
||||||
|
|
|
@ -131,7 +131,7 @@ bool CLightning::EventFrame(const Event &event)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
assert(obj->Implements(ObjectInterfaceType::Destroyable));
|
assert(obj->Implements(ObjectInterfaceType::Destroyable));
|
||||||
dynamic_cast<CDestroyableObject*>(obj)->DamageObject(DamageType::Lightning);
|
dynamic_cast<CDestroyableObject*>(obj)->DamageObject(DamageType::Lightning, std::numeric_limits<float>::infinity());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -954,7 +954,7 @@ void CParticle::FrameParticle(float rTime)
|
||||||
m_particle[i].goal = m_particle[i].pos;
|
m_particle[i].goal = m_particle[i].pos;
|
||||||
if (object != nullptr && object->Implements(ObjectInterfaceType::Damageable))
|
if (object != nullptr && object->Implements(ObjectInterfaceType::Damageable))
|
||||||
{
|
{
|
||||||
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Phazer, 0.002f);
|
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Phazer, 0.002f, m_particle[i].objFather);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_particle[i].zoom = 1.0f-(m_particle[i].time-m_particle[i].duration);
|
m_particle[i].zoom = 1.0f-(m_particle[i].time-m_particle[i].duration);
|
||||||
|
@ -1157,7 +1157,7 @@ void CParticle::FrameParticle(float rTime)
|
||||||
{
|
{
|
||||||
if (object->Implements(ObjectInterfaceType::Damageable))
|
if (object->Implements(ObjectInterfaceType::Damageable))
|
||||||
{
|
{
|
||||||
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Fire, 0.001f);
|
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Fire, 0.001f, m_particle[i].objFather);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_exploGunCounter++;
|
m_exploGunCounter++;
|
||||||
|
@ -1241,7 +1241,7 @@ void CParticle::FrameParticle(float rTime)
|
||||||
|
|
||||||
if (object->Implements(ObjectInterfaceType::Damageable))
|
if (object->Implements(ObjectInterfaceType::Damageable))
|
||||||
{
|
{
|
||||||
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Organic, 0.1f); // starts explosion
|
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Organic, 0.1f, m_particle[i].objFather); // starts explosion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1286,7 +1286,7 @@ void CParticle::FrameParticle(float rTime)
|
||||||
{
|
{
|
||||||
if (object->Implements(ObjectInterfaceType::Damageable))
|
if (object->Implements(ObjectInterfaceType::Damageable))
|
||||||
{
|
{
|
||||||
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Fire); // starts explosion
|
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Fire, std::numeric_limits<float>::infinity(), m_particle[i].objFather); // starts explosion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1345,7 +1345,7 @@ void CParticle::FrameParticle(float rTime)
|
||||||
{
|
{
|
||||||
if (object->Implements(ObjectInterfaceType::Damageable))
|
if (object->Implements(ObjectInterfaceType::Damageable))
|
||||||
{
|
{
|
||||||
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Organic, 0.001f);
|
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Organic, 0.001f, m_particle[i].objFather);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_exploGunCounter ++;
|
m_exploGunCounter ++;
|
||||||
|
@ -2423,7 +2423,7 @@ void CParticle::FrameParticle(float rTime)
|
||||||
if (object != nullptr)
|
if (object != nullptr)
|
||||||
{
|
{
|
||||||
assert(object->Implements(ObjectInterfaceType::Damageable));
|
assert(object->Implements(ObjectInterfaceType::Damageable));
|
||||||
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Tower);
|
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Tower, std::numeric_limits<float>::infinity(), m_particle[i].objFather);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2296,6 +2296,7 @@ void CPyro::FallProgress(float rTime)
|
||||||
if (floor) // reaches the ground?
|
if (floor) // reaches the ground?
|
||||||
{
|
{
|
||||||
assert(m_object->Implements(ObjectInterfaceType::Destroyable));
|
assert(m_object->Implements(ObjectInterfaceType::Destroyable));
|
||||||
|
// TODO: implement "killer"?
|
||||||
dynamic_cast<CDestroyableObject*>(m_object)->DestroyObject(DestructionType::Explosion);
|
dynamic_cast<CDestroyableObject*>(m_object)->DestroyObject(DestructionType::Explosion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2319,6 +2320,7 @@ void CPyro::FallProgress(float rTime)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
assert(m_object->Implements(ObjectInterfaceType::Destroyable));
|
assert(m_object->Implements(ObjectInterfaceType::Destroyable));
|
||||||
|
// TODO: implement "killer"?
|
||||||
dynamic_cast<CDestroyableObject*>(m_object)->DestroyObject(DestructionType::Explosion);
|
dynamic_cast<CDestroyableObject*>(m_object)->DestroyObject(DestructionType::Explosion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,7 @@
|
||||||
#include "level/mainmovie.h"
|
#include "level/mainmovie.h"
|
||||||
#include "level/player_profile.h"
|
#include "level/player_profile.h"
|
||||||
#include "level/scene_conditions.h"
|
#include "level/scene_conditions.h"
|
||||||
|
#include "level/scoreboard.h"
|
||||||
|
|
||||||
#include "level/parser/parser.h"
|
#include "level/parser/parser.h"
|
||||||
|
|
||||||
|
@ -2518,7 +2519,7 @@ bool CRobotMain::EventFrame(const Event &event)
|
||||||
|
|
||||||
if (m_phase == PHASE_SIMUL)
|
if (m_phase == PHASE_SIMUL)
|
||||||
{
|
{
|
||||||
if (!m_editLock)
|
if (!m_editLock && !m_engine->GetPause())
|
||||||
{
|
{
|
||||||
CheckEndMission(true);
|
CheckEndMission(true);
|
||||||
UpdateAudio(true);
|
UpdateAudio(true);
|
||||||
|
@ -2695,6 +2696,8 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
|
||||||
m_endTakeResearch = 0;
|
m_endTakeResearch = 0;
|
||||||
m_endTakeWinDelay = 2.0f;
|
m_endTakeWinDelay = 2.0f;
|
||||||
m_endTakeLostDelay = 2.0f;
|
m_endTakeLostDelay = 2.0f;
|
||||||
|
m_teamFinished.clear();
|
||||||
|
m_scoreboard.reset();
|
||||||
m_globalMagnifyDamage = 1.0f;
|
m_globalMagnifyDamage = 1.0f;
|
||||||
m_obligatoryTokens.clear();
|
m_obligatoryTokens.clear();
|
||||||
m_mapShow = true;
|
m_mapShow = true;
|
||||||
|
@ -3552,6 +3555,34 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (line->GetCommand() == "Scoreboard" && !resetObject)
|
||||||
|
{
|
||||||
|
if (line->GetParam("enable")->AsBool(false))
|
||||||
|
{
|
||||||
|
// Create the scoreboard
|
||||||
|
m_scoreboard = MakeUnique<CScoreboard>();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (line->GetCommand() == "ScoreboardKillRule" && !resetObject)
|
||||||
|
{
|
||||||
|
if (!m_scoreboard)
|
||||||
|
throw CLevelParserException("ScoreboardKillRule encountered but scoreboard is not enabled");
|
||||||
|
auto rule = MakeUnique<CScoreboard::CScoreboardKillRule>();
|
||||||
|
rule->Read(line.get());
|
||||||
|
m_scoreboard->AddKillRule(std::move(rule));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (line->GetCommand() == "ScoreboardEndTakeRule" && !resetObject)
|
||||||
|
{
|
||||||
|
if (!m_scoreboard)
|
||||||
|
throw CLevelParserException("ScoreboardEndTakeRule encountered but scoreboard is not enabled");
|
||||||
|
auto rule = MakeUnique<CScoreboard::CScoreboardEndTakeRule>();
|
||||||
|
rule->Read(line.get());
|
||||||
|
m_scoreboard->AddEndTakeRule(std::move(rule));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (line->GetCommand() == "ObligatoryToken" && !resetObject)
|
if (line->GetCommand() == "ObligatoryToken" && !resetObject)
|
||||||
{
|
{
|
||||||
std::string token = line->GetParam("text")->AsString();
|
std::string token = line->GetParam("text")->AsString();
|
||||||
|
@ -4909,7 +4940,7 @@ Error CRobotMain::ProcessEndMissionTake()
|
||||||
int team = it.first;
|
int team = it.first;
|
||||||
if (team == 0) continue;
|
if (team == 0) continue;
|
||||||
usesTeamConditions = true;
|
usesTeamConditions = true;
|
||||||
if (!m_objMan->TeamExists(team)) continue;
|
if (m_teamFinished[team]) continue;
|
||||||
teamCount++;
|
teamCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4924,8 +4955,32 @@ Error CRobotMain::ProcessEndMissionTake()
|
||||||
|
|
||||||
if (teamCount == 0)
|
if (teamCount == 0)
|
||||||
{
|
{
|
||||||
GetLogger()->Info("All teams died, mission ended with failure\n");
|
GetLogger()->Info("All teams died, mission ended\n");
|
||||||
m_missionResult = INFO_LOST;
|
if (m_scoreboard)
|
||||||
|
{
|
||||||
|
std::string details = "";
|
||||||
|
for (auto it : teams)
|
||||||
|
{
|
||||||
|
int team = it.first;
|
||||||
|
if (team == 0) continue;
|
||||||
|
details += "Team "+boost::lexical_cast<std::string>(team)+": "+boost::lexical_cast<std::string>(m_scoreboard->GetScore(team))+" points\n";
|
||||||
|
}
|
||||||
|
m_ui->GetDialog()->StartInformation(
|
||||||
|
"Results",
|
||||||
|
"The battle has ended",
|
||||||
|
details,
|
||||||
|
false, true,
|
||||||
|
[&]() {
|
||||||
|
ChangePhase(PHASE_WIN);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
m_endTakeWinDelay = 0.0f;
|
||||||
|
m_missionResult = ERR_OK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_missionResult = INFO_LOST;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -4933,7 +4988,7 @@ Error CRobotMain::ProcessEndMissionTake()
|
||||||
{
|
{
|
||||||
int team = it.first;
|
int team = it.first;
|
||||||
if (team == 0) continue;
|
if (team == 0) continue;
|
||||||
if (!m_objMan->TeamExists(team)) continue;
|
if (m_teamFinished[team]) continue;
|
||||||
|
|
||||||
Error result = ProcessEndMissionTakeForGroup(it.second);
|
Error result = ProcessEndMissionTakeForGroup(it.second);
|
||||||
if (result == INFO_LOST || result == INFO_LOSTq)
|
if (result == INFO_LOST || result == INFO_LOSTq)
|
||||||
|
@ -4944,10 +4999,12 @@ Error CRobotMain::ProcessEndMissionTake()
|
||||||
m_displayText->SetEnable(false); // To prevent "bot destroyed" messages
|
m_displayText->SetEnable(false); // To prevent "bot destroyed" messages
|
||||||
m_objMan->DestroyTeam(team);
|
m_objMan->DestroyTeam(team);
|
||||||
m_displayText->SetEnable(true);
|
m_displayText->SetEnable(true);
|
||||||
|
|
||||||
|
m_teamFinished[team] = true;
|
||||||
}
|
}
|
||||||
else if (result == ERR_OK)
|
else if (result == ERR_OK)
|
||||||
{
|
{
|
||||||
if (m_winDelay == 0.0f)
|
/*if (m_winDelay == 0.0f)
|
||||||
{
|
{
|
||||||
GetLogger()->Info("Team %d won\n", team);
|
GetLogger()->Info("Team %d won\n", team);
|
||||||
|
|
||||||
|
@ -4963,7 +5020,13 @@ Error CRobotMain::ProcessEndMissionTake()
|
||||||
m_displayText->SetEnable(false);
|
m_displayText->SetEnable(false);
|
||||||
}
|
}
|
||||||
m_missionResult = ERR_OK;
|
m_missionResult = ERR_OK;
|
||||||
return ERR_OK;
|
return ERR_OK;*/
|
||||||
|
GetLogger()->Info("Team %d finished\n", team);
|
||||||
|
m_displayText->DisplayText(("<<< Team "+boost::lexical_cast<std::string>(team)+" finished >>>").c_str(), Math::Vector(0.0f,0.0f,0.0f));
|
||||||
|
if (m_scoreboard)
|
||||||
|
m_scoreboard->ProcessEndTake(team);
|
||||||
|
m_objMan->DestroyTeam(team, DestructionType::Win);
|
||||||
|
m_teamFinished[team] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5817,3 +5880,8 @@ std::string CRobotMain::GetPreviousFromCommandHistory()
|
||||||
return "";
|
return "";
|
||||||
return m_commandHistory[--m_commandHistoryIndex];
|
return m_commandHistory[--m_commandHistoryIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CScoreboard* CRobotMain::GetScoreboard()
|
||||||
|
{
|
||||||
|
return m_scoreboard.get();
|
||||||
|
}
|
||||||
|
|
|
@ -87,6 +87,7 @@ class CInput;
|
||||||
class CObjectManager;
|
class CObjectManager;
|
||||||
class CSceneEndCondition;
|
class CSceneEndCondition;
|
||||||
class CAudioChangeCondition;
|
class CAudioChangeCondition;
|
||||||
|
class CScoreboard;
|
||||||
class CPlayerProfile;
|
class CPlayerProfile;
|
||||||
class CSettings;
|
class CSettings;
|
||||||
class COldObject;
|
class COldObject;
|
||||||
|
@ -307,6 +308,10 @@ public:
|
||||||
//! Return list of scripts to load to robot created in BotFactory
|
//! Return list of scripts to load to robot created in BotFactory
|
||||||
std::vector<std::string> GetNewScriptNames(ObjectType type);
|
std::vector<std::string> GetNewScriptNames(ObjectType type);
|
||||||
|
|
||||||
|
//! Return the scoreboard manager
|
||||||
|
//! Note: this may return nullptr if the scoreboard is not enabled!
|
||||||
|
CScoreboard* GetScoreboard();
|
||||||
|
|
||||||
void SelectPlayer(std::string playerName);
|
void SelectPlayer(std::string playerName);
|
||||||
CPlayerProfile* GetPlayerProfile();
|
CPlayerProfile* GetPlayerProfile();
|
||||||
|
|
||||||
|
@ -655,9 +660,15 @@ protected:
|
||||||
long m_endTakeResearch = 0;
|
long m_endTakeResearch = 0;
|
||||||
float m_endTakeWinDelay = 0.0f;
|
float m_endTakeWinDelay = 0.0f;
|
||||||
float m_endTakeLostDelay = 0.0f;
|
float m_endTakeLostDelay = 0.0f;
|
||||||
|
//! Set to true for teams that have already finished
|
||||||
|
std::map<int, bool> m_teamFinished;
|
||||||
|
|
||||||
std::vector<std::unique_ptr<CAudioChangeCondition>> m_audioChange;
|
std::vector<std::unique_ptr<CAudioChangeCondition>> m_audioChange;
|
||||||
|
|
||||||
|
//! The scoreboard
|
||||||
|
//! If the scoreboard is not enabled for this level, this will be null
|
||||||
|
std::unique_ptr<CScoreboard> m_scoreboard;
|
||||||
|
|
||||||
std::map<std::string, MinMax> m_obligatoryTokens;
|
std::map<std::string, MinMax> m_obligatoryTokens;
|
||||||
|
|
||||||
//! Enabled buildings
|
//! Enabled buildings
|
||||||
|
|
|
@ -29,11 +29,13 @@
|
||||||
#include "object/interface/powered_object.h"
|
#include "object/interface/powered_object.h"
|
||||||
#include "object/interface/transportable_object.h"
|
#include "object/interface/transportable_object.h"
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
void CSceneCondition::Read(CLevelParserLine* line)
|
|
||||||
|
void CObjectCondition::Read(CLevelParserLine* line)
|
||||||
{
|
{
|
||||||
this->pos = line->GetParam("pos")->AsPoint(Math::Vector(0.0f, 0.0f, 0.0f))*g_unit;
|
this->pos = line->GetParam("pos")->AsPoint(Math::Vector(0.0f, 0.0f, 0.0f))*g_unit;
|
||||||
this->dist = line->GetParam("dist")->AsFloat(8.0f)*g_unit;
|
this->dist = line->GetParam("dist")->AsFloat(std::numeric_limits<float>::infinity())*g_unit;
|
||||||
this->type = line->GetParam("type")->AsObjectType(OBJECT_NULL);
|
this->type = line->GetParam("type")->AsObjectType(OBJECT_NULL);
|
||||||
this->powermin = line->GetParam("powermin")->AsFloat(-1);
|
this->powermin = line->GetParam("powermin")->AsFloat(-1);
|
||||||
this->powermax = line->GetParam("powermax")->AsFloat(100);
|
this->powermax = line->GetParam("powermax")->AsFloat(100);
|
||||||
|
@ -41,6 +43,82 @@ void CSceneCondition::Read(CLevelParserLine* line)
|
||||||
this->drive = line->GetParam("drive")->AsDriveType(DriveType::Other);
|
this->drive = line->GetParam("drive")->AsDriveType(DriveType::Other);
|
||||||
this->countTransported = line->GetParam("countTransported")->AsBool(true);
|
this->countTransported = line->GetParam("countTransported")->AsBool(true);
|
||||||
this->team = line->GetParam("team")->AsInt(0);
|
this->team = line->GetParam("team")->AsInt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CObjectCondition::CheckForObject(CObject* obj)
|
||||||
|
{
|
||||||
|
if (!this->countTransported)
|
||||||
|
{
|
||||||
|
if (IsObjectBeingTransported(obj)) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectType type = obj->GetType();
|
||||||
|
|
||||||
|
ToolType tool = GetToolFromObject(type);
|
||||||
|
DriveType drive = GetDriveFromObject(type);
|
||||||
|
if (this->tool != ToolType::Other &&
|
||||||
|
tool != this->tool)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (this->drive != DriveType::Other &&
|
||||||
|
drive != this->drive)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (this->tool == ToolType::Other &&
|
||||||
|
this->drive == DriveType::Other &&
|
||||||
|
type != this->type &&
|
||||||
|
this->type != OBJECT_NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ((this->team > 0 && obj->GetTeam() != this->team) ||
|
||||||
|
(this->team < 0 && (obj->GetTeam() == -(this->team) || obj->GetTeam() == 0)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
float energyLevel = -1;
|
||||||
|
CPowerContainerObject* power = nullptr;
|
||||||
|
if (obj->Implements(ObjectInterfaceType::PowerContainer))
|
||||||
|
{
|
||||||
|
power = dynamic_cast<CPowerContainerObject*>(obj);
|
||||||
|
}
|
||||||
|
else if (obj->Implements(ObjectInterfaceType::Powered))
|
||||||
|
{
|
||||||
|
CObject* powerObj = dynamic_cast<CPoweredObject*>(obj)->GetPower();
|
||||||
|
if(powerObj != nullptr && powerObj->Implements(ObjectInterfaceType::PowerContainer))
|
||||||
|
{
|
||||||
|
power = dynamic_cast<CPowerContainerObject*>(powerObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (power != nullptr)
|
||||||
|
{
|
||||||
|
energyLevel = power->GetEnergy();
|
||||||
|
if (power->GetCapacity() > 1.0f) energyLevel *= 10; // TODO: Who designed it like that ?!?!
|
||||||
|
}
|
||||||
|
if (energyLevel < this->powermin || energyLevel > this->powermax) return false;
|
||||||
|
|
||||||
|
Math::Vector oPos;
|
||||||
|
if (IsObjectBeingTransported(obj))
|
||||||
|
oPos = dynamic_cast<CTransportableObject*>(obj)->GetTransporter()->GetPosition();
|
||||||
|
else
|
||||||
|
oPos = obj->GetPosition();
|
||||||
|
oPos.y = 0.0f;
|
||||||
|
|
||||||
|
Math::Vector bPos = this->pos;
|
||||||
|
bPos.y = 0.0f;
|
||||||
|
|
||||||
|
if (Math::DistanceProjected(oPos, bPos) <= this->dist)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSceneCondition::Read(CLevelParserLine* line)
|
||||||
|
{
|
||||||
|
CObjectCondition::Read(line);
|
||||||
|
|
||||||
|
// Scene conditions STILL use a different default value
|
||||||
|
// See issue #759
|
||||||
|
this->dist = line->GetParam("dist")->AsFloat(8.0f)*g_unit;
|
||||||
|
|
||||||
this->min = line->GetParam("min")->AsInt(1);
|
this->min = line->GetParam("min")->AsInt(1);
|
||||||
this->max = line->GetParam("max")->AsInt(9999);
|
this->max = line->GetParam("max")->AsInt(9999);
|
||||||
|
@ -48,74 +126,12 @@ void CSceneCondition::Read(CLevelParserLine* line)
|
||||||
|
|
||||||
int CSceneCondition::CountObjects()
|
int CSceneCondition::CountObjects()
|
||||||
{
|
{
|
||||||
Math::Vector bPos = this->pos;
|
|
||||||
bPos.y = 0.0f;
|
|
||||||
|
|
||||||
Math::Vector oPos;
|
|
||||||
|
|
||||||
int nb = 0;
|
int nb = 0;
|
||||||
for (CObject* obj : CObjectManager::GetInstancePointer()->GetAllObjects())
|
for (CObject* obj : CObjectManager::GetInstancePointer()->GetAllObjects())
|
||||||
{
|
{
|
||||||
if (!obj->GetActive()) continue;
|
if (!obj->GetActive()) continue;
|
||||||
|
if (!CheckForObject(obj)) continue;
|
||||||
if (!this->countTransported)
|
nb ++;
|
||||||
{
|
|
||||||
if (IsObjectBeingTransported(obj)) continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjectType type = obj->GetType();
|
|
||||||
|
|
||||||
ToolType tool = GetToolFromObject(type);
|
|
||||||
DriveType drive = GetDriveFromObject(type);
|
|
||||||
if (this->tool != ToolType::Other &&
|
|
||||||
tool != this->tool)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (this->drive != DriveType::Other &&
|
|
||||||
drive != this->drive)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (this->tool == ToolType::Other &&
|
|
||||||
this->drive == DriveType::Other &&
|
|
||||||
type != this->type &&
|
|
||||||
this->type != OBJECT_NULL)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if ((this->team > 0 && obj->GetTeam() != this->team) ||
|
|
||||||
(this->team < 0 && (obj->GetTeam() == -(this->team) || obj->GetTeam() == 0)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
float energyLevel = -1;
|
|
||||||
CPowerContainerObject* power = nullptr;
|
|
||||||
if (obj->Implements(ObjectInterfaceType::PowerContainer))
|
|
||||||
{
|
|
||||||
power = dynamic_cast<CPowerContainerObject*>(obj);
|
|
||||||
}
|
|
||||||
else if (obj->Implements(ObjectInterfaceType::Powered))
|
|
||||||
{
|
|
||||||
CObject* powerObj = dynamic_cast<CPoweredObject*>(obj)->GetPower();
|
|
||||||
if(powerObj != nullptr && powerObj->Implements(ObjectInterfaceType::PowerContainer))
|
|
||||||
{
|
|
||||||
power = dynamic_cast<CPowerContainerObject*>(powerObj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (power != nullptr)
|
|
||||||
{
|
|
||||||
energyLevel = power->GetEnergy();
|
|
||||||
if (power->GetCapacity() > 1.0f) energyLevel *= 10; // TODO: Who designed it like that ?!?!
|
|
||||||
}
|
|
||||||
if (energyLevel < this->powermin || energyLevel > this->powermax) continue;
|
|
||||||
|
|
||||||
if (IsObjectBeingTransported(obj))
|
|
||||||
oPos = dynamic_cast<CTransportableObject*>(obj)->GetTransporter()->GetPosition();
|
|
||||||
else
|
|
||||||
oPos = obj->GetPosition();
|
|
||||||
|
|
||||||
oPos.y = 0.0f;
|
|
||||||
|
|
||||||
if (Math::DistanceProjected(oPos, bPos) <= this->dist)
|
|
||||||
nb ++;
|
|
||||||
}
|
}
|
||||||
return nb;
|
return nb;
|
||||||
}
|
}
|
||||||
|
@ -126,7 +142,6 @@ bool CSceneCondition::Check()
|
||||||
return nb >= this->min && nb <= this->max;
|
return nb >= this->min && nb <= this->max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CSceneEndCondition::Read(CLevelParserLine* line)
|
void CSceneEndCondition::Read(CLevelParserLine* line)
|
||||||
{
|
{
|
||||||
CSceneCondition::Read(line);
|
CSceneCondition::Read(line);
|
||||||
|
|
|
@ -34,12 +34,13 @@
|
||||||
#include "object/tool_type.h"
|
#include "object/tool_type.h"
|
||||||
|
|
||||||
class CLevelParserLine;
|
class CLevelParserLine;
|
||||||
|
class CObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \class CSceneCondition
|
* \class CObjectCondition
|
||||||
* \brief Base scene condition structure
|
* \brief Base object condition structure
|
||||||
*/
|
*/
|
||||||
class CSceneCondition
|
class CObjectCondition
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Math::Vector pos = Math::Vector(0.0f, 0.0f, 0.0f)*g_unit;
|
Math::Vector pos = Math::Vector(0.0f, 0.0f, 0.0f)*g_unit;
|
||||||
|
@ -52,11 +53,25 @@ public:
|
||||||
bool countTransported = true;
|
bool countTransported = true;
|
||||||
int team = 0;
|
int team = 0;
|
||||||
|
|
||||||
|
//! Read from line in scene file
|
||||||
|
virtual void Read(CLevelParserLine* line);
|
||||||
|
|
||||||
|
//! Checks if this condition is met
|
||||||
|
bool CheckForObject(CObject* obj);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class CSceneCondition
|
||||||
|
* \brief Base scene condition structure
|
||||||
|
*/
|
||||||
|
class CSceneCondition : public CObjectCondition
|
||||||
|
{
|
||||||
|
public:
|
||||||
int min = 1; // wins if >
|
int min = 1; // wins if >
|
||||||
int max = 9999; // wins if <
|
int max = 9999; // wins if <
|
||||||
|
|
||||||
//! Read from line in scene file
|
//! Read from line in scene file
|
||||||
virtual void Read(CLevelParserLine* line);
|
void Read(CLevelParserLine* line) override;
|
||||||
|
|
||||||
//! Checks if this condition is met
|
//! Checks if this condition is met
|
||||||
bool Check();
|
bool Check();
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the Colobot: Gold Edition source code
|
||||||
|
* Copyright (C) 2001-2017, Daniel Roux, EPSITEC SA & TerranovaTeam
|
||||||
|
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see http://gnu.org/licenses
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "level/scoreboard.h"
|
||||||
|
|
||||||
|
#include "level/parser/parserline.h"
|
||||||
|
|
||||||
|
#include "level/robotmain.h"
|
||||||
|
|
||||||
|
#include "object/object.h"
|
||||||
|
|
||||||
|
#include "ui/displaytext.h"
|
||||||
|
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
|
|
||||||
|
void CScoreboard::CScoreboardRule::Read(CLevelParserLine* line)
|
||||||
|
{
|
||||||
|
this->score = line->GetParam("score")->AsInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CScoreboard::CScoreboardKillRule::Read(CLevelParserLine* line)
|
||||||
|
{
|
||||||
|
CScoreboardRule::Read(line);
|
||||||
|
CObjectCondition::Read(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CScoreboard::CScoreboardEndTakeRule::Read(CLevelParserLine* line)
|
||||||
|
{
|
||||||
|
CScoreboardRule::Read(line);
|
||||||
|
this->team = line->GetParam("team")->AsInt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CScoreboard::AddKillRule(std::unique_ptr<CScoreboardKillRule> rule)
|
||||||
|
{
|
||||||
|
m_rulesKill.push_back(std::move(rule));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CScoreboard::AddEndTakeRule(std::unique_ptr<CScoreboardEndTakeRule> rule)
|
||||||
|
{
|
||||||
|
m_rulesEndTake.push_back(std::move(rule));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CScoreboard::ProcessKill(CObject* target, CObject* killer)
|
||||||
|
{
|
||||||
|
if (killer == nullptr) return;
|
||||||
|
if (killer->GetTeam() == 0) return;
|
||||||
|
for (auto& rule : m_rulesKill)
|
||||||
|
{
|
||||||
|
if ((rule->team == killer->GetTeam() || rule->team == 0) &&
|
||||||
|
rule->CheckForObject(target))
|
||||||
|
{
|
||||||
|
AddPoints(killer->GetTeam(), rule->score);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CScoreboard::ProcessEndTake(int team)
|
||||||
|
{
|
||||||
|
for (auto& rule : m_rulesEndTake)
|
||||||
|
{
|
||||||
|
if (rule->team == team || rule->team == 0)
|
||||||
|
{
|
||||||
|
AddPoints(team, rule->score);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CScoreboard::AddPoints(int team, int points)
|
||||||
|
{
|
||||||
|
GetLogger()->Info("Team %d earned %d points\n", team, points);
|
||||||
|
CRobotMain::GetInstancePointer()->GetDisplayText()->DisplayText(("<<< Team "+boost::lexical_cast<std::string>(team)+" recieved "+boost::lexical_cast<std::string>(points)+" points! >>>").c_str(), Math::Vector(0.0f,0.0f,0.0f), 15.0f, 60.0f, 10.0f, Ui::TT_WARNING);
|
||||||
|
m_score[team] += points;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CScoreboard::GetScore(int team)
|
||||||
|
{
|
||||||
|
return m_score[team];
|
||||||
|
}
|
|
@ -0,0 +1,120 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the Colobot: Gold Edition source code
|
||||||
|
* Copyright (C) 2001-2017, Daniel Roux, EPSITEC SA & TerranovaTeam
|
||||||
|
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see http://gnu.org/licenses
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file level/scoreboard.h
|
||||||
|
* \brief Code responsible for managing the scoreboard used to score complex code battles
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "level/scene_conditions.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
class CObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class CScoreboard
|
||||||
|
* \brief Scoreboard used to score complex code battles
|
||||||
|
*
|
||||||
|
* \todo This is pretty much a work-in-progress hack for Diversity. Be wary of possible API changes.
|
||||||
|
*
|
||||||
|
* \todo Proper documentation
|
||||||
|
*
|
||||||
|
* \see CRobotMain::GetScoreboard()
|
||||||
|
*
|
||||||
|
* \section example Usage example
|
||||||
|
* \code{.scene}
|
||||||
|
* Scoreboard enable=true // enable the scoreboard
|
||||||
|
* 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
|
||||||
|
* ScoreboardEndTakeRule score=1000 // completion of EndMissionTake objectives for any team results in 1000 points for that team
|
||||||
|
* \endcode
|
||||||
|
*/
|
||||||
|
class CScoreboard
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//! Creates the scoreboard
|
||||||
|
//! The scoreboard exists only if enabled in level file
|
||||||
|
CScoreboard() {};
|
||||||
|
//! Destroys the scoreboard
|
||||||
|
~CScoreboard() {};
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* \class CScoreboardRule
|
||||||
|
* \brief Base class for scoreboard rules
|
||||||
|
*/
|
||||||
|
class CScoreboardRule
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int score = 0;
|
||||||
|
|
||||||
|
//! Read from line in scene file
|
||||||
|
virtual void Read(CLevelParserLine* line);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class CScoreboardKillRule
|
||||||
|
* \brief Scoreboard rule for destroying other objects
|
||||||
|
* \see CScoreboard::AddKillRule()
|
||||||
|
*/
|
||||||
|
class CScoreboardKillRule : public CScoreboardRule, public CObjectCondition
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//! Read from line in scene file
|
||||||
|
void Read(CLevelParserLine* line) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class CScoreboardEndTakeRule
|
||||||
|
* \brief Scoreboard rule for EndMissionTake rewards
|
||||||
|
* \see CScoreboard::AddEndTakeRule()
|
||||||
|
*/
|
||||||
|
class CScoreboardEndTakeRule : public CScoreboardRule
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int team = 0;
|
||||||
|
|
||||||
|
//! Read from line in scene file
|
||||||
|
void Read(CLevelParserLine* line) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
void AddKillRule(std::unique_ptr<CScoreboardKillRule> rule);
|
||||||
|
void AddEndTakeRule(std::unique_ptr<CScoreboardEndTakeRule> rule);
|
||||||
|
|
||||||
|
//! Called after an object is destroyed by another object
|
||||||
|
//! \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);
|
||||||
|
//! Called after EndTake contition has been met, used to handle ScoreboardEndTakeRule
|
||||||
|
void ProcessEndTake(int team);
|
||||||
|
|
||||||
|
void AddPoints(int team, int points);
|
||||||
|
int GetScore(int team);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::unique_ptr<CScoreboardKillRule>> m_rulesKill = {};
|
||||||
|
std::vector<std::unique_ptr<CScoreboardEndTakeRule>> m_rulesEndTake = {};
|
||||||
|
std::map<int, int> m_score;
|
||||||
|
};
|
|
@ -23,6 +23,8 @@
|
||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
|
class CObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \enum DamageType
|
* \enum DamageType
|
||||||
* \brief Type of damage, for use in CDamageableObject::DamageObject
|
* \brief Type of damage, for use in CDamageableObject::DamageObject
|
||||||
|
@ -56,5 +58,5 @@ public:
|
||||||
|
|
||||||
//! Damage the object, with the given force. Returns true if the object has been fully destroyed (assuming the object is destroyable, of course). If force == infinity, destroy immediately (this is the default value)
|
//! Damage the object, with the given force. Returns true if the object has been fully destroyed (assuming the object is destroyable, of course). If force == infinity, destroy immediately (this is the default value)
|
||||||
/** NOTE: You should never assume that after this function exits, the object is destroyed, unless it returns true. Even if you specify force = infinity, if may still sometimes decide not to destroy the object. */
|
/** NOTE: You should never assume that after this function exits, the object is destroyed, unless it returns true. Even if you specify force = infinity, if may still sometimes decide not to destroy the object. */
|
||||||
virtual bool DamageObject(DamageType type, float force = std::numeric_limits<float>::infinity()) = 0;
|
virtual bool DamageObject(DamageType type, float force = std::numeric_limits<float>::infinity(), CObject* killer = nullptr) = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -32,6 +32,7 @@ enum class DestructionType
|
||||||
ExplosionWater = 2, //!< explosion underwater
|
ExplosionWater = 2, //!< explosion underwater
|
||||||
Burn = 3, //!< burning
|
Burn = 3, //!< burning
|
||||||
Drowned = 4, //!< drowned (only for Me)
|
Drowned = 4, //!< drowned (only for Me)
|
||||||
|
Win = 5, //!< used when removing objects from a team that won
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -65,7 +66,7 @@ public:
|
||||||
|
|
||||||
//! Destroy the object immediately. Use this only if you are 100% sure this is what you want, because object with magnifyDamage=0 should be able to bypass all damage. It's recommended to use CDamageableObject::DamageObject() instead.
|
//! Destroy the object immediately. Use this only if you are 100% sure this is what you want, because object with magnifyDamage=0 should be able to bypass all damage. It's recommended to use CDamageableObject::DamageObject() instead.
|
||||||
/** NOTE: After this function exits, you can assume the object has been definetly destroyed */
|
/** NOTE: After this function exits, you can assume the object has been definetly destroyed */
|
||||||
virtual void DestroyObject(DestructionType type) = 0;
|
virtual void DestroyObject(DestructionType type, CObject* killer = nullptr) = 0;
|
||||||
|
|
||||||
//! Returns the distance modifier for CLightning, used to modify hit probability. Value in range [0..1], where 0 is never and 1 is normal probability
|
//! Returns the distance modifier for CLightning, used to modify hit probability. Value in range [0..1], where 0 is never and 1 is normal probability
|
||||||
virtual float GetLightningHitProbability() = 0;
|
virtual float GetLightningHitProbability() = 0;
|
||||||
|
|
|
@ -199,7 +199,7 @@ bool CObjectManager::TeamExists(int team)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CObjectManager::DestroyTeam(int team)
|
void CObjectManager::DestroyTeam(int team, DestructionType destructionType)
|
||||||
{
|
{
|
||||||
assert(team != 0);
|
assert(team != 0);
|
||||||
|
|
||||||
|
@ -209,7 +209,7 @@ void CObjectManager::DestroyTeam(int team)
|
||||||
{
|
{
|
||||||
if (object->Implements(ObjectInterfaceType::Destroyable))
|
if (object->Implements(ObjectInterfaceType::Destroyable))
|
||||||
{
|
{
|
||||||
dynamic_cast<CDestroyableObject*>(object)->DestroyObject(DestructionType::Explosion);
|
dynamic_cast<CDestroyableObject*>(object)->DestroyObject(destructionType);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include "object/object_create_params.h"
|
#include "object/object_create_params.h"
|
||||||
#include "object/object_interface_type.h"
|
#include "object/object_interface_type.h"
|
||||||
#include "object/object_type.h"
|
#include "object/object_type.h"
|
||||||
|
#include "object/interface/destroyable_object.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -180,7 +181,7 @@ public:
|
||||||
|
|
||||||
//! Destroy all objects of team
|
//! Destroy all objects of team
|
||||||
// TODO: This should be probably moved to separate class
|
// TODO: This should be probably moved to separate class
|
||||||
void DestroyTeam(int team);
|
void DestroyTeam(int team, DestructionType destructionType = DestructionType::Explosion);
|
||||||
|
|
||||||
//! Counts all objects implementing given interface
|
//! Counts all objects implementing given interface
|
||||||
int CountObjectsImplementing(ObjectInterfaceType interface);
|
int CountObjectsImplementing(ObjectInterfaceType interface);
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include "graphics/engine/terrain.h"
|
#include "graphics/engine/terrain.h"
|
||||||
|
|
||||||
#include "level/robotmain.h"
|
#include "level/robotmain.h"
|
||||||
|
#include "level/scoreboard.h"
|
||||||
|
|
||||||
#include "level/parser/parserexceptions.h"
|
#include "level/parser/parserexceptions.h"
|
||||||
#include "level/parser/parserline.h"
|
#include "level/parser/parserline.h"
|
||||||
|
@ -335,7 +336,7 @@ void COldObject::Simplify()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool COldObject::DamageObject(DamageType type, float force)
|
bool COldObject::DamageObject(DamageType type, float force, CObject* killer)
|
||||||
{
|
{
|
||||||
assert(Implements(ObjectInterfaceType::Damageable));
|
assert(Implements(ObjectInterfaceType::Damageable));
|
||||||
assert(!Implements(ObjectInterfaceType::Destroyable) || Implements(ObjectInterfaceType::Shielded) || Implements(ObjectInterfaceType::Fragile));
|
assert(!Implements(ObjectInterfaceType::Destroyable) || Implements(ObjectInterfaceType::Shielded) || Implements(ObjectInterfaceType::Fragile));
|
||||||
|
@ -355,7 +356,7 @@ bool COldObject::DamageObject(DamageType type, float force)
|
||||||
{
|
{
|
||||||
if ( m_type == OBJECT_BOMB && type != DamageType::Explosive ) return false; // Mine can't be destroyed by shooting
|
if ( m_type == OBJECT_BOMB && type != DamageType::Explosive ) return false; // Mine can't be destroyed by shooting
|
||||||
|
|
||||||
DestroyObject(DestructionType::Explosion);
|
DestroyObject(DestructionType::Explosion, killer);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -400,11 +401,11 @@ bool COldObject::DamageObject(DamageType type, float force)
|
||||||
{
|
{
|
||||||
if (type == DamageType::Fire)
|
if (type == DamageType::Fire)
|
||||||
{
|
{
|
||||||
DestroyObject(DestructionType::Burn);
|
DestroyObject(DestructionType::Burn, killer);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DestroyObject(DestructionType::Explosion);
|
DestroyObject(DestructionType::Explosion, killer);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -425,7 +426,7 @@ bool COldObject::DamageObject(DamageType type, float force)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void COldObject::DestroyObject(DestructionType type)
|
void COldObject::DestroyObject(DestructionType type, CObject* killer)
|
||||||
{
|
{
|
||||||
assert(Implements(ObjectInterfaceType::Destroyable));
|
assert(Implements(ObjectInterfaceType::Destroyable));
|
||||||
|
|
||||||
|
@ -522,6 +523,10 @@ void COldObject::DestroyObject(DestructionType type)
|
||||||
{
|
{
|
||||||
pyroType = Gfx::PT_DEADW;
|
pyroType = Gfx::PT_DEADW;
|
||||||
}
|
}
|
||||||
|
else if ( type == DestructionType::Win )
|
||||||
|
{
|
||||||
|
pyroType = Gfx::PT_WPCHECK;
|
||||||
|
}
|
||||||
assert(pyroType != Gfx::PT_NULL);
|
assert(pyroType != Gfx::PT_NULL);
|
||||||
m_engine->GetPyroManager()->Create(pyroType, this);
|
m_engine->GetPyroManager()->Create(pyroType, this);
|
||||||
|
|
||||||
|
@ -539,6 +544,10 @@ void COldObject::DestroyObject(DestructionType type)
|
||||||
}
|
}
|
||||||
m_main->RemoveFromSelectionHistory(this);
|
m_main->RemoveFromSelectionHistory(this);
|
||||||
|
|
||||||
|
CScoreboard* scoreboard = m_main->GetScoreboard();
|
||||||
|
if (scoreboard)
|
||||||
|
scoreboard->ProcessKill(this, killer);
|
||||||
|
|
||||||
m_team = 0; // Back to neutral on destruction
|
m_team = 0; // Back to neutral on destruction
|
||||||
|
|
||||||
if ( m_botVar != nullptr )
|
if ( m_botVar != nullptr )
|
||||||
|
|
|
@ -110,8 +110,8 @@ public:
|
||||||
|
|
||||||
void Simplify() override;
|
void Simplify() override;
|
||||||
|
|
||||||
bool DamageObject(DamageType type, float force = std::numeric_limits<float>::infinity()) override;
|
bool DamageObject(DamageType type, float force = std::numeric_limits<float>::infinity(), CObject* killer = nullptr) override;
|
||||||
void DestroyObject(DestructionType type) override;
|
void DestroyObject(DestructionType type, CObject* killer = nullptr) override;
|
||||||
|
|
||||||
bool EventProcess(const Event& event) override;
|
bool EventProcess(const Event& event) override;
|
||||||
void UpdateMapping();
|
void UpdateMapping();
|
||||||
|
|
|
@ -2701,6 +2701,7 @@ bool CPhysics::ExploOther(ObjectType iType,
|
||||||
|
|
||||||
if ( force > destructionForce )
|
if ( force > destructionForce )
|
||||||
{
|
{
|
||||||
|
// TODO: implement "killer"?
|
||||||
dynamic_cast<CDamageableObject*>(pObj)->DamageObject(damageType);
|
dynamic_cast<CDamageableObject*>(pObj)->DamageObject(damageType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2726,6 +2727,7 @@ bool CPhysics::ExploOther(ObjectType iType,
|
||||||
oType == OBJECT_HUSTON ) // building?
|
oType == OBJECT_HUSTON ) // building?
|
||||||
{
|
{
|
||||||
assert(pObj->Implements(ObjectInterfaceType::Damageable));
|
assert(pObj->Implements(ObjectInterfaceType::Damageable));
|
||||||
|
// TODO: implement "killer"?
|
||||||
dynamic_cast<CDamageableObject*>(pObj)->DamageObject(DamageType::Collision, force/400.0f);
|
dynamic_cast<CDamageableObject*>(pObj)->DamageObject(DamageType::Collision, force/400.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2756,6 +2758,7 @@ bool CPhysics::ExploOther(ObjectType iType,
|
||||||
oType == OBJECT_MOBILEit ) // vehicle?
|
oType == OBJECT_MOBILEit ) // vehicle?
|
||||||
{
|
{
|
||||||
assert(pObj->Implements(ObjectInterfaceType::Damageable));
|
assert(pObj->Implements(ObjectInterfaceType::Damageable));
|
||||||
|
// TODO: implement "killer"?
|
||||||
dynamic_cast<CDamageableObject*>(pObj)->DamageObject(DamageType::Collision, force/200.0f);
|
dynamic_cast<CDamageableObject*>(pObj)->DamageObject(DamageType::Collision, force/200.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2780,6 +2783,7 @@ int CPhysics::ExploHimself(ObjectType iType, ObjectType oType, float force)
|
||||||
|
|
||||||
if ( force > destructionForce && destructionForce >= 0.0f )
|
if ( force > destructionForce && destructionForce >= 0.0f )
|
||||||
{
|
{
|
||||||
|
// TODO: implement "killer"?
|
||||||
dynamic_cast<CDamageableObject*>(m_object)->DamageObject(DamageType::Explosive);
|
dynamic_cast<CDamageableObject*>(m_object)->DamageObject(DamageType::Explosive);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
@ -2860,6 +2864,7 @@ int CPhysics::ExploHimself(ObjectType iType, ObjectType oType, float force)
|
||||||
force /= 200.0f;
|
force /= 200.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: implement "killer"?
|
||||||
if ( dynamic_cast<CDamageableObject*>(m_object)->DamageObject(DamageType::Collision, force) ) return 2;
|
if ( dynamic_cast<CDamageableObject*>(m_object)->DamageObject(DamageType::Collision, force) ) return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue