Merge branch 'dev' into dev-graphics-overhaul
# Conflicts: # src/level/player_profile.cpp # src/object/task/taskgoto.cpp # src/object/task/taskgoto.h # src/ui/mainui.cppdev
commit
daa9419557
|
@ -1,11 +1,11 @@
|
|||
[submodule "data"]
|
||||
path = data
|
||||
url = git://github.com/colobot/colobot-data.git
|
||||
url = https://github.com/colobot/colobot-data.git
|
||||
branch = .
|
||||
update = rebase
|
||||
[submodule "lib/googletest"]
|
||||
path = lib/googletest
|
||||
url = git://github.com/google/googletest.git
|
||||
url = https://github.com/google/googletest.git
|
||||
ignore = all
|
||||
[submodule "lib/json"]
|
||||
path = lib/json
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit e2239ee6043f73722e7aa812a459f54a28552929
|
||||
Subproject commit 97a467571a0f615a4d96e79e4399c43221ca1232
|
|
@ -435,8 +435,8 @@ add_library(colobotbase STATIC
|
|||
ui/particles_generator.h
|
||||
ui/screen/screen.cpp
|
||||
ui/screen/screen.h
|
||||
ui/screen/screen_apperance.cpp
|
||||
ui/screen/screen_apperance.h
|
||||
ui/screen/screen_appearance.cpp
|
||||
ui/screen/screen_appearance.h
|
||||
ui/screen/screen_io.cpp
|
||||
ui/screen/screen_io.h
|
||||
ui/screen/screen_io_read.cpp
|
||||
|
@ -525,7 +525,7 @@ if(PLATFORM_WINDOWS)
|
|||
# This should be treated as a temporary workaround
|
||||
if(USE_STATIC_RUNTIME) # Since we're using static runtime, assume every external library is static too
|
||||
find_package(Intl REQUIRED)
|
||||
|
||||
|
||||
find_library(BZ2_LIBRARY NAMES bz2)
|
||||
find_library(JPEG_LIBRARY NAMES jpeg)
|
||||
find_library(TIFF_LIBRARY NAMES tiff)
|
||||
|
|
|
@ -244,6 +244,7 @@ ParseArgsStatus CApplication::ParseArguments(int argc, char *argv[])
|
|||
OPT_DEBUG,
|
||||
OPT_RUNSCENE,
|
||||
OPT_SCENETEST,
|
||||
OPT_LOADSAVE,
|
||||
OPT_LOGLEVEL,
|
||||
OPT_LANGDIR,
|
||||
OPT_DATADIR,
|
||||
|
@ -262,6 +263,7 @@ ParseArgsStatus CApplication::ParseArguments(int argc, char *argv[])
|
|||
{ "debug", required_argument, nullptr, OPT_DEBUG },
|
||||
{ "runscene", required_argument, nullptr, OPT_RUNSCENE },
|
||||
{ "scenetest", no_argument, nullptr, OPT_SCENETEST },
|
||||
{ "loadsave", required_argument, nullptr, OPT_LOADSAVE },
|
||||
{ "loglevel", required_argument, nullptr, OPT_LOGLEVEL },
|
||||
{ "langdir", required_argument, nullptr, OPT_LANGDIR },
|
||||
{ "datadir", required_argument, nullptr, OPT_DATADIR },
|
||||
|
@ -307,6 +309,7 @@ ParseArgsStatus CApplication::ParseArguments(int argc, char *argv[])
|
|||
GetLogger()->Message(" -debug modes enable debug modes (more info printed in logs; see code for reference of modes)\n");
|
||||
GetLogger()->Message(" -runscene sceneNNN run given scene on start\n");
|
||||
GetLogger()->Message(" -scenetest win every mission right after it's loaded\n");
|
||||
GetLogger()->Message(" -loadsave path load given saved game on start (path is <player>/<save>\n");
|
||||
GetLogger()->Message(" -loglevel level set log level to level (one of: trace, debug, info, warn, error, none)\n");
|
||||
GetLogger()->Message(" -langdir path set custom language directory path\n");
|
||||
GetLogger()->Message(" environment variable: COLOBOT_LANG_DIR\n");
|
||||
|
@ -364,6 +367,22 @@ ParseArgsStatus CApplication::ParseArguments(int argc, char *argv[])
|
|||
m_sceneTest = true;
|
||||
break;
|
||||
}
|
||||
case OPT_LOADSAVE:
|
||||
{
|
||||
std::string playerAndPath = optarg;
|
||||
size_t pos = playerAndPath.find_first_of("/");
|
||||
if (pos != std::string::npos && pos > 0 && pos+1 < playerAndPath.length()) // Split player name from path
|
||||
{
|
||||
m_loadSavePlayerName = playerAndPath.substr(0, pos);
|
||||
m_loadSaveDirName = playerAndPath.substr(pos+1, playerAndPath.length()-pos-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
GetLogger()->Error("Invalid path: '%s'\n", optarg);
|
||||
return PARSE_ARGS_FAIL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OPT_LOGLEVEL:
|
||||
{
|
||||
LogLevel logLevel;
|
||||
|
@ -590,7 +609,7 @@ bool CApplication::Create()
|
|||
h = atoi(hs.c_str());
|
||||
}
|
||||
|
||||
// Why not just set m_deviceConfig.size to w,h? Because this way if the resolution is no longer supported (e.g. changimg monitor) defaults will be used instead
|
||||
// Why not just set m_deviceConfig.size to w,h? Because this way if the resolution is no longer supported (e.g. changing monitor) defaults will be used instead
|
||||
for (auto it = modes.begin(); it != modes.end(); ++it)
|
||||
{
|
||||
if (it->x == w && it->y == h)
|
||||
|
@ -695,8 +714,15 @@ bool CApplication::Create()
|
|||
|
||||
StartLoadingMusic();
|
||||
|
||||
if (m_runSceneCategory == LevelCategory::Max)
|
||||
if (!m_loadSaveDirName.empty())
|
||||
{
|
||||
m_controller->GetRobotMain()->SelectPlayer(m_loadSavePlayerName);
|
||||
m_controller->GetRobotMain()->LoadSaveFromDirName(m_loadSaveDirName);
|
||||
}
|
||||
else if (m_runSceneCategory == LevelCategory::Max)
|
||||
{
|
||||
m_controller->StartApp();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_controller->GetRobotMain()->UpdateCustomLevelList(); // To load the userlevels
|
||||
|
@ -1865,7 +1891,7 @@ void CApplication::SetLanguage(Language language)
|
|||
}
|
||||
else
|
||||
{
|
||||
GetLogger()->Warn("Enviromnent locale ('%s') is not supported, setting default language\n", envLang);
|
||||
GetLogger()->Warn("Environment locale ('%s') is not supported, setting default language\n", envLang);
|
||||
m_language = LANGUAGE_ENGLISH;
|
||||
}
|
||||
}
|
||||
|
@ -1934,7 +1960,7 @@ void CApplication::SetLanguage(Language language)
|
|||
}
|
||||
catch (...)
|
||||
{
|
||||
GetLogger()->Warn("Failed to update locale, possibly incorect system configuration. Will fallback to classic locale.\n");
|
||||
GetLogger()->Warn("Failed to update locale, possibly incorrect system configuration. Will fallback to classic locale.\n");
|
||||
try
|
||||
{
|
||||
std::locale::global(std::locale::classic());
|
||||
|
|
|
@ -219,7 +219,7 @@ public:
|
|||
|
||||
//! Returns the relative time since last update [seconds]
|
||||
float GetRelTime() const;
|
||||
//! Returns the exact realative time since last update [nanoseconds]
|
||||
//! Returns the exact relative time since last update [nanoseconds]
|
||||
long long GetExactRelTime() const;
|
||||
|
||||
//! Returns the exact relative time since last update disregarding speed setting [nanoseconds]
|
||||
|
@ -406,13 +406,17 @@ protected:
|
|||
int m_runSceneRank;
|
||||
//@}
|
||||
|
||||
//! Game to load on startup
|
||||
std::string m_loadSavePlayerName;
|
||||
std::string m_loadSaveDirName;
|
||||
|
||||
//! Scene test mode
|
||||
bool m_sceneTest;
|
||||
|
||||
//! Application language
|
||||
Language m_language;
|
||||
|
||||
//! Screen resoultion overriden by commandline
|
||||
//! Screen resolution overriden by commandline
|
||||
bool m_resolutionOverride;
|
||||
|
||||
//! Headles mode
|
||||
|
|
|
@ -59,14 +59,14 @@ object-oriented language, CBOT, which can be used to program the robots availabl
|
|||
|
||||
The original version of the game was developed by [Epsitec](http://www.epsitec.ch/) and released in 2001.
|
||||
Later, in 2005 another version named Ceebot was released. In March 2012, through attempts
|
||||
by Polish Colobot fans, Epsitec agreeed to release the source code of the game on GPLv3 license.
|
||||
by Polish Colobot fans, Epsitec agreed to release the source code of the game on GPLv3 license.
|
||||
The license was given specifically to our community, <b>TerranovaTeam</b>,
|
||||
part of <b>International Colobot Community (ICC)</b> (previously known as <i>Polish Portal of Colobot (PPC)</i>;
|
||||
Polish: <i>Polski Portal Colobota</i>) with our website at http://colobot.info/.
|
||||
|
||||
\section Intro Introduction
|
||||
|
||||
The source code released by Epitec was sparsely documented. This documentation, written from scratch,
|
||||
The source code released by Epsitec was sparsely documented. This documentation, written from scratch,
|
||||
will aim to describe the various components of the code.
|
||||
|
||||
Currently, the only documented classes are the ones written from scratch or the old ones rewritten
|
||||
|
@ -91,7 +91,7 @@ The current layout is the following:
|
|||
- src/graphics/opengl - concrete implementation of CDevice class in OpenGL: CGLDevice
|
||||
- src/graphics/d3d - in (far) future - perhaps a newer implementation in DirectX (9? 10?)
|
||||
- src/math - mathematical structures and functions
|
||||
- src/object - non-grphical game object logic, that is robots, buildings, etc.
|
||||
- src/object - non-graphical game object logic, that is robots, buildings, etc.
|
||||
- src/level - main part of non-graphical game engine, that is loading levels etc.
|
||||
- src/level/parser - parser for loading/saving level files from format known as <i>scene files</i>
|
||||
- src/ui - 2D user interface (menu, buttons, check boxes, etc.)
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
#include "level/parser/parser.h"
|
||||
|
||||
|
||||
void PlayerApperance::DefPerso()
|
||||
void PlayerAppearance::DefPerso()
|
||||
{
|
||||
this->colorCombi.r = 206.0f/256.0f;
|
||||
this->colorCombi.g = 206.0f/256.0f;
|
||||
|
@ -75,7 +75,7 @@ void PlayerApperance::DefPerso()
|
|||
this->colorBand.a = 0.0f;
|
||||
}
|
||||
|
||||
void PlayerApperance::DefHairColor()
|
||||
void PlayerAppearance::DefHairColor()
|
||||
{
|
||||
if (this->face == 0) // normal ?
|
||||
{
|
||||
|
@ -121,7 +121,7 @@ CPlayerProfile::CPlayerProfile(std::string playerName)
|
|||
m_levelInfoLoaded[static_cast<LevelCategory>(i)] = false;
|
||||
}
|
||||
|
||||
LoadApperance();
|
||||
LoadAppearance();
|
||||
}
|
||||
|
||||
CPlayerProfile::~CPlayerProfile()
|
||||
|
@ -391,17 +391,17 @@ void CPlayerProfile::SaveFreeGameUnlock()
|
|||
file.close();
|
||||
}
|
||||
|
||||
// APPERANCE
|
||||
// APPEARANCE
|
||||
|
||||
PlayerApperance& CPlayerProfile::GetApperance()
|
||||
PlayerAppearance& CPlayerProfile::GetAppearance()
|
||||
{
|
||||
return m_apperance;
|
||||
return m_appearance;
|
||||
}
|
||||
|
||||
void CPlayerProfile::LoadApperance()
|
||||
void CPlayerProfile::LoadAppearance()
|
||||
{
|
||||
m_apperance.face = 0;
|
||||
m_apperance.DefPerso();
|
||||
m_appearance.face = 0;
|
||||
m_appearance.DefPerso();
|
||||
|
||||
std::string filename = GetSaveFile("face.gam");
|
||||
if (!CResourceManager::Exists(filename))
|
||||
|
@ -409,48 +409,48 @@ void CPlayerProfile::LoadApperance()
|
|||
|
||||
try
|
||||
{
|
||||
CLevelParser apperanceParser(filename);
|
||||
apperanceParser.Load();
|
||||
CLevelParser appearanceParser(filename);
|
||||
appearanceParser.Load();
|
||||
CLevelParserLine* line;
|
||||
|
||||
line = apperanceParser.Get("Head");
|
||||
m_apperance.face = line->GetParam("face")->AsInt();
|
||||
m_apperance.glasses = line->GetParam("glasses")->AsInt();
|
||||
m_apperance.colorHair = line->GetParam("hair")->AsColor();
|
||||
line = appearanceParser.Get("Head");
|
||||
m_appearance.face = line->GetParam("face")->AsInt();
|
||||
m_appearance.glasses = line->GetParam("glasses")->AsInt();
|
||||
m_appearance.colorHair = line->GetParam("hair")->AsColor();
|
||||
|
||||
line = apperanceParser.Get("Body");
|
||||
m_apperance.colorCombi = line->GetParam("combi")->AsColor();
|
||||
m_apperance.colorBand = line->GetParam("band")->AsColor();
|
||||
line = appearanceParser.Get("Body");
|
||||
m_appearance.colorCombi = line->GetParam("combi")->AsColor();
|
||||
m_appearance.colorBand = line->GetParam("band")->AsColor();
|
||||
}
|
||||
catch (CLevelParserException& e)
|
||||
{
|
||||
GetLogger()->Error("Unable to read personalized player apperance: %s\n", e.what());
|
||||
GetLogger()->Error("Unable to read personalized player appearance: %s\n", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void CPlayerProfile::SaveApperance()
|
||||
void CPlayerProfile::SaveAppearance()
|
||||
{
|
||||
try
|
||||
{
|
||||
CLevelParser apperanceParser(GetSaveFile("face.gam"));
|
||||
CLevelParser appearanceParser(GetSaveFile("face.gam"));
|
||||
CLevelParserLineUPtr line;
|
||||
|
||||
line = std::make_unique<CLevelParserLine>("Head");
|
||||
line->AddParam("face", std::make_unique<CLevelParserParam>(m_apperance.face));
|
||||
line->AddParam("glasses", std::make_unique<CLevelParserParam>(m_apperance.glasses));
|
||||
line->AddParam("hair", std::make_unique<CLevelParserParam>(m_apperance.colorHair));
|
||||
apperanceParser.AddLine(std::move(line));
|
||||
line->AddParam("face", std::make_unique<CLevelParserParam>(m_appearance.face));
|
||||
line->AddParam("glasses", std::make_unique<CLevelParserParam>(m_appearance.glasses));
|
||||
line->AddParam("hair", std::make_unique<CLevelParserParam>(m_appearance.colorHair));
|
||||
appearanceParser.AddLine(std::move(line));
|
||||
|
||||
line = std::make_unique<CLevelParserLine>("Body");
|
||||
line->AddParam("combi", std::make_unique<CLevelParserParam>(m_apperance.colorCombi));
|
||||
line->AddParam("band", std::make_unique<CLevelParserParam>(m_apperance.colorBand));
|
||||
apperanceParser.AddLine(std::move(line));
|
||||
line->AddParam("combi", std::make_unique<CLevelParserParam>(m_appearance.colorCombi));
|
||||
line->AddParam("band", std::make_unique<CLevelParserParam>(m_appearance.colorBand));
|
||||
appearanceParser.AddLine(std::move(line));
|
||||
|
||||
apperanceParser.Save();
|
||||
appearanceParser.Save();
|
||||
}
|
||||
catch (CLevelParserException& e)
|
||||
{
|
||||
GetLogger()->Error("Unable to write personalized player apperance: %s\n", e.what());
|
||||
GetLogger()->Error("Unable to write personalized player appearance: %s\n", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -524,7 +524,7 @@ void CPlayerProfile::LoadScene(std::string dir)
|
|||
CLevelParserLine* line = levelParser.Get("Mission");
|
||||
cat = GetLevelCategoryFromDir(line->GetParam("base")->AsString());
|
||||
|
||||
if (dir == "../../crashsave")
|
||||
if(!m_levelInfoLoaded[cat])
|
||||
LoadFinishedLevels(cat);
|
||||
|
||||
rank = line->GetParam("rank")->AsInt();
|
||||
|
@ -552,7 +552,7 @@ void CPlayerProfile::LoadScene(std::string dir)
|
|||
}
|
||||
else
|
||||
{
|
||||
// Backwards combatibility
|
||||
// Backwards compatibility
|
||||
chap = rank/100;
|
||||
rank = rank%100;
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ struct LevelInfo
|
|||
bool bPassed = false;
|
||||
};
|
||||
|
||||
struct PlayerApperance
|
||||
struct PlayerAppearance
|
||||
{
|
||||
int face = 0; // face
|
||||
int glasses = 0; // glasses
|
||||
|
@ -108,12 +108,12 @@ public:
|
|||
//! Saves unlocked DoneResearch for free game
|
||||
void SetFreeGameResearchUnlock(int freeResearch);
|
||||
|
||||
//! Returns a reference to PlayerApperance structure
|
||||
PlayerApperance& GetApperance();
|
||||
//! Loads PlayerApperance structure
|
||||
void LoadApperance();
|
||||
//! Saves PlayerApperance structure
|
||||
void SaveApperance();
|
||||
//! Returns a reference to PlayerAppearance structure
|
||||
PlayerAppearance& GetAppearance();
|
||||
//! Loads PlayerAppearance structure
|
||||
void LoadAppearance();
|
||||
//! Saves PlayerAppearance structure
|
||||
void SaveAppearance();
|
||||
|
||||
//! Returns true if player has at least one saved scene
|
||||
bool HasAnySavedScene();
|
||||
|
@ -157,6 +157,6 @@ protected:
|
|||
//! Researches unlocked for free game
|
||||
int m_freegameResearch;
|
||||
|
||||
//! Player apperance
|
||||
PlayerApperance m_apperance;
|
||||
//! Player appearance
|
||||
PlayerAppearance m_appearance;
|
||||
};
|
||||
|
|
|
@ -320,7 +320,7 @@ std::string PhaseToString(Phase phase)
|
|||
if (phase == PHASE_WELCOME2) return "PHASE_WELCOME2";
|
||||
if (phase == PHASE_WELCOME3) return "PHASE_WELCOME3";
|
||||
if (phase == PHASE_PLAYER_SELECT) return "PHASE_PLAYER_SELECT";
|
||||
if (phase == PHASE_APPERANCE) return "PHASE_APPERANCE";
|
||||
if (phase == PHASE_APPEARANCE) return "PHASE_APPEARANCE";
|
||||
if (phase == PHASE_MAIN_MENU) return "PHASE_MAIN_MENU";
|
||||
if (phase == PHASE_LEVEL_LIST) return "PHASE_LEVEL_LIST";
|
||||
if (phase == PHASE_MOD_LIST) return "PHASE_MOD_LIST";
|
||||
|
@ -355,14 +355,14 @@ bool IsPhaseWithWorld(Phase phase)
|
|||
if (phase == PHASE_SIMUL ) return true;
|
||||
if (phase == PHASE_WIN ) return true;
|
||||
if (phase == PHASE_LOST ) return true;
|
||||
if (phase == PHASE_APPERANCE) return true;
|
||||
if (phase == PHASE_APPEARANCE) return true;
|
||||
if (IsInSimulationConfigPhase(phase)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsMainMenuPhase(Phase phase)
|
||||
{
|
||||
if (phase == PHASE_APPERANCE) return true;
|
||||
if (phase == PHASE_APPEARANCE) return true;
|
||||
return !IsPhaseWithWorld(phase);
|
||||
}
|
||||
|
||||
|
@ -534,7 +534,7 @@ void CRobotMain::ChangePhase(Phase phase)
|
|||
float sx = (32.0f+2.0f)/640.0f;
|
||||
float sy = (32.0f+2.0f)/480.0f;
|
||||
|
||||
if (m_phase != PHASE_APPERANCE)
|
||||
if (m_phase != PHASE_APPEARANCE)
|
||||
{
|
||||
m_engine->SetDrawWorld(true);
|
||||
m_engine->SetDrawFront(false);
|
||||
|
@ -1165,7 +1165,7 @@ bool CRobotMain::ProcessEvent(Event &event)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (m_phase == PHASE_APPERANCE)
|
||||
if (m_phase == PHASE_APPEARANCE)
|
||||
EventObject(event);
|
||||
|
||||
if (m_phase == PHASE_WIN ||
|
||||
|
@ -2100,7 +2100,7 @@ void CRobotMain::HiliteClear()
|
|||
//! Highlights the object with the mouse hovers over
|
||||
void CRobotMain::HiliteObject(const glm::vec2& pos)
|
||||
{
|
||||
if (m_fixScene && m_phase != PHASE_APPERANCE) return;
|
||||
if (m_fixScene && m_phase != PHASE_APPEARANCE) return;
|
||||
if (m_movieLock) return;
|
||||
if (m_movie->IsExist()) return;
|
||||
if (m_app->GetMouseMode() == MOUSE_NONE) return;
|
||||
|
@ -2166,7 +2166,7 @@ void CRobotMain::HiliteObject(const glm::vec2& pos)
|
|||
//! Highlights the object with the mouse hovers over
|
||||
void CRobotMain::HiliteFrame(float rTime)
|
||||
{
|
||||
if (m_fixScene && m_phase != PHASE_APPERANCE) return;
|
||||
if (m_fixScene && m_phase != PHASE_APPEARANCE) return;
|
||||
if (m_movieLock) return;
|
||||
if (m_movie->IsExist()) return;
|
||||
|
||||
|
@ -2451,7 +2451,7 @@ bool CRobotMain::EventFrame(const Event &event)
|
|||
if (m_engine->GetFog())
|
||||
m_camera->SetOverBaseColor(m_particle->GetFogColor(m_engine->GetEyePt()));
|
||||
}
|
||||
if (m_phase == PHASE_APPERANCE ||
|
||||
if (m_phase == PHASE_APPEARANCE ||
|
||||
m_phase == PHASE_WIN ||
|
||||
m_phase == PHASE_LOST)
|
||||
{
|
||||
|
@ -2724,7 +2724,7 @@ void CRobotMain::ScenePerso()
|
|||
}
|
||||
catch (const std::runtime_error& e)
|
||||
{
|
||||
LevelLoadingError("An error occurred while trying to load apperance scene", e, PHASE_PLAYER_SELECT);
|
||||
LevelLoadingError("An error occurred while trying to load appearance scene", e, PHASE_PLAYER_SELECT);
|
||||
}
|
||||
|
||||
m_engine->SetDrawWorld(false); // does not draw anything on the interface
|
||||
|
@ -3946,7 +3946,7 @@ void CRobotMain::ChangeColor()
|
|||
m_phase != PHASE_MOD_LIST &&
|
||||
m_phase != PHASE_WIN &&
|
||||
m_phase != PHASE_LOST &&
|
||||
m_phase != PHASE_APPERANCE ) return;
|
||||
m_phase != PHASE_APPEARANCE ) return;
|
||||
|
||||
// Player texture
|
||||
|
||||
|
@ -3961,11 +3961,11 @@ void CRobotMain::ChangeColor()
|
|||
colorRef1.r = 206.0f/256.0f;
|
||||
colorRef1.g = 206.0f/256.0f;
|
||||
colorRef1.b = 204.0f/256.0f; // ~white
|
||||
colorNew1 = m_playerProfile->GetApperance().colorCombi;
|
||||
colorNew1 = m_playerProfile->GetAppearance().colorCombi;
|
||||
colorRef2.r = 255.0f/256.0f;
|
||||
colorRef2.g = 132.0f/256.0f;
|
||||
colorRef2.b = 1.0f/256.0f; // orange
|
||||
colorNew2 = m_playerProfile->GetApperance().colorBand;
|
||||
colorNew2 = m_playerProfile->GetAppearance().colorBand;
|
||||
|
||||
glm::vec2 exclu[6];
|
||||
exclu[0] = { 192.0f / 256.0f, 0.0f / 256.0f };
|
||||
|
@ -4007,7 +4007,7 @@ void CRobotMain::ChangeColor()
|
|||
colorRef1.b = 0.0f/256.0f; // yellow
|
||||
tolerance = 0.20f;
|
||||
}
|
||||
colorNew1 = m_playerProfile->GetApperance().colorHair;
|
||||
colorNew1 = m_playerProfile->GetAppearance().colorHair;
|
||||
colorRef2.r = 0.0f;
|
||||
colorRef2.g = 0.0f;
|
||||
colorRef2.b = 0.0f;
|
||||
|
@ -5492,13 +5492,13 @@ MissionType CRobotMain::GetMissionType()
|
|||
//! Returns the representation to use for the player
|
||||
int CRobotMain::GetGamerFace()
|
||||
{
|
||||
return m_playerProfile->GetApperance().face;
|
||||
return m_playerProfile->GetAppearance().face;
|
||||
}
|
||||
|
||||
//! Returns the representation to use for the player
|
||||
int CRobotMain::GetGamerGlasses()
|
||||
{
|
||||
return m_playerProfile->GetApperance().glasses;
|
||||
return m_playerProfile->GetAppearance().glasses;
|
||||
}
|
||||
|
||||
//! Returns the mode with just the head
|
||||
|
@ -5878,6 +5878,17 @@ void CRobotMain::QuickLoad()
|
|||
m_playerProfile->LoadScene(dir);
|
||||
}
|
||||
|
||||
void CRobotMain::LoadSaveFromDirName(const std::string& gameDir)
|
||||
{
|
||||
std::string dir = m_playerProfile->GetSaveFile(gameDir);
|
||||
if(!CResourceManager::Exists(dir))
|
||||
{
|
||||
GetLogger()->Error("Save slot not found\n");
|
||||
return;
|
||||
}
|
||||
m_playerProfile->LoadScene(dir);
|
||||
}
|
||||
|
||||
void CRobotMain::SetExitAfterMission(bool exit)
|
||||
{
|
||||
m_exitAfterMission = exit;
|
||||
|
|
|
@ -56,7 +56,7 @@ enum Phase
|
|||
PHASE_WELCOME2,
|
||||
PHASE_WELCOME3,
|
||||
PHASE_PLAYER_SELECT,
|
||||
PHASE_APPERANCE,
|
||||
PHASE_APPEARANCE,
|
||||
PHASE_MAIN_MENU,
|
||||
PHASE_LEVEL_LIST,
|
||||
PHASE_MOD_LIST,
|
||||
|
@ -203,7 +203,7 @@ public:
|
|||
Phase GetPhase();
|
||||
//@}
|
||||
|
||||
//! Load the scene for apperance customization
|
||||
//! Load the scene for appearance customization
|
||||
void ScenePerso();
|
||||
|
||||
void SetMovieLock(bool lock);
|
||||
|
@ -373,6 +373,9 @@ public:
|
|||
//! Enable mode where completing mission closes the game
|
||||
void SetExitAfterMission(bool exit);
|
||||
|
||||
//! Load saved game (used by command line argument)
|
||||
void LoadSaveFromDirName(const std::string& gameDir);
|
||||
|
||||
//! Returns true if player can interact with things manually
|
||||
bool CanPlayerInteract();
|
||||
|
||||
|
|
|
@ -48,10 +48,10 @@ const float FLY_DEF_HEIGHT = 50.0f; // default flying height
|
|||
|
||||
// Settings that define goto() accuracy:
|
||||
const float BM_DIM_STEP = 5.0f; // Size of one pixel on the bitmap. Setting 5 means that 5x5 square (in game units) will be represented by 1 px on the bitmap. Decreasing this value will make a bigger bitmap, and may increase accuracy. TODO: Check how it actually impacts goto() accuracy
|
||||
const float BEAM_ACCURACY = 5.0f; // higher value = more accurate, but slower
|
||||
const float SAFETY_MARGIN = 0.5f; // Smallest distance between two objects. Smaller = less "no route to destination", but higher probability of collisions between objects.
|
||||
const float SAFETY_MARGIN = 1.5f; // Smallest distance between two objects. Smaller = less "no route to destination", but higher probability of collisions between objects.
|
||||
// Changing SAFETY_MARGIN (old value was 4.0f) seems to have fixed many issues with goto(). TODO: maybe we could make it even smaller? Did changing it introduce any new bugs?
|
||||
|
||||
const int NB_ITER = 200; // Maximum number of iterations you have the right to make before temporarily interrupt in order not to lower the framerate.
|
||||
|
||||
|
||||
|
||||
|
@ -130,7 +130,7 @@ bool CTaskGoto::EventProcess(const Event &event)
|
|||
if (a || b)
|
||||
{
|
||||
Gfx::Color c = Gfx::Color(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
if (b) c = Gfx::Color(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
if (b) c = Gfx::Color(0.0f, 1.0f, 1.0f, 1.0f);
|
||||
debugImage->SetPixel({ x, y }, c);
|
||||
}
|
||||
}
|
||||
|
@ -225,7 +225,7 @@ bool CTaskGoto::EventProcess(const Event &event)
|
|||
if ( m_bmCargoObject->GetType() == OBJECT_BASE ) dist = 12.0f;
|
||||
}
|
||||
|
||||
ret = BeamSearch(pos, goal, dist);
|
||||
ret = PathFindingSearch(pos, goal, dist);
|
||||
if ( ret == ERR_OK )
|
||||
{
|
||||
if ( m_physics->GetLand() ) m_phase = TGP_BEAMWCOLD;
|
||||
|
@ -349,7 +349,7 @@ bool CTaskGoto::EventProcess(const Event &event)
|
|||
{
|
||||
m_physics->SetMotorSpeedX(0.0f); // stops the advance
|
||||
m_physics->SetMotorSpeedZ(0.0f); // stops the rotation
|
||||
BeamStart(); // we start all
|
||||
PathFindingStart(); // we start all
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -793,7 +793,7 @@ Error CTaskGoto::Start(glm::vec3 goal, float altitude,
|
|||
}
|
||||
}
|
||||
|
||||
BeamStart();
|
||||
PathFindingStart();
|
||||
|
||||
if ( m_bmCargoObject == nullptr )
|
||||
{
|
||||
|
@ -829,7 +829,7 @@ Error CTaskGoto::IsEnded()
|
|||
{
|
||||
m_physics->SetMotorSpeedX(0.0f); // stops the advance
|
||||
m_physics->SetMotorSpeedZ(0.0f); // stops the rotation
|
||||
BeamInit();
|
||||
PathFindingInit();
|
||||
m_phase = TGP_BEAMSEARCH; // will seek the path
|
||||
}
|
||||
return ERR_CONTINUE;
|
||||
|
@ -891,7 +891,7 @@ Error CTaskGoto::IsEnded()
|
|||
m_physics->SetMotorSpeedX(0.0f); // stops the advance
|
||||
m_physics->SetMotorSpeedZ(0.0f); // stops the rotation
|
||||
|
||||
m_bmIndex = BeamShortcut();
|
||||
m_bmIndex = PathFindingShortcut();
|
||||
|
||||
if ( m_bmIndex > m_bmTotal )
|
||||
{
|
||||
|
@ -1631,13 +1631,13 @@ void CTaskGoto::ComputeFlyingRepulse(float &dir)
|
|||
// Among all of the following, seek if there is one allowing to go directly to the crow flies.
|
||||
// If yes, skip all the unnecessary intermediate points.
|
||||
|
||||
int CTaskGoto::BeamShortcut()
|
||||
int CTaskGoto::PathFindingShortcut()
|
||||
{
|
||||
int i;
|
||||
|
||||
for ( i=m_bmTotal ; i>=m_bmIndex+2 ; i-- ) // tries from the last
|
||||
{
|
||||
if ( BitmapTestLine(m_bmPoints[m_bmIndex], m_bmPoints[i], 0.0f, false) )
|
||||
if ( BitmapTestLine(m_bmPoints[m_bmIndex], m_bmPoints[i]) )
|
||||
{
|
||||
return i; // bingo, found
|
||||
}
|
||||
|
@ -1648,7 +1648,7 @@ int CTaskGoto::BeamShortcut()
|
|||
|
||||
// That's the big start.
|
||||
|
||||
void CTaskGoto::BeamStart()
|
||||
void CTaskGoto::PathFindingStart()
|
||||
{
|
||||
glm::vec3 min, max;
|
||||
|
||||
|
@ -1674,14 +1674,14 @@ void CTaskGoto::BeamStart()
|
|||
{
|
||||
m_physics->SetMotorSpeedX(0.0f); // stops the advance
|
||||
m_physics->SetMotorSpeedZ(0.0f); // stops the rotation
|
||||
BeamInit();
|
||||
PathFindingInit();
|
||||
m_phase = TGP_BEAMSEARCH; // will seek the path
|
||||
}
|
||||
}
|
||||
|
||||
// Initialization before the first BeamSearch.
|
||||
// Initialization before the first PathFindingSearch.
|
||||
|
||||
void CTaskGoto::BeamInit()
|
||||
void CTaskGoto::PathFindingInit()
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -1690,6 +1690,34 @@ void CTaskGoto::BeamInit()
|
|||
m_bmIter[i] = -1;
|
||||
}
|
||||
m_bmStep = 0;
|
||||
for (auto& bucket : m_bfsQueue)
|
||||
{
|
||||
bucket.clear();
|
||||
}
|
||||
m_bfsQueueMin = 0;
|
||||
m_bfsQueueCountPushed = 0;
|
||||
m_bfsQueueCountPopped = 0;
|
||||
m_bfsQueueCountRepeated = 0;
|
||||
m_bfsQueueCountSkipped = 0;
|
||||
}
|
||||
|
||||
static int HeuristicDistance(int nX, int nY, int startX, int startY)
|
||||
{
|
||||
// 8-way connectivity yields a shortest path that
|
||||
// consists of a diagonal and a non-diagonal part.
|
||||
// ...+
|
||||
// : |
|
||||
// :..|
|
||||
// : /:
|
||||
// :/ :
|
||||
// +..:
|
||||
const int distX = std::abs(nX - startX);
|
||||
const int distY = std::abs(nY - startY);
|
||||
const int smaller = std::min(distX, distY);
|
||||
const int bigger = std::max(distX, distY);
|
||||
// diagonal number of steps: smaller
|
||||
// non-diagonal number of steps: bigger - smaller
|
||||
return smaller * (7 - 5) + bigger * 5;
|
||||
}
|
||||
|
||||
// Calculates points and passes to go from start to goal.
|
||||
|
@ -1700,199 +1728,350 @@ void CTaskGoto::BeamInit()
|
|||
// ERR_CONTINUE if not done yet
|
||||
// goalRadius: distance at which we must approach the goal
|
||||
|
||||
Error CTaskGoto::BeamSearch(const glm::vec3 &start, const glm::vec3 &goal,
|
||||
float goalRadius)
|
||||
Error CTaskGoto::PathFindingSearch(const glm::vec3 &start, const glm::vec3 &goal,
|
||||
float goalRadius)
|
||||
{
|
||||
float step, len;
|
||||
int nbIter;
|
||||
|
||||
m_bmStep ++;
|
||||
|
||||
len = Math::DistanceProjected(start, goal);
|
||||
step = len/BEAM_ACCURACY;
|
||||
if ( step < BM_DIM_STEP*2.1f ) step = BM_DIM_STEP*2.1f;
|
||||
if ( step > 20.0f ) step = 20.0f;
|
||||
nbIter = 200; // in order not to lower the framerate
|
||||
m_bmIterCounter = 0;
|
||||
return BeamExplore(start, start, goal, goalRadius, 165.0f*Math::PI/180.0f, 22, step, 0, nbIter);
|
||||
}
|
||||
// Relative postion and distance to neighbors.
|
||||
static const int dXs[8] = {-1, 0, 1, -1, 1, -1, 0, 1};
|
||||
static const int dYs[8] = {-1, -1, -1, 0, 0, 1, 1, 1};
|
||||
// These are the costs of the edges. They must be less than the number of buckets in the queue.
|
||||
static const int32_t dDist[8] = {7, 5, 7, 5, 5, 7, 5, 7};
|
||||
|
||||
// prevPos: previous position
|
||||
// curPos: current position
|
||||
// goalPos: position that seeks to achieve
|
||||
// angle: angle to the goal we explores
|
||||
// nbDiv: number of subdivisions being done with angle
|
||||
// step length of a step
|
||||
// i number of recursions made
|
||||
// nbIter maximum number of iterations you have the right to make before temporarily interrupt
|
||||
const int startX = static_cast<int>((start.x+1600.0f)/BM_DIM_STEP);
|
||||
const int startY = static_cast<int>((start.z+1600.0f)/BM_DIM_STEP);
|
||||
const int goalX = static_cast<int>((goal.x+1600.0f)/BM_DIM_STEP);
|
||||
const int goalY = static_cast<int>((goal.z+1600.0f)/BM_DIM_STEP);
|
||||
|
||||
Error CTaskGoto::BeamExplore(const glm::vec3 &prevPos, const glm::vec3 &curPos,
|
||||
const glm::vec3 &goalPos, float goalRadius,
|
||||
float angle, int nbDiv, float step,
|
||||
int i, int nbIter)
|
||||
{
|
||||
glm::vec3 newPos;
|
||||
Error ret;
|
||||
int iDiv, iClear, iLar;
|
||||
|
||||
iLar = 0;
|
||||
if ( i >= MAXPOINTS ) return ERR_GOTO_ITER; // too many recursions
|
||||
|
||||
m_bmTotal = i;
|
||||
|
||||
if ( m_bmIter[i] == -1 )
|
||||
if (m_bfsQueueCountPushed == 0) // New search
|
||||
{
|
||||
m_bmIter[i] = 0;
|
||||
|
||||
if ( i == 0 )
|
||||
if (startX == goalX && startY == goalY)
|
||||
{
|
||||
m_bmPoints[i] = curPos;
|
||||
m_bmPoints[0] = start;
|
||||
m_bmPoints[1] = goal;
|
||||
m_bmTotal = 1;
|
||||
return ERR_OK;
|
||||
}
|
||||
// Enqueue the goal node
|
||||
if ( goalX >= 0 && goalX < m_bmSize &&
|
||||
goalY >= 0 && goalY < m_bmSize )
|
||||
{
|
||||
const int indexInMap = goalY * m_bmSize + goalX;
|
||||
const int totalDistance = HeuristicDistance(goalX, goalY, startX, startY);
|
||||
m_bfsQueueMin = totalDistance;
|
||||
m_bfsDistances[indexInMap] = 0;
|
||||
m_bfsQueue[totalDistance % NUMQUEUEBUCKETS].push_back(indexInMap);
|
||||
m_bfsQueueCountPushed += 1;
|
||||
BitmapSetDot(1, goalX, goalY); // Mark as enqueued
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !BitmapTestLine(prevPos, curPos, angle/nbDiv, true) ) return ERR_GOTO_IMPOSSIBLE;
|
||||
m_bfsQueueMin = std::numeric_limits<int>::max();
|
||||
}
|
||||
|
||||
m_bmPoints[i] = curPos;
|
||||
|
||||
if ( Math::DistanceProjected(curPos, goalPos)-goalRadius <= step )
|
||||
// Enqueue nodes around the goal
|
||||
if (goalRadius > 0.0f)
|
||||
{
|
||||
const int minX = std::max(0, static_cast<int>((goal.x-goalRadius+1600.0f)/BM_DIM_STEP));
|
||||
const int minY = std::max(0, static_cast<int>((goal.z-goalRadius+1600.0f)/BM_DIM_STEP));
|
||||
const int maxX = std::min(m_bmSize-1, static_cast<int>((goal.x+goalRadius+1600.0f)/BM_DIM_STEP));
|
||||
const int maxY = std::min(m_bmSize-1, static_cast<int>((goal.z+goalRadius+1600.0f)/BM_DIM_STEP));
|
||||
for (int y = minY; y <= maxY; ++y)
|
||||
{
|
||||
if ( goalRadius == 0.0f )
|
||||
for (int x = minX; x <= maxX; ++x)
|
||||
{
|
||||
newPos = goalPos;
|
||||
}
|
||||
else
|
||||
{
|
||||
newPos = BeamPoint(curPos, goalPos, 0, Math::DistanceProjected(curPos, goalPos)-goalRadius);
|
||||
}
|
||||
if ( BitmapTestLine(curPos, newPos, angle/nbDiv, false) )
|
||||
{
|
||||
m_bmPoints[i+1] = newPos;
|
||||
m_bmTotal = i+1;
|
||||
return ERR_OK;
|
||||
float floatX = (x + 0.5f) * BM_DIM_STEP - 1600.0f;
|
||||
float floatY = (y + 0.5f) * BM_DIM_STEP - 1600.0f;
|
||||
if (std::hypot(floatX-goal.x, floatY-goal.z) <= goalRadius &&
|
||||
BitmapTestDotIsVisitable(x, y) &&
|
||||
!BitmapTestDot(1, x, y))
|
||||
{
|
||||
const int indexInMap = y * m_bmSize + x;
|
||||
const int totalDistance = HeuristicDistance(x, y, startX, startY);
|
||||
m_bfsQueueMin = std::min(m_bfsQueueMin, totalDistance);
|
||||
m_bfsDistances[indexInMap] = 0;
|
||||
m_bfsQueue[totalDistance % NUMQUEUEBUCKETS].push_back(indexInMap);
|
||||
m_bfsQueueCountPushed += 1;
|
||||
BitmapSetDot(1, x, y); // Mark as enqueued
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( iLar >= m_bmIter[i] )
|
||||
m_bmIterCounter = 0;
|
||||
|
||||
while (m_bfsQueueCountPushed != m_bfsQueueCountPopped)
|
||||
{
|
||||
newPos = BeamPoint(curPos, goalPos, 0, step);
|
||||
ret = BeamExplore(curPos, newPos, goalPos, goalRadius, angle, nbDiv, step, i+1, nbIter);
|
||||
if ( ret != ERR_GOTO_IMPOSSIBLE ) return ret;
|
||||
m_bmIter[i] = iLar+1;
|
||||
for ( iClear=i+1 ; iClear<=MAXPOINTS ; iClear++ ) m_bmIter[iClear] = -1;
|
||||
// Pop a node from the queue
|
||||
while (m_bfsQueue[m_bfsQueueMin % NUMQUEUEBUCKETS].empty())
|
||||
{
|
||||
m_bfsQueueMin += 1;
|
||||
if (m_bfsQueueMin % NUMQUEUEBUCKETS == 0 && !m_bfsQueue[NUMQUEUEBUCKETS].empty())
|
||||
{
|
||||
// Process nodes with oversized costs.
|
||||
const size_t countBefore = m_bfsQueue[NUMQUEUEBUCKETS].size();
|
||||
for (size_t i = 0; i < m_bfsQueue[NUMQUEUEBUCKETS].size();)
|
||||
{
|
||||
const uint32_t indexInMap = m_bfsQueue[NUMQUEUEBUCKETS][i];
|
||||
const int x = indexInMap % m_bmSize;
|
||||
const int y = indexInMap / m_bmSize;
|
||||
const int32_t distance = m_bfsDistances[indexInMap];
|
||||
const int totalDistance = distance + HeuristicDistance(x, y, startX, startY);
|
||||
if (totalDistance < m_bfsQueueMin + NUMQUEUEBUCKETS)
|
||||
{
|
||||
// Move node to a regular bucket.
|
||||
m_bfsQueue[totalDistance % NUMQUEUEBUCKETS].push_back(indexInMap);
|
||||
m_bfsQueue[NUMQUEUEBUCKETS][i] = m_bfsQueue[NUMQUEUEBUCKETS].back();
|
||||
m_bfsQueue[NUMQUEUEBUCKETS].pop_back();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Look at next node.
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
const size_t countAfter = m_bfsQueue[NUMQUEUEBUCKETS].size();
|
||||
GetLogger()->Debug("Redistributed %lu of %lu nodes from the bucket with oversized costs.\n",
|
||||
countBefore - countAfter, countBefore);
|
||||
}
|
||||
}
|
||||
auto& bucket = m_bfsQueue[m_bfsQueueMin % NUMQUEUEBUCKETS];
|
||||
const uint32_t indexInMap = bucket.back();
|
||||
bucket.pop_back();
|
||||
m_bfsQueueCountPopped += 1;
|
||||
|
||||
const int x = indexInMap % m_bmSize;
|
||||
const int y = indexInMap / m_bmSize;
|
||||
const int32_t distance = m_bfsDistances[indexInMap];
|
||||
const int totalDistance = distance + HeuristicDistance(x, y, startX, startY);
|
||||
|
||||
if (totalDistance != m_bfsQueueMin)
|
||||
{
|
||||
if (totalDistance < m_bfsQueueMin)
|
||||
{
|
||||
// This node has been updated to a lower cost and has allready been processed.
|
||||
m_bfsQueueCountSkipped += 1;
|
||||
// GetLogger()->Debug("Skipping node with smaller distance, distance: %d, totalDistance: %d, m_bfsQueueMin: %d\n",
|
||||
// distance, totalDistance, m_bfsQueueMin);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (totalDistance < m_bfsQueueMin + NUMQUEUEBUCKETS)
|
||||
{
|
||||
// Move node to a regular bucket.
|
||||
m_bfsQueue[totalDistance % NUMQUEUEBUCKETS].push_back(indexInMap);
|
||||
m_bfsQueueCountPushed += 1;
|
||||
GetLogger()->Debug("Moving node with bigger distance into regular bucket, distance: %d, totalDistance: %d, m_bfsQueueMin: %d\n",
|
||||
distance, totalDistance, m_bfsQueueMin);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Move node to the bucket with oversized costs.
|
||||
m_bfsQueue[NUMQUEUEBUCKETS].push_back(indexInMap);
|
||||
m_bfsQueueCountPushed += 1;
|
||||
GetLogger()->Debug("Moving node with bigger distance into bucket with oversized costs, distance: %d, totalDistance: %d, m_bfsQueueMin: %d\n",
|
||||
distance, totalDistance, m_bfsQueueMin);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (x == startX && y == startY)
|
||||
{
|
||||
// We have reached the start.
|
||||
// Follow decreasing distances to find the path.
|
||||
m_bmPoints[0] = start;
|
||||
int btX = x;
|
||||
int btY = y;
|
||||
for (m_bmTotal = 1; m_bmTotal < MAXPOINTS; ++m_bmTotal)
|
||||
{
|
||||
int bestX = -1;
|
||||
int bestY = -1;
|
||||
int32_t bestDistance = std::numeric_limits<int32_t>::max();
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
const int nX = btX + dXs[i];
|
||||
const int nY = btY + dYs[i];
|
||||
if (!BitmapTestDot(1, nX, nY)) continue;
|
||||
const int32_t nDistance = m_bfsDistances[nY * m_bmSize + nX];
|
||||
if (nDistance < bestDistance)
|
||||
{
|
||||
bestX = nX;
|
||||
bestY = nY;
|
||||
bestDistance = nDistance;
|
||||
}
|
||||
}
|
||||
if (bestX == -1)
|
||||
{
|
||||
GetLogger()->Debug("Failed to find node parent\n");
|
||||
return ERR_GOTO_ITER;
|
||||
}
|
||||
btX = bestX;
|
||||
btY = bestY;
|
||||
if (btX == goalX && btY == goalY)
|
||||
{
|
||||
m_bmPoints[m_bmTotal] = goal;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bmPoints[m_bmTotal].x = (btX + 0.5f) * BM_DIM_STEP - 1600.f;
|
||||
m_bmPoints[m_bmTotal].z = (btY + 0.5f) * BM_DIM_STEP - 1600.f;
|
||||
}
|
||||
|
||||
if (bestDistance == 0)
|
||||
{
|
||||
if (goalRadius > 0.0f)
|
||||
{
|
||||
// Find a more exact position by repeatedly bisecting the interval.
|
||||
const float r2 = goalRadius * goalRadius;
|
||||
glm::vec3 inside = m_bmPoints[m_bmTotal] - goal;
|
||||
glm::vec3 outside = m_bmPoints[m_bmTotal-1] - goal;
|
||||
glm::vec3 mid = (inside + outside) * 0.5f;
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{
|
||||
if (mid.x*mid.x + mid.z*mid.z < r2)
|
||||
{
|
||||
inside = mid;
|
||||
}
|
||||
else
|
||||
{
|
||||
outside = mid;
|
||||
}
|
||||
mid = (inside + outside) * 0.5f;
|
||||
}
|
||||
m_bmPoints[m_bmTotal] = mid + goal;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const float distanceToGoal = Math::DistanceProjected(m_bmPoints[m_bmTotal], goal);
|
||||
GetLogger()->Debug("Found path to goal with %d nodes and %d cost. Final distance to goal: %f\n", m_bmTotal + 1, totalDistance, distanceToGoal);
|
||||
GetLogger()->Debug("m_bmStep: %d\n", m_bmStep);
|
||||
GetLogger()->Debug("m_bfsQueueMin: %d mod %d = %d\n", m_bfsQueueMin, NUMQUEUEBUCKETS, m_bfsQueueMin % NUMQUEUEBUCKETS);
|
||||
GetLogger()->Debug("m_bfsQueueCountPushed: %d\n", m_bfsQueueCountPushed);
|
||||
GetLogger()->Debug("m_bfsQueueCountPopped: %d\n", m_bfsQueueCountPopped);
|
||||
GetLogger()->Debug("m_bfsQueueCountRepeated: %d\n", m_bfsQueueCountRepeated);
|
||||
GetLogger()->Debug("m_bfsQueueCountSkipped: %d\n", m_bfsQueueCountSkipped);
|
||||
GetLogger()->Debug("m_bfsQueue sizes:\n");
|
||||
for (size_t i = 0; i < m_bfsQueue.size(); ++i)
|
||||
{
|
||||
if (!m_bfsQueue[i].empty()) GetLogger()->Debug(" %lu: %lu\n", i, m_bfsQueue[i].size());
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
// Expand the node
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
const int nX = x + dXs[i];
|
||||
const int nY = y + dYs[i];
|
||||
if (BitmapTestDotIsVisitable(nX, nY))
|
||||
{
|
||||
const int neighborIndexInMap = nY * m_bmSize + nX;
|
||||
const int32_t newDistance = distance + dDist[i];
|
||||
if (BitmapTestDot(1, nX, nY))
|
||||
{
|
||||
// We have seen this node before.
|
||||
// Only enqueue previously seen nodes if this is a shorter path.
|
||||
if (newDistance < m_bfsDistances[neighborIndexInMap])
|
||||
{
|
||||
m_bfsQueueCountRepeated += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Enqueue this neighbor
|
||||
const int32_t newTotalDistance = newDistance + HeuristicDistance(nX, nY, startX, startY);
|
||||
m_bfsDistances[neighborIndexInMap] = newDistance;
|
||||
m_bfsQueue[newTotalDistance % NUMQUEUEBUCKETS].push_back(neighborIndexInMap);
|
||||
m_bfsQueueCountPushed += 1;
|
||||
BitmapSetDot(1, nX, nY); // Mark as enqueued
|
||||
}
|
||||
}
|
||||
|
||||
// Limit the number of iterations per frame.
|
||||
m_bmIterCounter ++;
|
||||
if ( m_bmIterCounter >= nbIter ) return ERR_CONTINUE;
|
||||
}
|
||||
iLar ++;
|
||||
|
||||
for ( iDiv=1 ; iDiv<=nbDiv ; iDiv++ )
|
||||
{
|
||||
if ( iLar >= m_bmIter[i] )
|
||||
{
|
||||
newPos = BeamPoint(curPos, goalPos, angle*iDiv/nbDiv, step);
|
||||
ret = BeamExplore(curPos, newPos, goalPos, goalRadius, angle, nbDiv, step, i+1, nbIter);
|
||||
if ( ret != ERR_GOTO_IMPOSSIBLE ) return ret;
|
||||
m_bmIter[i] = iLar+1;
|
||||
for ( iClear=i+1 ; iClear<=MAXPOINTS ; iClear++ ) m_bmIter[iClear] = -1;
|
||||
m_bmIterCounter ++;
|
||||
if ( m_bmIterCounter >= nbIter ) return ERR_CONTINUE;
|
||||
}
|
||||
iLar ++;
|
||||
|
||||
if ( iLar >= m_bmIter[i] )
|
||||
{
|
||||
newPos = BeamPoint(curPos, goalPos, -angle*iDiv/nbDiv, step);
|
||||
ret = BeamExplore(curPos, newPos, goalPos, goalRadius, angle, nbDiv, step, i+1, nbIter);
|
||||
if ( ret != ERR_GOTO_IMPOSSIBLE ) return ret;
|
||||
m_bmIter[i] = iLar+1;
|
||||
for ( iClear=i+1 ; iClear<=MAXPOINTS ; iClear++ ) m_bmIter[iClear] = -1;
|
||||
m_bmIterCounter ++;
|
||||
if ( m_bmIterCounter >= nbIter ) return ERR_CONTINUE;
|
||||
}
|
||||
iLar ++;
|
||||
if ( m_bmIterCounter >= NB_ITER ) return ERR_CONTINUE;
|
||||
}
|
||||
|
||||
return ERR_GOTO_IMPOSSIBLE;
|
||||
}
|
||||
|
||||
// Is a right "start-goal". Calculates the point located at the distance "step"
|
||||
// from the point "start" and an angle "angle" with the right.
|
||||
|
||||
glm::vec3 CTaskGoto::BeamPoint(const glm::vec3 &startPoint,
|
||||
const glm::vec3 &goalPoint,
|
||||
float angle, float step)
|
||||
{
|
||||
glm::vec3 resPoint;
|
||||
float goalAngle;
|
||||
|
||||
goalAngle = Math::RotateAngle(goalPoint.x-startPoint.x, goalPoint.z-startPoint.z);
|
||||
|
||||
resPoint.x = startPoint.x + cosf(goalAngle+angle)*step;
|
||||
resPoint.z = startPoint.z + sinf(goalAngle+angle)*step;
|
||||
resPoint.y = 0.0f;
|
||||
|
||||
return resPoint;
|
||||
}
|
||||
|
||||
// Tests if a path along a straight line is possible.
|
||||
|
||||
bool CTaskGoto::BitmapTestLine(const glm::vec3 &start, const glm::vec3 &goal,
|
||||
float stepAngle, bool bSecond)
|
||||
bool CTaskGoto::BitmapTestLine(const glm::vec3 &start, const glm::vec3 &goal)
|
||||
{
|
||||
glm::vec3 pos, inc;
|
||||
float dist, step;
|
||||
float distNoB2;
|
||||
int i, max, x, y;
|
||||
|
||||
if ( m_bmArray == nullptr ) return true;
|
||||
|
||||
dist = Math::DistanceProjected(start, goal);
|
||||
if ( dist == 0.0f ) return true;
|
||||
step = BM_DIM_STEP*0.5f;
|
||||
const glm::vec2 startInGrid = glm::vec2((start.x+1600.0f)/BM_DIM_STEP, (start.z+1600.0f)/BM_DIM_STEP);
|
||||
const glm::vec2 goalInGrid = glm::vec2((goal.x+1600.0f)/BM_DIM_STEP, (goal.z+1600.0f)/BM_DIM_STEP);
|
||||
|
||||
inc.x = (goal.x-start.x)*step/dist;
|
||||
inc.z = (goal.z-start.z)*step/dist;
|
||||
const int startXInt = static_cast<int>(startInGrid.x);
|
||||
const int startYInt = static_cast<int>(startInGrid.y);
|
||||
const int goalXInt = static_cast<int>(goalInGrid.x);
|
||||
const int goalYInt = static_cast<int>(goalInGrid.y);
|
||||
|
||||
pos = start;
|
||||
|
||||
if ( bSecond )
|
||||
if (startXInt == goalXInt && startYInt == goalYInt)
|
||||
{
|
||||
x = static_cast<int>((pos.x+1600.0f)/BM_DIM_STEP);
|
||||
y = static_cast<int>((pos.z+1600.0f)/BM_DIM_STEP);
|
||||
BitmapSetDot(1, x, y); // puts the flag as the starting point
|
||||
return true;
|
||||
}
|
||||
|
||||
max = static_cast<int>(dist/step);
|
||||
if ( max == 0 ) max = 1;
|
||||
distNoB2 = BM_DIM_STEP*sqrtf(2.0f)/sinf(stepAngle);
|
||||
for ( i=0 ; i<max ; i++ )
|
||||
// Grid traversal based on
|
||||
// Amanatides, John, and Andrew Woo. "A fast voxel traversal algorithm for ray tracing." Eurographics. Vol. 87. No. 3. 1987.
|
||||
// http://www.cse.yorku.ca/~amana/research/grid.pdf
|
||||
|
||||
glm::vec2 dirInGrid = goalInGrid - startInGrid;
|
||||
dirInGrid /= std::hypot(dirInGrid.x, dirInGrid.y);
|
||||
const int stepX = dirInGrid.x > 0.0f ? 1 : -1;
|
||||
const int stepY = dirInGrid.y > 0.0f ? 1 : -1;
|
||||
|
||||
// At what t does the ray enter the next cell?
|
||||
float tMaxX =
|
||||
dirInGrid.x > 0.0 ? (std::floor(startInGrid.x) - startInGrid.x + 1) / dirInGrid.x :
|
||||
dirInGrid.x < 0.0 ? (std::floor(startInGrid.x) - startInGrid.x) / dirInGrid.x :
|
||||
std::numeric_limits<float>::infinity();
|
||||
float tMaxY =
|
||||
dirInGrid.y > 0.0 ? (std::floor(startInGrid.y) - startInGrid.y + 1) / dirInGrid.y :
|
||||
dirInGrid.y < 0.0 ? (std::floor(startInGrid.y) - startInGrid.y) / dirInGrid.y :
|
||||
std::numeric_limits<float>::infinity();
|
||||
|
||||
// How much t is needed to step from one column/row to another?
|
||||
// stepX = dir.x * t
|
||||
// stepX / dir.x = t
|
||||
const float tDeltaX = static_cast<float>(stepX) / dirInGrid.x;
|
||||
const float tDeltaY = static_cast<float>(stepY) / dirInGrid.y;
|
||||
|
||||
// Traverse the grid
|
||||
const int numIntersections =
|
||||
std::abs(goalXInt - startXInt) +
|
||||
std::abs(goalYInt - startYInt);
|
||||
int x = startXInt;
|
||||
int y = startYInt;
|
||||
|
||||
for ( int i = 0; i < numIntersections; ++i )
|
||||
{
|
||||
if ( i == max-1 )
|
||||
if ( tMaxX < tMaxY )
|
||||
{
|
||||
pos = goal; // tests the point of arrival
|
||||
tMaxX += tDeltaX;
|
||||
x += stepX;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos.x += inc.x;
|
||||
pos.z += inc.z;
|
||||
tMaxY += tDeltaY;
|
||||
y += stepY;
|
||||
}
|
||||
|
||||
x = static_cast<int>((pos.x+1600.0f)/BM_DIM_STEP);
|
||||
y = static_cast<int>((pos.z+1600.0f)/BM_DIM_STEP);
|
||||
|
||||
if ( bSecond )
|
||||
if ( BitmapTestDot(0, x, y) )
|
||||
{
|
||||
if ( i > 2 && BitmapTestDot(1, x, y) ) return false;
|
||||
|
||||
if ( step*(i+1) > distNoB2 && i < max-2 )
|
||||
{
|
||||
BitmapSetDot(1, x, y);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( BitmapTestDot(0, x, y) ) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2096,10 +2275,14 @@ void CTaskGoto::BitmapTerrain(int minx, int miny, int maxx, int maxy)
|
|||
|
||||
bool CTaskGoto::BitmapOpen()
|
||||
{
|
||||
BitmapClose();
|
||||
|
||||
m_bmSize = static_cast<int>(3200.0f/BM_DIM_STEP);
|
||||
m_bmArray = std::make_unique<unsigned char[]>(m_bmSize * m_bmSize / 8 * 2);
|
||||
if (m_bmArray.get() == nullptr) m_bmArray = std::make_unique<unsigned char[]>(m_bmSize * m_bmSize / 8 * 2);
|
||||
memset(m_bmArray.get(), 0, m_bmSize*m_bmSize/8*2);
|
||||
if (m_bfsDistances.get() == nullptr) m_bfsDistances = std::make_unique<int32_t[]>(m_bmSize * m_bmSize);
|
||||
for (auto& bucket : m_bfsQueue)
|
||||
{
|
||||
bucket.reserve(256);
|
||||
}
|
||||
m_bmChanged = true;
|
||||
|
||||
m_bmOffset = m_bmSize/2;
|
||||
|
@ -2206,3 +2389,17 @@ bool CTaskGoto::BitmapTestDot(int rank, int x, int y)
|
|||
|
||||
return m_bmArray[rank*m_bmLine*m_bmSize + m_bmLine*y + x/8] & (1<<x%8);
|
||||
}
|
||||
|
||||
bool CTaskGoto::BitmapTestDotIsVisitable(int x, int y)
|
||||
{
|
||||
if ( x < 0 || x >= m_bmSize ||
|
||||
y < 0 || y >= m_bmSize ) return false;
|
||||
|
||||
if ( x < m_bmMinX || x > m_bmMaxX ||
|
||||
y < m_bmMinY || y > m_bmMaxY )
|
||||
{
|
||||
BitmapTerrain(x-10,y-10, x+10,y+10); // remade a layer
|
||||
}
|
||||
|
||||
return !(m_bmArray[m_bmLine*y + x/8] & (1<<x%8));
|
||||
}
|
||||
|
|
|
@ -23,13 +23,15 @@
|
|||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
|
||||
class CObject;
|
||||
|
||||
const int MAXPOINTS = 500;
|
||||
|
||||
const int MAXPOINTS = 50000;
|
||||
const int NUMQUEUEBUCKETS = 32;
|
||||
|
||||
enum TaskGotoGoal
|
||||
{
|
||||
|
@ -94,14 +96,12 @@ protected:
|
|||
void ComputeRepulse(glm::vec2& dir);
|
||||
void ComputeFlyingRepulse(float &dir);
|
||||
|
||||
int BeamShortcut();
|
||||
void BeamStart();
|
||||
void BeamInit();
|
||||
Error BeamSearch(const glm::vec3 &start, const glm::vec3 &goal, float goalRadius);
|
||||
Error BeamExplore(const glm::vec3 &prevPos, const glm::vec3 &curPos, const glm::vec3 &goalPos, float goalRadius, float angle, int nbDiv, float step, int i, int nbIter);
|
||||
glm::vec3 BeamPoint(const glm::vec3 &startPoint, const glm::vec3 &goalPoint, float angle, float step);
|
||||
int PathFindingShortcut();
|
||||
void PathFindingStart();
|
||||
void PathFindingInit();
|
||||
Error PathFindingSearch(const glm::vec3 &start, const glm::vec3 &goal, float goalRadius);
|
||||
|
||||
bool BitmapTestLine(const glm::vec3 &start, const glm::vec3 &goal, float stepAngle, bool bSecond);
|
||||
bool BitmapTestLine(const glm::vec3 &start, const glm::vec3 &goal);
|
||||
void BitmapObject();
|
||||
void BitmapTerrain(const glm::vec3 &min, const glm::vec3 &max);
|
||||
void BitmapTerrain(int minx, int miny, int maxx, int maxy);
|
||||
|
@ -112,10 +112,11 @@ protected:
|
|||
void BitmapSetDot(int rank, int x, int y);
|
||||
void BitmapClearDot(int rank, int x, int y);
|
||||
bool BitmapTestDot(int rank, int x, int y);
|
||||
bool BitmapTestDotIsVisitable(int x, int y);
|
||||
|
||||
protected:
|
||||
glm::vec3 m_goal = { 0, 0, 0 };
|
||||
glm::vec3 m_goalObject = { 0, 0, 0 };
|
||||
glm::vec3 m_goal = { 0, 0, 0 };
|
||||
glm::vec3 m_goalObject = { 0, 0, 0 };
|
||||
float m_angle = 0.0f;
|
||||
float m_altitude = 0.0f;
|
||||
TaskGotoCrash m_crashMode = TGC_DEFAULT;
|
||||
|
@ -136,10 +137,17 @@ protected:
|
|||
int m_bmSize = 0; // width or height of the table
|
||||
int m_bmOffset = 0; // m_bmSize/2
|
||||
int m_bmLine = 0; // increment line m_bmSize/8
|
||||
std::unique_ptr<unsigned char[]> m_bmArray; // bit table
|
||||
std::unique_ptr<unsigned char[]> m_bmArray; // Bit table
|
||||
std::unique_ptr<int32_t[]> m_bfsDistances; // Distances to the goal for breadth-first search.
|
||||
std::array<std::vector<uint32_t>, NUMQUEUEBUCKETS + 1> m_bfsQueue; // Priority queue with indices to nodes. Nodes are sorted into buckets. The last bucket contains oversized costs.
|
||||
int m_bfsQueueMin = 0; // Front of the queue. This value mod 8 is the index to the bucket with the next node to be expanded.
|
||||
int m_bfsQueueCountPushed = 0; // Number of nodes inserted into the queue.
|
||||
int m_bfsQueueCountPopped = 0; // Number of nodes extacted from the queue.
|
||||
int m_bfsQueueCountRepeated = 0; // Number of nodes re-inserted into the queue.
|
||||
int m_bfsQueueCountSkipped = 0; // Number of nodes skipped because of unexpected distance (likely re-added).
|
||||
int m_bmMinX = 0, m_bmMinY = 0;
|
||||
int m_bmMaxX = 0, m_bmMaxY = 0;
|
||||
int m_bmTotal = 0; // number of points in m_bmPoints
|
||||
int m_bmTotal = 0; // index of final point in m_bmPoints
|
||||
int m_bmIndex = 0; // index in m_bmPoints
|
||||
glm::vec3 m_bmPoints[MAXPOINTS+2];
|
||||
signed char m_bmIter[MAXPOINTS+2] = {};
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
#include "ui/controls/window.h"
|
||||
|
||||
#include "ui/screen/screen.h"
|
||||
#include "ui/screen/screen_apperance.h"
|
||||
#include "ui/screen/screen_appearance.h"
|
||||
#include "ui/screen/screen_io_read.h"
|
||||
#include "ui/screen/screen_io_write.h"
|
||||
#include "ui/screen/screen_level_list.h"
|
||||
|
@ -81,7 +81,7 @@ CMainUserInterface::CMainUserInterface()
|
|||
|
||||
m_dialog = std::make_unique<CMainDialog>();
|
||||
|
||||
m_screenAppearance = std::make_unique<CScreenApperance>();
|
||||
m_screenAppearance = std::make_unique<CScreenAppearance>();
|
||||
m_screenLevelList = std::make_unique<CScreenLevelList>(m_dialog.get());
|
||||
m_screenIORead = std::make_unique<CScreenIORead>(m_screenLevelList.get());
|
||||
m_screenIOWrite = std::make_unique<CScreenIOWrite>(m_screenLevelList.get());
|
||||
|
@ -178,7 +178,7 @@ void CMainUserInterface::ChangePhase(Phase phase)
|
|||
{
|
||||
m_currentScreen = m_screenPlayerSelect.get();
|
||||
}
|
||||
if (m_phase == PHASE_APPERANCE)
|
||||
if (m_phase == PHASE_APPEARANCE)
|
||||
{
|
||||
m_currentScreen = m_screenAppearance.get();
|
||||
}
|
||||
|
@ -791,7 +791,7 @@ bool CMainUserInterface::GetPlusExplorer()
|
|||
|
||||
bool CMainUserInterface::GetGamerOnlyHead()
|
||||
{
|
||||
if (m_phase == PHASE_APPERANCE)
|
||||
if (m_phase == PHASE_APPEARANCE)
|
||||
return m_screenAppearance->GetGamerOnlyHead();
|
||||
|
||||
return false;
|
||||
|
@ -799,7 +799,7 @@ bool CMainUserInterface::GetGamerOnlyHead()
|
|||
|
||||
float CMainUserInterface::GetPersoAngle()
|
||||
{
|
||||
if (m_phase == PHASE_APPERANCE)
|
||||
if (m_phase == PHASE_APPEARANCE)
|
||||
return m_screenAppearance->GetPersoAngle();
|
||||
|
||||
return 0.0f;
|
||||
|
|
|
@ -46,7 +46,7 @@ class CInterface;
|
|||
class CMainDialog;
|
||||
|
||||
class CScreen;
|
||||
class CScreenApperance;
|
||||
class CScreenAppearance;
|
||||
class CScreenIORead;
|
||||
class CScreenIOWrite;
|
||||
class CScreenLevelList;
|
||||
|
@ -114,7 +114,7 @@ protected:
|
|||
std::unique_ptr<CMainDialog> m_dialog;
|
||||
|
||||
CScreen* m_currentScreen;
|
||||
std::unique_ptr<CScreenApperance> m_screenAppearance;
|
||||
std::unique_ptr<CScreenAppearance> m_screenAppearance;
|
||||
std::unique_ptr<CScreenIORead> m_screenIORead;
|
||||
std::unique_ptr<CScreenIOWrite> m_screenIOWrite;
|
||||
std::unique_ptr<CScreenLevelList> m_screenLevelList;
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
* along with this program. If not, see http://gnu.org/licenses
|
||||
*/
|
||||
|
||||
#include "ui/screen/screen_apperance.h"
|
||||
#include "ui/screen/screen_appearance.h"
|
||||
|
||||
#include "app/app.h"
|
||||
|
||||
|
@ -78,13 +78,13 @@ const int PERSO_COLOR[3*10*3] =
|
|||
0, 0, 0, //
|
||||
};
|
||||
|
||||
CScreenApperance::CScreenApperance()
|
||||
: m_apperanceTab(0),
|
||||
m_apperanceAngle(0.0f)
|
||||
CScreenAppearance::CScreenAppearance()
|
||||
: m_appearanceTab(0),
|
||||
m_appearanceAngle(0.0f)
|
||||
{
|
||||
}
|
||||
|
||||
void CScreenApperance::CreateInterface()
|
||||
void CScreenAppearance::CreateInterface()
|
||||
{
|
||||
CWindow* pw;
|
||||
CLabel* pl;
|
||||
|
@ -306,17 +306,17 @@ void CScreenApperance::CreateInterface()
|
|||
pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_PDEF);
|
||||
pb->SetState(STATE_SHADOW);
|
||||
|
||||
m_apperanceTab = 0;
|
||||
m_apperanceAngle = -0.6f;
|
||||
m_main->GetPlayerProfile()->LoadApperance();
|
||||
m_appearanceTab = 0;
|
||||
m_appearanceAngle = -0.6f;
|
||||
m_main->GetPlayerProfile()->LoadAppearance();
|
||||
UpdatePerso();
|
||||
m_main->ScenePerso();
|
||||
CameraPerso();
|
||||
}
|
||||
|
||||
bool CScreenApperance::EventProcess(const Event &event)
|
||||
bool CScreenAppearance::EventProcess(const Event &event)
|
||||
{
|
||||
PlayerApperance& apperance = m_main->GetPlayerProfile()->GetApperance();
|
||||
PlayerAppearance& appearance = m_main->GetPlayerProfile()->GetAppearance();
|
||||
switch( event.type )
|
||||
{
|
||||
case EVENT_KEY_DOWN:
|
||||
|
@ -339,13 +339,13 @@ bool CScreenApperance::EventProcess(const Event &event)
|
|||
break;
|
||||
|
||||
case EVENT_INTERFACE_PHEAD:
|
||||
m_apperanceTab = 0;
|
||||
m_appearanceTab = 0;
|
||||
UpdatePerso();
|
||||
m_main->ScenePerso();
|
||||
CameraPerso();
|
||||
break;
|
||||
case EVENT_INTERFACE_PBODY:
|
||||
m_apperanceTab = 1;
|
||||
m_appearanceTab = 1;
|
||||
UpdatePerso();
|
||||
m_main->ScenePerso();
|
||||
CameraPerso();
|
||||
|
@ -355,8 +355,8 @@ bool CScreenApperance::EventProcess(const Event &event)
|
|||
case EVENT_INTERFACE_PFACE2:
|
||||
case EVENT_INTERFACE_PFACE3:
|
||||
case EVENT_INTERFACE_PFACE4:
|
||||
apperance.face = event.type-EVENT_INTERFACE_PFACE1;
|
||||
apperance.DefHairColor();
|
||||
appearance.face = event.type-EVENT_INTERFACE_PFACE1;
|
||||
appearance.DefHairColor();
|
||||
UpdatePerso();
|
||||
m_main->ScenePerso();
|
||||
break;
|
||||
|
@ -371,7 +371,7 @@ bool CScreenApperance::EventProcess(const Event &event)
|
|||
case EVENT_INTERFACE_PGLASS7:
|
||||
case EVENT_INTERFACE_PGLASS8:
|
||||
case EVENT_INTERFACE_PGLASS9:
|
||||
apperance.glasses = event.type-EVENT_INTERFACE_PGLASS0;
|
||||
appearance.glasses = event.type-EVENT_INTERFACE_PGLASS0;
|
||||
UpdatePerso();
|
||||
m_main->ScenePerso();
|
||||
break;
|
||||
|
@ -418,25 +418,25 @@ bool CScreenApperance::EventProcess(const Event &event)
|
|||
break;
|
||||
|
||||
case EVENT_INTERFACE_PDEF:
|
||||
apperance.DefPerso();
|
||||
appearance.DefPerso();
|
||||
UpdatePerso();
|
||||
m_main->ScenePerso();
|
||||
break;
|
||||
|
||||
case EVENT_INTERFACE_PLROT:
|
||||
m_apperanceAngle += 0.2f;
|
||||
m_appearanceAngle += 0.2f;
|
||||
break;
|
||||
case EVENT_INTERFACE_PRROT:
|
||||
m_apperanceAngle -= 0.2f;
|
||||
m_appearanceAngle -= 0.2f;
|
||||
break;
|
||||
|
||||
case EVENT_INTERFACE_POK:
|
||||
m_main->GetPlayerProfile()->SaveApperance();
|
||||
m_main->GetPlayerProfile()->SaveAppearance();
|
||||
m_main->ChangePhase(PHASE_MAIN_MENU);
|
||||
break;
|
||||
|
||||
case EVENT_INTERFACE_PCANCEL:
|
||||
m_main->GetPlayerProfile()->LoadApperance(); // reload apperance from file
|
||||
m_main->GetPlayerProfile()->LoadAppearance(); // reload appearance from file
|
||||
m_main->ChangePhase(PHASE_PLAYER_SELECT);
|
||||
break;
|
||||
|
||||
|
@ -446,14 +446,14 @@ bool CScreenApperance::EventProcess(const Event &event)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool CScreenApperance::GetGamerOnlyHead()
|
||||
bool CScreenAppearance::GetGamerOnlyHead()
|
||||
{
|
||||
return m_apperanceTab == 0;
|
||||
return m_appearanceTab == 0;
|
||||
}
|
||||
|
||||
float CScreenApperance::GetPersoAngle()
|
||||
float CScreenAppearance::GetPersoAngle()
|
||||
{
|
||||
return m_apperanceAngle;
|
||||
return m_appearanceAngle;
|
||||
}
|
||||
|
||||
// Tests whether two colors are equal or nearly are.
|
||||
|
@ -467,7 +467,7 @@ static bool EqColor(const Gfx::Color &c1, const Gfx::Color &c2)
|
|||
|
||||
// Updates all the buttons for the character.
|
||||
|
||||
void CScreenApperance::UpdatePerso()
|
||||
void CScreenAppearance::UpdatePerso()
|
||||
{
|
||||
CWindow* pw;
|
||||
CLabel* pl;
|
||||
|
@ -478,7 +478,7 @@ void CScreenApperance::UpdatePerso()
|
|||
std::string name;
|
||||
int i;
|
||||
|
||||
PlayerApperance& apperance = m_main->GetPlayerProfile()->GetApperance();
|
||||
PlayerAppearance& appearance = m_main->GetPlayerProfile()->GetAppearance();
|
||||
|
||||
pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW5));
|
||||
if ( pw == nullptr ) return;
|
||||
|
@ -486,18 +486,18 @@ void CScreenApperance::UpdatePerso()
|
|||
pb = static_cast<CButton*>(pw->SearchControl(EVENT_INTERFACE_PHEAD));
|
||||
if ( pb != nullptr )
|
||||
{
|
||||
pb->SetState(STATE_CHECK, m_apperanceTab==0);
|
||||
pb->SetState(STATE_CHECK, m_appearanceTab==0);
|
||||
}
|
||||
pb = static_cast<CButton*>(pw->SearchControl(EVENT_INTERFACE_PBODY));
|
||||
if ( pb != nullptr )
|
||||
{
|
||||
pb->SetState(STATE_CHECK, m_apperanceTab==1);
|
||||
pb->SetState(STATE_CHECK, m_appearanceTab==1);
|
||||
}
|
||||
|
||||
pl = static_cast<CLabel*>(pw->SearchControl(EVENT_LABEL11));
|
||||
if ( pl != nullptr )
|
||||
{
|
||||
if ( m_apperanceTab == 0 )
|
||||
if ( m_appearanceTab == 0 )
|
||||
{
|
||||
pl->SetState(STATE_VISIBLE);
|
||||
GetResource(RES_TEXT, RT_PERSO_FACE, name);
|
||||
|
@ -512,7 +512,7 @@ void CScreenApperance::UpdatePerso()
|
|||
pl = static_cast<CLabel*>(pw->SearchControl(EVENT_LABEL12));
|
||||
if ( pl != nullptr )
|
||||
{
|
||||
if ( m_apperanceTab == 0 )
|
||||
if ( m_appearanceTab == 0 )
|
||||
{
|
||||
pl->SetState(STATE_VISIBLE);
|
||||
GetResource(RES_TEXT, RT_PERSO_GLASSES, name);
|
||||
|
@ -527,7 +527,7 @@ void CScreenApperance::UpdatePerso()
|
|||
pl = static_cast<CLabel*>(pw->SearchControl(EVENT_LABEL13));
|
||||
if ( pl != nullptr )
|
||||
{
|
||||
if ( m_apperanceTab == 0 ) GetResource(RES_TEXT, RT_PERSO_HAIR, name);
|
||||
if ( m_appearanceTab == 0 ) GetResource(RES_TEXT, RT_PERSO_HAIR, name);
|
||||
else GetResource(RES_TEXT, RT_PERSO_BAND, name);
|
||||
pl->SetName(name);
|
||||
}
|
||||
|
@ -535,7 +535,7 @@ void CScreenApperance::UpdatePerso()
|
|||
pl = static_cast<CLabel*>(pw->SearchControl(EVENT_LABEL14));
|
||||
if ( pl != nullptr )
|
||||
{
|
||||
if ( m_apperanceTab == 0 )
|
||||
if ( m_appearanceTab == 0 )
|
||||
{
|
||||
pl->ClearState(STATE_VISIBLE);
|
||||
}
|
||||
|
@ -551,23 +551,23 @@ void CScreenApperance::UpdatePerso()
|
|||
{
|
||||
pb = static_cast<CButton*>(pw->SearchControl(static_cast<EventType>(EVENT_INTERFACE_PFACE1+i)));
|
||||
if ( pb == nullptr ) break;
|
||||
pb->SetState(STATE_VISIBLE, m_apperanceTab==0);
|
||||
pb->SetState(STATE_CHECK, i==apperance.face);
|
||||
pb->SetState(STATE_VISIBLE, m_appearanceTab==0);
|
||||
pb->SetState(STATE_CHECK, i==appearance.face);
|
||||
}
|
||||
|
||||
for ( i=0 ; i<10 ; i++ )
|
||||
{
|
||||
pb = static_cast<CButton*>(pw->SearchControl(static_cast<EventType>(EVENT_INTERFACE_PGLASS0+i)));
|
||||
if ( pb == nullptr ) break;
|
||||
pb->SetState(STATE_VISIBLE, m_apperanceTab==0);
|
||||
pb->SetState(STATE_CHECK, i==apperance.glasses);
|
||||
pb->SetState(STATE_VISIBLE, m_appearanceTab==0);
|
||||
pb->SetState(STATE_CHECK, i==appearance.glasses);
|
||||
}
|
||||
|
||||
for ( i=0 ; i<3*3 ; i++ )
|
||||
{
|
||||
pc = static_cast<CColor*>(pw->SearchControl(static_cast<EventType>(EVENT_INTERFACE_PC0a+i)));
|
||||
if ( pc == nullptr ) break;
|
||||
if ( m_apperanceTab == 0 )
|
||||
if ( m_appearanceTab == 0 )
|
||||
{
|
||||
pc->ClearState(STATE_VISIBLE);
|
||||
}
|
||||
|
@ -579,29 +579,29 @@ void CScreenApperance::UpdatePerso()
|
|||
color.b = PERSO_COLOR[3*10*1+3*i+2]/255.0f;
|
||||
color.a = 0.0f;
|
||||
pc->SetColor(color);
|
||||
pc->SetState(STATE_CHECK, EqColor(color, apperance.colorCombi));
|
||||
pc->SetState(STATE_CHECK, EqColor(color, appearance.colorCombi));
|
||||
}
|
||||
|
||||
pc = static_cast<CColor*>(pw->SearchControl(static_cast<EventType>(EVENT_INTERFACE_PC0b+i)));
|
||||
if ( pc == nullptr ) break;
|
||||
color.r = PERSO_COLOR[3*10*2*m_apperanceTab+3*i+0]/255.0f;
|
||||
color.g = PERSO_COLOR[3*10*2*m_apperanceTab+3*i+1]/255.0f;
|
||||
color.b = PERSO_COLOR[3*10*2*m_apperanceTab+3*i+2]/255.0f;
|
||||
color.r = PERSO_COLOR[3*10*2*m_appearanceTab+3*i+0]/255.0f;
|
||||
color.g = PERSO_COLOR[3*10*2*m_appearanceTab+3*i+1]/255.0f;
|
||||
color.b = PERSO_COLOR[3*10*2*m_appearanceTab+3*i+2]/255.0f;
|
||||
color.a = 0.0f;
|
||||
pc->SetColor(color);
|
||||
pc->SetState(STATE_CHECK, EqColor(color, m_apperanceTab?apperance.colorBand:apperance.colorHair));
|
||||
pc->SetState(STATE_CHECK, EqColor(color, m_appearanceTab?appearance.colorBand:appearance.colorHair));
|
||||
}
|
||||
|
||||
for ( i=0 ; i<3 ; i++ )
|
||||
{
|
||||
ps = static_cast<CSlider*>(pw->SearchControl(static_cast<EventType>(EVENT_INTERFACE_PCRa+i)));
|
||||
if ( ps == nullptr ) break;
|
||||
ps->SetState(STATE_VISIBLE, m_apperanceTab==1);
|
||||
ps->SetState(STATE_VISIBLE, m_appearanceTab==1);
|
||||
}
|
||||
|
||||
if ( m_apperanceTab == 1 )
|
||||
if ( m_appearanceTab == 1 )
|
||||
{
|
||||
color = apperance.colorCombi;
|
||||
color = appearance.colorCombi;
|
||||
ps = static_cast<CSlider*>(pw->SearchControl(EVENT_INTERFACE_PCRa));
|
||||
if ( ps != nullptr ) ps->SetVisibleValue(color.r*255.0f);
|
||||
ps = static_cast<CSlider*>(pw->SearchControl(EVENT_INTERFACE_PCGa));
|
||||
|
@ -610,8 +610,8 @@ void CScreenApperance::UpdatePerso()
|
|||
if ( ps != nullptr ) ps->SetVisibleValue(color.b*255.0f);
|
||||
}
|
||||
|
||||
if ( m_apperanceTab == 0 ) color = apperance.colorHair;
|
||||
else color = apperance.colorBand;
|
||||
if ( m_appearanceTab == 0 ) color = appearance.colorHair;
|
||||
else color = appearance.colorBand;
|
||||
ps = static_cast<CSlider*>(pw->SearchControl(EVENT_INTERFACE_PCRb));
|
||||
if ( ps != nullptr ) ps->SetVisibleValue(color.r*255.0f);
|
||||
ps = static_cast<CSlider*>(pw->SearchControl(EVENT_INTERFACE_PCGb));
|
||||
|
@ -622,9 +622,9 @@ void CScreenApperance::UpdatePerso()
|
|||
|
||||
// Updates the camera for the character.
|
||||
|
||||
void CScreenApperance::CameraPerso()
|
||||
void CScreenAppearance::CameraPerso()
|
||||
{
|
||||
if ( m_apperanceTab == 0 )
|
||||
if ( m_appearanceTab == 0 )
|
||||
{
|
||||
SetCamera(0.325f, -0.15f, 5.0f);
|
||||
}
|
||||
|
@ -636,44 +636,44 @@ void CScreenApperance::CameraPerso()
|
|||
|
||||
// Sets a fixed color.
|
||||
|
||||
void CScreenApperance::FixPerso(int rank, int index)
|
||||
void CScreenAppearance::FixPerso(int rank, int index)
|
||||
{
|
||||
PlayerApperance& apperance = m_main->GetPlayerProfile()->GetApperance();
|
||||
if ( m_apperanceTab == 0 )
|
||||
PlayerAppearance& appearance = m_main->GetPlayerProfile()->GetAppearance();
|
||||
if ( m_appearanceTab == 0 )
|
||||
{
|
||||
if ( index == 1 )
|
||||
{
|
||||
apperance.colorHair.r = PERSO_COLOR[3*10*0+rank*3+0]/255.0f;
|
||||
apperance.colorHair.g = PERSO_COLOR[3*10*0+rank*3+1]/255.0f;
|
||||
apperance.colorHair.b = PERSO_COLOR[3*10*0+rank*3+2]/255.0f;
|
||||
appearance.colorHair.r = PERSO_COLOR[3*10*0+rank*3+0]/255.0f;
|
||||
appearance.colorHair.g = PERSO_COLOR[3*10*0+rank*3+1]/255.0f;
|
||||
appearance.colorHair.b = PERSO_COLOR[3*10*0+rank*3+2]/255.0f;
|
||||
}
|
||||
}
|
||||
if ( m_apperanceTab == 1 )
|
||||
if ( m_appearanceTab == 1 )
|
||||
{
|
||||
if ( index == 0 )
|
||||
{
|
||||
apperance.colorCombi.r = PERSO_COLOR[3*10*1+rank*3+0]/255.0f;
|
||||
apperance.colorCombi.g = PERSO_COLOR[3*10*1+rank*3+1]/255.0f;
|
||||
apperance.colorCombi.b = PERSO_COLOR[3*10*1+rank*3+2]/255.0f;
|
||||
appearance.colorCombi.r = PERSO_COLOR[3*10*1+rank*3+0]/255.0f;
|
||||
appearance.colorCombi.g = PERSO_COLOR[3*10*1+rank*3+1]/255.0f;
|
||||
appearance.colorCombi.b = PERSO_COLOR[3*10*1+rank*3+2]/255.0f;
|
||||
}
|
||||
if ( index == 1 )
|
||||
{
|
||||
apperance.colorBand.r = PERSO_COLOR[3*10*2+rank*3+0]/255.0f;
|
||||
apperance.colorBand.g = PERSO_COLOR[3*10*2+rank*3+1]/255.0f;
|
||||
apperance.colorBand.b = PERSO_COLOR[3*10*2+rank*3+2]/255.0f;
|
||||
appearance.colorBand.r = PERSO_COLOR[3*10*2+rank*3+0]/255.0f;
|
||||
appearance.colorBand.g = PERSO_COLOR[3*10*2+rank*3+1]/255.0f;
|
||||
appearance.colorBand.b = PERSO_COLOR[3*10*2+rank*3+2]/255.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Updates the color of the character.
|
||||
|
||||
void CScreenApperance::ColorPerso()
|
||||
void CScreenAppearance::ColorPerso()
|
||||
{
|
||||
CWindow* pw;
|
||||
CSlider* ps;
|
||||
Gfx::Color color;
|
||||
|
||||
PlayerApperance& apperance = m_main->GetPlayerProfile()->GetApperance();
|
||||
PlayerAppearance& appearance = m_main->GetPlayerProfile()->GetAppearance();
|
||||
|
||||
pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW5));
|
||||
if ( pw == nullptr ) return;
|
||||
|
@ -686,7 +686,7 @@ void CScreenApperance::ColorPerso()
|
|||
if ( ps != nullptr ) color.g = ps->GetVisibleValue()/255.0f;
|
||||
ps = static_cast<CSlider*>(pw->SearchControl(EVENT_INTERFACE_PCBa));
|
||||
if ( ps != nullptr ) color.b = ps->GetVisibleValue()/255.0f;
|
||||
if ( m_apperanceTab == 1 ) apperance.colorCombi = color;
|
||||
if ( m_appearanceTab == 1 ) appearance.colorCombi = color;
|
||||
|
||||
ps = static_cast<CSlider*>(pw->SearchControl(EVENT_INTERFACE_PCRb));
|
||||
if ( ps != nullptr ) color.r = ps->GetVisibleValue()/255.0f;
|
||||
|
@ -694,11 +694,11 @@ void CScreenApperance::ColorPerso()
|
|||
if ( ps != nullptr ) color.g = ps->GetVisibleValue()/255.0f;
|
||||
ps = static_cast<CSlider*>(pw->SearchControl(EVENT_INTERFACE_PCBb));
|
||||
if ( ps != nullptr ) color.b = ps->GetVisibleValue()/255.0f;
|
||||
if ( m_apperanceTab == 0 ) apperance.colorHair = color;
|
||||
else apperance.colorBand = color;
|
||||
if ( m_appearanceTab == 0 ) appearance.colorHair = color;
|
||||
else appearance.colorBand = color;
|
||||
}
|
||||
|
||||
void CScreenApperance::SetCamera(float x, float y, float cameraDistance)
|
||||
void CScreenAppearance::SetCamera(float x, float y, float cameraDistance)
|
||||
{
|
||||
Gfx::CCamera* camera = m_main->GetCamera();
|
||||
Gfx::CEngine* engine = Gfx::CEngine::GetInstancePointer();
|
|
@ -24,10 +24,10 @@
|
|||
namespace Ui
|
||||
{
|
||||
|
||||
class CScreenApperance : public CScreen
|
||||
class CScreenAppearance : public CScreen
|
||||
{
|
||||
public:
|
||||
CScreenApperance();
|
||||
CScreenAppearance();
|
||||
void CreateInterface() override;
|
||||
bool EventProcess(const Event &event) override;
|
||||
|
||||
|
@ -44,8 +44,8 @@ protected:
|
|||
void SetCamera(float x, float y, float cameraDistance);
|
||||
|
||||
protected:
|
||||
int m_apperanceTab; // perso: tab selected
|
||||
float m_apperanceAngle; // perso: angle of presentation
|
||||
int m_appearanceTab; // perso: tab selected
|
||||
float m_appearanceAngle; // perso: angle of presentation
|
||||
};
|
||||
|
||||
} // namespace Ui
|
|
@ -183,7 +183,7 @@ bool CScreenPlayerSelect::EventProcess(const Event &event)
|
|||
|
||||
case EVENT_INTERFACE_PERSO:
|
||||
NameSelect();
|
||||
m_main->ChangePhase(PHASE_APPERANCE);
|
||||
m_main->ChangePhase(PHASE_APPEARANCE);
|
||||
break;
|
||||
|
||||
case EVENT_INTERFACE_NDELETE:
|
||||
|
|
Loading…
Reference in New Issue