Commit b5d65500 authored by Gerhard Stein's avatar Gerhard Stein

Cleanups and game state fixes

parent a3bea486
......@@ -116,7 +116,6 @@ public:
std::string mPatchFname;
std::map<GameOption, stOption> mOptions;
int mPlayers = 1;
Difficulty mDifficulty = EASY;
EpisodeInfoStruct* getEpisodeInfoStructRef()
......@@ -126,11 +125,42 @@ public:
{ pEpisodeInfo = const_cast<EpisodeInfoStruct*>(epStruct); }
auto numPlayers() const {
return mPlayers;
}
void setNumPlayers(const int numPlayers){
mPlayers = numPlayers;
}
/*
auto numPlayerVariants() const {
return mPlayers;
}
void setNumPlayerVariants(const int numPlayerVar){
mPlayerVariants = numPlayerVar;
}
*/
std::string mapLevelName;
stCheat mCheatmode;
private:
/**
* @brief mPlayers Number of players
*/
int mPlayers = 1;
/**
* @brief mPlayerVarianst Number of players that totally are possible.
* Means not what is currently being played.
*/
//int mPlayerVariants = 1;
std::vector<CTileProperties> m_TileProperties[2];
CPhysicsSettings m_PhysicsSettings;
......
......@@ -38,7 +38,7 @@ mp_AttachedObject(p_attacher)
void CCamera::cycleCamlead()
{
const int numPlayers = gBehaviorEngine.mPlayers;
const int numPlayers = gBehaviorEngine.numPlayers();
if( numPlayers == 1 ) // For one player this doesn't make sense to change
{
......
......@@ -42,7 +42,8 @@ void CHUD::setup(const int playerIdx,
mRenderRect.x = 8; mRenderRect.y = 4;
if(gBehaviorEngine.mPlayers > 3)
// Start at zero, beacuse we need more room for the HUD Boxes
if(gBehaviorEngine.numPlayers() > 3)
{
mRenderRect.x = 0; mRenderRect.y = 0;
}
......@@ -215,7 +216,7 @@ void CHUD::renderGalaxy()
gGraphics.drawDigits(getRightAlignedString(itoa(charges),2),60, 20, hudBlitsfc );
gGraphics.drawDigits(getRightAlignedString(itoa(lives),2), 20, 20, hudBlitsfc );
if(gBehaviorEngine.mPlayers > 1 && mId == CCamera::getLead())
if(gBehaviorEngine.numPlayers() > 1 && mId == CCamera::getLead())
{
SDL_Rect rect;
rect.x = 7; rect.y = 29;
......@@ -258,7 +259,7 @@ void CHUD::renderVorticon()
// Print the score
Font.drawFont(mHUDBlit, getRightAlignedString(itoa(score),8),8, 2, false );
if(gBehaviorEngine.mPlayers > 1)
if(gBehaviorEngine.numPlayers() > 1)
{
SDL_Rect rect;
rect.x = 2; rect.y = 29;
......
......@@ -26,14 +26,13 @@ struct GMSwitchToPassiveMode : CEvent
struct GMSwitchToPlayGameMode : CEvent
{
const int m_Episode;
const int m_Numplayers;
const std::string m_DataDirectory;
const int m_startlevel;
GMSwitchToPlayGameMode( const int Episode, const int Numplayers,
const std::string& DataDirectory, const int startlevel = -1 ) :
GMSwitchToPlayGameMode( const int Episode,
const std::string& DataDirectory,
const int startlevel = -1 ) :
m_Episode(Episode),
m_Numplayers(Numplayers),
m_DataDirectory(DataDirectory),
m_startlevel(startlevel)
{}
......
......@@ -47,7 +47,8 @@ void CGamePlayMode::ponder(const float deltaT)
}
else if( mp_PlayGame->getStartGame() )
{ // Start another new game
EventContainer.add( new GMSwitchToPlayGameMode(m_Episode, gBehaviorEngine.mPlayers, m_DataDirectory) );
EventContainer.add( new GMSwitchToPlayGameMode(m_Episode,
m_DataDirectory) );
}
else if( mp_PlayGame->getExitEvent() )
{
......
......@@ -50,9 +50,6 @@ void CPlayGame::loadGame()
gLogging.textOut("XML based save state loaded successfully!");
return;
}
// This is for legacy savegame state formats
loadGameState();
}
// Getters
......
......@@ -29,7 +29,6 @@ public:
void loadGame();
virtual bool loadGameState() = 0;
virtual bool loadXMLGameState() = 0;
virtual bool saveXMLGameState() = 0;
virtual void cleanup() = 0;
......
......@@ -18,14 +18,10 @@ void KeenEngine::switchToGamePlayMode(const int startLevel)
{
const int episode = gBehaviorEngine.getEpisode();
auto &numPlayers = gBehaviorEngine.mPlayers;
// If you get here, you always have at least one player
if(numPlayers <= 0)
numPlayers = 1;
std::string DataDirectory = gKeenFiles.gameDir;
gEventManager.add( new GMSwitchToPlayGameMode( episode, numPlayers, DataDirectory, startLevel ) );
gEventManager.add( new GMSwitchToPlayGameMode( episode,
DataDirectory,
startLevel ) );
}
......
......@@ -44,13 +44,13 @@ CPlayGame(startlevel),
m_WorldMap( mInventoryVec),
m_LevelPlay( mInventoryVec)
{
const int numPlayers = gBehaviorEngine.mPlayers;
mDead.assign(numPlayers, false);
mGameOver.assign(numPlayers, false);
const int numPlayer = gBehaviorEngine.numPlayers();
mDead.assign(numPlayer, false);
mGameOver.assign(numPlayer, false);
mInventoryVec.resize(numPlayers);
mInventoryVec.resize(numPlayer);
for(int i=0 ; i<numPlayers ; i++)
for(int i=0 ; i<numPlayer ; i++)
{
mInventoryVec[i].setup(i, spriteVars[i]);
}
......@@ -70,46 +70,6 @@ m_LevelPlay( mInventoryVec)
gEffectController.setupEffect(pColorMergeFX);
}
// NOTE: Only for compatibility mode. Since CG 1.5 it is only used for
// supporting older versions of Savegame states of CG
bool CPlayGameGalaxy::loadGameState()
{
CSaveGameController &savedGame = gSaveGameController;
// This fills the datablock from CSavedGame object
if(!savedGame.load())
return false;
// Create the special merge effect (Fadeout)
CColorMerge *pColorMergeFX = new CColorMerge(8);
/// Save the Game in the CSavedGame object
// store the episode, level and difficulty
savedGame.decodeData(m_Episode);
savedGame.decodeData(gBehaviorEngine.mDifficulty);
// Load number of Players
savedGame.decodeData(gBehaviorEngine.mPlayers);
// We need to load both Levels first, before we do the writing from the saved state.
mInventoryVec[0] << savedGame;
bool active;
savedGame.decodeData( active );
m_WorldMap.setActive(active);
m_WorldMap << savedGame;
savedGame.decodeData( active );
m_LevelPlay.setActive(active);
if(active)
m_LevelPlay<<savedGame;
// Create the special merge effect (Fadeout)
gEffectController.setupEffect(pColorMergeFX);
return true;
}
......@@ -134,7 +94,7 @@ bool CPlayGameGalaxy::loadXMLGameState()
// Get number of Players
const unsigned int numPlayers = stateNode.get<int>("NumPlayer");
gBehaviorEngine.mPlayers = numPlayers;
gBehaviorEngine.setNumPlayers(numPlayers);
if(!mInventoryVec.empty())
mInventoryVec.clear();
......@@ -162,8 +122,8 @@ bool CPlayGameGalaxy::loadXMLGameState()
variant = playerNode.get<int>("<xmlattr>.variant");
const int idx = playerNode.get("<xmlattr>.id", 0);
auto &invNode = playerNode.get_child("inventory");
mInventoryVec[variant].setup(idx, variant);
mInventoryVec[variant] << invNode;
mInventoryVec[idx].setup(idx, variant);
mInventoryVec[idx] << invNode;
}
}
......@@ -205,7 +165,7 @@ bool CPlayGameGalaxy::saveXMLGameState()
stateNode.put("difficulty", gBehaviorEngine.mDifficulty);
// Save number of Players
const size_t numPlayers = size_t(gBehaviorEngine.mPlayers);
const size_t numPlayers = size_t(gBehaviorEngine.numPlayers());
stateNode.put("NumPlayer", numPlayers);
ptree &deadNode = pt.add("death", "");
......@@ -268,7 +228,7 @@ bool CPlayGameGalaxy::init()
m_LevelPlay.setActive(true);
}
const int numPlayers = gBehaviorEngine.mPlayers;
const int numPlayers = gBehaviorEngine.numPlayers();
mDead.assign(numPlayers, false);
mGameOver.assign(numPlayers, false);
......@@ -417,7 +377,7 @@ void CPlayGameGalaxy::pumpEvent(const CEvent *evPtr)
if(ev->data >= 0xC000) // Start a new level!
{
// Ensure no one is dead anymore
const int numPlayers = gBehaviorEngine.mPlayers;
const int numPlayers = gBehaviorEngine.numPlayers();
mDead.assign(numPlayers, false);
mGameOver.assign(numPlayers, false);
......@@ -442,7 +402,7 @@ void CPlayGameGalaxy::pumpEvent(const CEvent *evPtr)
else if( const EventExitLevel *ev = dynamic_cast<const EventExitLevel*>(evPtr) )
{
// Ensure no one is dead anymore
const int numPlayers = gBehaviorEngine.mPlayers;
const int numPlayers = gBehaviorEngine.numPlayers();
mDead.assign(numPlayers, false);
mGameOver.assign(numPlayers, false);
......
......@@ -31,7 +31,6 @@ public:
CPlayGameGalaxy(const int startlevel,
const std::vector<int> &spriteVars);
bool loadGameState();
bool loadXMLGameState();
bool saveXMLGameState();
bool init();
......
......@@ -387,13 +387,14 @@ void GalaxyEngine::pumpEvent(const CEvent *evPtr)
else if( const NewGamePlayersEvent* pNewGame =
dynamic_cast<const NewGamePlayersEvent*>(evPtr) )
{
gBehaviorEngine.mPlayers = pNewGame->mSelection;
const auto numPlayerVars = pNewGame->mSelection;
gBehaviorEngine.setNumPlayers(numPlayerVars);
// Ensure the Sprite variations are correctly setup
if(gBehaviorEngine.mPlayers > 1)
if(numPlayerVars > 1)
{
mSpriteVars.clear();
for(int i=0 ; i<gBehaviorEngine.mPlayers ; i++ )
for(int i=0 ; i<numPlayerVars ; i++ )
{
mSpriteVars.push_back(i);
}
......@@ -451,7 +452,7 @@ void GalaxyEngine::pumpEvent(const CEvent *evPtr)
{
// Ensure the Sprite variations are correctly setup
mSpriteVars.clear();
for(int i=0 ; i<gBehaviorEngine.mPlayers ; i++ )
for(int i=0 ; i<gBehaviorEngine.numPlayers() ; i++ )
{
mSpriteVars.push_back(i);
}
......
......@@ -393,7 +393,7 @@ void CMapLoaderGalaxy::spawnFoes(CMap &Map)
if(!m_ObjectPtr.empty())
m_ObjectPtr.clear();
const int numPlayers = gBehaviorEngine.mPlayers;
const int numPlayers = gBehaviorEngine.numPlayers();
// he we go to the adding objects
Map.mNumFuses = 0;
......
......@@ -261,7 +261,7 @@ void CPlayerBase::processInput()
{
// If player has the camlead, he can also reassign the input
// by pressing Shift+Number
if(mPlayerNum == m_camera.getLead() && gBehaviorEngine.mPlayers > 1)
if(mPlayerNum == m_camera.getLead() && gBehaviorEngine.numPlayers() > 1)
{
if(gInput.getHoldedKey(KSHIFT))
{
......
......@@ -226,7 +226,7 @@ void VorticonEngine::pumpEvent(const CEvent *evPtr)
}
else if( const NewGamePlayersEvent* pNewGame = dynamic_cast<const NewGamePlayersEvent*>(evPtr) )
{
gBehaviorEngine.mPlayers = pNewGame->mSelection;
gBehaviorEngine.setNumPlayers(pNewGame->mSelection);
gEventManager.add( new OpenMenuEvent(new CDifficultySelection(GsControl::Style::VORTICON)) );
return;
}
......
......@@ -41,8 +41,9 @@ mp_levels_completed(mpLevelCompleted)
m_playingmode = WORLDMAP;
// Set every value in the class to zero.
memset(&inventory, 0, sizeof(stInventory));
// Reset inventory
inventory = stInventory();
setDefaultStartValues();
setDatatoZero();
}
......
......@@ -15,180 +15,6 @@
///////////////////////////
// Game State Management //
///////////////////////////
bool CPlayGameVorticon::loadGameState()
{
gMusicPlayer.stop();
if(loadXMLGameState())
{
return true;
}
CSaveGameController &savedGame = gSaveGameController;
bool ok = true;
// This fills the datablock from CSavedGame object
if(!savedGame.load())
{
return false;
}
// Create the special merge effect (Fadeout)
CColorMerge *pColorMergeFX = new CColorMerge(8);
// Prepare for loading the new level map and the players.
cleanup();
// get the episode, level and difficulty
char newLevel;
ok &= savedGame.decodeData(m_Episode);
ok &= savedGame.decodeData(newLevel);
bool loadmusic = ( m_Level != newLevel || m_Level == 80 );
m_Level = newLevel;
ok &= savedGame.decodeData(gBehaviorEngine.mDifficulty);
bool dark, checkpointset;
int checkx, checky;
ok &= savedGame.decodeData(checkpointset);
ok &= savedGame.decodeData(checkx);
ok &= savedGame.decodeData(checky);
ok &= savedGame.decodeData(dark);
// Load number of Players
unsigned int numPlayers;
ok &= savedGame.decodeData(numPlayers);
gBehaviorEngine.mPlayers = numPlayers;
if(!m_Player.empty())
m_Player.clear();
// Start getting data of the loaded players
for( size_t i=0 ; i < numPlayers ; i++ )
{
m_Player.push_back( CPlayer(mpLevelCompleted, *mMap.get(), i) );
m_Player.at(i).m_index = i;
m_Player.at(i).setDatatoZero();
}
CVorticonMapLoaderWithPlayer Maploader(mMap, m_Player, mSpriteObjectContainer);
m_checkpointset = checkpointset;
Maploader.m_checkpointset = m_checkpointset;
if(!Maploader.load(m_Episode, m_Level, m_Gamepath, loadmusic, false))
return false;
m_checkpoint_x = checkx;
m_checkpoint_y = checky;
m_level_command = START_LEVEL;
for(auto &player : m_Player)
{
int x, y;
player.setupforLevelPlay();
ok &= savedGame.decodeData(x);
ok &= savedGame.decodeData(y);
player.moveToForce(Vector2D<int>(x,y));
ok &= savedGame.decodeData(player.blockedd);
ok &= savedGame.decodeData(player.blockedu);
ok &= savedGame.decodeData(player.blockedl);
ok &= savedGame.decodeData(player.blockedr);
ok &= savedGame.decodeData(player.inventory);
player.pdie = 0;
}
// load the number of objects on screen
Uint32 size;
ok &= savedGame.decodeData(size);
for( Uint32 i=0 ; i<size ; i++ )
{
unsigned int x,y;
if(i >= mSpriteObjectContainer.size())
{
std::unique_ptr<CVorticonSpriteObject> object( new CVorticonSpriteObject( mMap.get(), 0, 0, OBJ_NONE, 0) );
object->exists = false;
mSpriteObjectContainer.push_back(move(object));
}
CVorticonSpriteObject &object = *(mSpriteObjectContainer.at(i));
ok &= savedGame.decodeData(object.m_type);
ok &= savedGame.decodeData(x);
ok &= savedGame.decodeData(y);
object.moveToForce(Vector2D<int>(x,y));
ok &= savedGame.decodeData(object.mIsDead);
ok &= savedGame.decodeData(object.onscreen);
ok &= savedGame.decodeData(object.hasbeenonscreen);
ok &= savedGame.decodeData(object.exists);
ok &= savedGame.decodeData(object.blockedd);
ok &= savedGame.decodeData(object.blockedu);
ok &= savedGame.decodeData(object.blockedl);
ok &= savedGame.decodeData(object.blockedr);
ok &= savedGame.decodeData(object.mHealthPoints);
ok &= savedGame.decodeData(object.canbezapped);
ok &= savedGame.decodeData(object.cansupportplayer);
ok &= savedGame.decodeData(object.inhibitfall);
ok &= savedGame.decodeData(object.honorPriority);
ok &= savedGame.decodeData(object.mSpriteIdx);
object.performCollisions();
if(object.m_type == OBJ_DOOR or
object.m_type == OBJ_RAY or
object.m_type == OBJ_SNDWAVE or
object.m_type == OBJ_FIREBALL or
object.m_type == OBJ_ICECHUNK or
object.m_type == OBJ_ICEBIT or
object.m_type == OBJ_GOTPOINTS or
object.m_type == OBJ_ANKHSHIELD) // Some objects are really not needed. So don't load them
object.exists = false;
}
// TODO: An algorithm for comparing the number of players saved and we actually have need to be in sync
// Load the map_data as it was left last
ok &= savedGame.decodeData(mMap->m_width);
ok &= savedGame.decodeData(mMap->m_height);
ok &= savedGame.readDataBlock( reinterpret_cast<byte*>(mMap->getForegroundData()) );
// Load completed levels
ok &= savedGame.readDataBlock( (byte*)(mpLevelCompleted) );
m_Player[0].setMapData(mMap.get());
m_Player[0].setupCameraObject();
m_Player[0].mpCamera->attachObject(&m_Player[0]);
while(m_Player[0].mpCamera->mMoving)
{
m_Player[0].mpCamera->process();
m_Player[0].mpCamera->processEvents();
}
mMap->drawAll();
// Create the special merge effect (Fadeout)
gEffectController.setupEffect(pColorMergeFX);
mpObjectAI.reset( new CVorticonSpriteObjectAI(mMap.get(), mSpriteObjectContainer, m_Player,
numPlayers, m_Episode, m_Level,
mMap->m_Dark) );
setupPlayers();
mMap->m_Dark = dark;
gGraphics.Palette.setdark(mMap->m_Dark);
m_Player[0].mpCamera->reAdjust();
return ok;
}
bool CPlayGameVorticon::loadXMLGameState()
{
......@@ -371,20 +197,19 @@ bool CPlayGameVorticon::loadXMLGameState()
// Create the special merge effect (Fadeout)
gEffectController.setupEffect(pColorMergeFX);
gBehaviorEngine.setNumPlayers(m_Player.size());
mpObjectAI.reset( new CVorticonSpriteObjectAI(mMap.get(), mSpriteObjectContainer, m_Player,
gBehaviorEngine.mPlayers, m_Episode, m_Level,
gBehaviorEngine.numPlayers(), m_Episode, m_Level,
mMap->m_Dark) );
setupPlayers();
mMap->m_Dark = stateNode.get<bool>("dark", false);
gGraphics.Palette.setdark(mMap->m_Dark);
m_Player[0].mpCamera->reAdjust();
gBehaviorEngine.mPlayers = m_Player.size();
return true;
}
......@@ -414,7 +239,7 @@ bool CPlayGameVorticon::saveXMLGameState()
stateNode.put("dark", mMap->m_Dark);
const unsigned int numPlayers = gBehaviorEngine.mPlayers;
const unsigned int numPlayers = gBehaviorEngine.numPlayers();
// Now save the inventory of every player
for( size_t i=0 ; i<numPlayers ; i++ )
......@@ -506,7 +331,7 @@ bool CPlayGameVorticon::saveGameState()
savedGame.encodeData(mMap->m_Dark);
// Save number of Players
const unsigned int numPlayers = gBehaviorEngine.mPlayers;
const unsigned int numPlayers = gBehaviorEngine.numPlayers();
savedGame.encodeData(numPlayers);
// Now save the inventory of every player
......
......@@ -34,13 +34,14 @@ void CPlayGameVorticon::processInLevel()
if(m_gameover)
return;
const int numPlayers = gBehaviorEngine.mPlayers;
const int numPlayers = gBehaviorEngine.numPlayers();
// Perform player Objects...
for( int i=0 ; i<numPlayers ; i++ )
{
// check if someone has lives
if(m_Player[i].inventory.lives==0 && m_Player[i].pdie==PDIE_DEAD)
if(m_Player[i].inventory.lives==0 &&
m_Player[i].pdie==PDIE_DEAD)
continue;
// Process the other stuff like, items, jump, etc.
......
......@@ -58,7 +58,7 @@ CPlayGame(startlevel)
m_Player.clear();
}
const int numPlayers = gBehaviorEngine.mPlayers;
const int numPlayers = gBehaviorEngine.numPlayers();
m_Player.assign( numPlayers, CPlayer(mpLevelCompleted, *mMap.get(), 0) );
......@@ -101,7 +101,7 @@ void CPlayGameVorticon::setupPlayers()
if(!mpHUDVec.empty())
mpHUDVec.clear();
const int numPlayers = gBehaviorEngine.mPlayers;
const int numPlayers = gBehaviorEngine.numPlayers();
for (int i=0 ; i<numPlayers ; i++)
{
......@@ -111,7 +111,6 @@ void CPlayGameVorticon::setupPlayers()
{
player.m_playingmode = CPlayer::WORLDMAP;
m_showKeensLeft |= ( player.pdie == PDIE_DEAD );
//if(player.godmode) player.solid = false;
}
else
{
......@@ -159,7 +158,7 @@ bool CPlayGameVorticon::init()
CVorticonMapLoaderWithPlayer MapLoader( mMap, m_Player, mSpriteObjectContainer );
MapLoader.m_checkpointset = m_checkpointset;
const int numPlayers = gBehaviorEngine.mPlayers;
const int numPlayers = gBehaviorEngine.numPlayers();
// load level map
if( !MapLoader.load( m_Episode, m_Level, m_Gamepath ) )
......@@ -230,7 +229,7 @@ bool CPlayGameVorticon::init()
bool CPlayGameVorticon::StatusScreenOpen()
{
const int numPlayers = gBehaviorEngine.mPlayers;
const int numPlayers = gBehaviorEngine.numPlayers();
for( unsigned short i=0 ; i<numPlayers ; i++ )
{
if(m_Player[i].m_showStatusScreen)
......@@ -320,7 +319,7 @@ void CPlayGameVorticon::ponder(const float deltaT)
if(m_Player[mCamLead].pdie)
{
const int numPlayers = gBehaviorEngine.mPlayers;
const int numPlayers = gBehaviorEngine.numPlayers();
for( int i=0 ; i<numPlayers ; i++ )
{
if(m_Player[i].pdie)
......@@ -467,7 +466,7 @@ void CPlayGameVorticon::cycleCamLead()
{
mCamLead++;
const int numPlayers = gBehaviorEngine.mPlayers;
const int numPlayers = gBehaviorEngine.numPlayers();
if( mCamLead >= numPlayers )
mCamLead = 0;
}
......@@ -483,7 +482,7 @@ void CPlayGameVorticon::handleFKeys()
{
gBehaviorEngine.mCheatmode.items = false;
gInput.flushAll();
const size_t numPlayers = size_t(gBehaviorEngine.mPlayers);
const size_t numPlayers = size_t(gBehaviorEngine.numPlayers());
for(size_t i=0;i<numPlayers;i++)
{
m_Player[i].pfiring = false;
......@@ -584,7 +583,7 @@ void CPlayGameVorticon::handleFKeys()
void CPlayGameVorticon::verifyMultiplayerConsistency()
{
const size_t numPlayers = size_t(gBehaviorEngine.mPlayers);
const size_t numPlayers = size_t(gBehaviorEngine.numPlayers());
ShareWithOthers(HasPogo);
ShareWithOthers(HasJoystick);
......@@ -606,7 +605,7 @@ void CPlayGameVorticon::verifyFinales()
hasBattery = hasWiskey = hasJoystick = hasVaccum = false;
// Check if one of the Players has the items
const unsigned int numPlayers = gBehaviorEngine.mPlayers;
const unsigned int numPlayers = gBehaviorEngine.numPlayers();
for( size_t i=0 ;i < numPlayers ; i++)
{
hasBattery |= m_Player[i].inventory.HasBattery;
......@@ -754,7 +753,7 @@ void CPlayGameVorticon::drawAllElements()
// Draw masked tiles here!
mMap->_drawForegroundTiles();
const size_t numPlayers = size_t(gBehaviorEngine.mPlayers);
const size_t numPlayers = size_t(gBehaviorEngine.numPlayers());
for( size_t i=0 ; i<numPlayers ; i++ )
{
m_Player[i].drawStatusScreen();
......
......@@ -52,7 +52,6 @@ public:
bool init() override;
// Game states
bool loadGameState() override;
bool saveGameState();
bool loadXMLGameState() override;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment