Avoid to run Easter Egg mode as Grand Prix.
I added new files to avoid a mess. Proposed for 0.8.1 git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@14504 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
parent
6871e604c7
commit
195daa8794
28
data/gui/easter_egg.stkgui
Normal file
28
data/gui/easter_egg.stkgui
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<stkgui>
|
||||||
|
|
||||||
|
<icon-button id="back" x="0" y="0" height="8%" icon="gui/back.png"/>
|
||||||
|
|
||||||
|
<div x="2%" y="1%" width="96%" height="99%" layout="vertical-row" >
|
||||||
|
|
||||||
|
<header width="80%" I18N="Section in easter egg tracks selection screen" text="All Tracks"
|
||||||
|
align="center" text_align="center" />
|
||||||
|
|
||||||
|
<spacer width="20" height="5" />
|
||||||
|
|
||||||
|
<box proportion="1" width="100%" layout="vertical-row" padding="2">
|
||||||
|
<ribbon_grid id="tracks" proportion="1" width="100%" square_items="true"
|
||||||
|
label_location="bottom" align="center" child_width="160" child_height="120" />
|
||||||
|
<spacer width="20" height="13" />
|
||||||
|
</box>
|
||||||
|
|
||||||
|
<tabs width="100%" height="25" id="trackgroups">
|
||||||
|
<button id="standard" I18N="track group" text="Standard"/>
|
||||||
|
<button id="addons" I18N="track group" text="Add-Ons"/>
|
||||||
|
<button id="all" I18N="track group" text="All"/>
|
||||||
|
</tabs>
|
||||||
|
|
||||||
|
<spacer width="20" height="3%" />
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</stkgui>
|
@ -177,6 +177,7 @@ src/states_screens/dialogs/race_paused_dialog.cpp
|
|||||||
src/states_screens/dialogs/select_challenge.cpp
|
src/states_screens/dialogs/select_challenge.cpp
|
||||||
src/states_screens/dialogs/track_info_dialog.cpp
|
src/states_screens/dialogs/track_info_dialog.cpp
|
||||||
src/states_screens/dialogs/tutorial_message_dialog.cpp
|
src/states_screens/dialogs/tutorial_message_dialog.cpp
|
||||||
|
src/states_screens/easter_egg_screen.cpp
|
||||||
src/states_screens/feature_unlocked.cpp
|
src/states_screens/feature_unlocked.cpp
|
||||||
src/states_screens/grand_prix_lose.cpp
|
src/states_screens/grand_prix_lose.cpp
|
||||||
src/states_screens/grand_prix_win.cpp
|
src/states_screens/grand_prix_win.cpp
|
||||||
@ -438,6 +439,7 @@ src/states_screens/dialogs/race_paused_dialog.hpp
|
|||||||
src/states_screens/dialogs/select_challenge.hpp
|
src/states_screens/dialogs/select_challenge.hpp
|
||||||
src/states_screens/dialogs/track_info_dialog.hpp
|
src/states_screens/dialogs/track_info_dialog.hpp
|
||||||
src/states_screens/dialogs/tutorial_message_dialog.hpp
|
src/states_screens/dialogs/tutorial_message_dialog.hpp
|
||||||
|
src/states_screens/easter_egg_screen.hpp
|
||||||
src/states_screens/feature_unlocked.hpp
|
src/states_screens/feature_unlocked.hpp
|
||||||
src/states_screens/grand_prix_lose.hpp
|
src/states_screens/grand_prix_lose.hpp
|
||||||
src/states_screens/grand_prix_win.hpp
|
src/states_screens/grand_prix_win.hpp
|
||||||
|
301
src/states_screens/easter_egg_screen.cpp
Normal file
301
src/states_screens/easter_egg_screen.cpp
Normal file
@ -0,0 +1,301 @@
|
|||||||
|
// SuperTuxKart - a fun racing game with go-kart
|
||||||
|
// Copyright (C) 2009-2013 Marianne Gagnon
|
||||||
|
//
|
||||||
|
// 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, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
|
#include "challenges/unlock_manager.hpp"
|
||||||
|
#include "graphics/irr_driver.hpp"
|
||||||
|
#include "guiengine/widget.hpp"
|
||||||
|
#include "guiengine/widgets/dynamic_ribbon_widget.hpp"
|
||||||
|
#include "guiengine/widgets/icon_button_widget.hpp"
|
||||||
|
#include "io/file_manager.hpp"
|
||||||
|
#include "states_screens/state_manager.hpp"
|
||||||
|
#include "states_screens/easter_egg_screen.hpp"
|
||||||
|
#include "states_screens/dialogs/track_info_dialog.hpp"
|
||||||
|
#include "tracks/track.hpp"
|
||||||
|
#include "tracks/track_manager.hpp"
|
||||||
|
#include "utils/translation.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace GUIEngine;
|
||||||
|
using namespace irr::core;
|
||||||
|
using namespace irr::video;
|
||||||
|
|
||||||
|
static const char ALL_TRACK_GROUPS_ID[] = "all";
|
||||||
|
|
||||||
|
DEFINE_SCREEN_SINGLETON( EasterEggScreen );
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
EasterEggScreen::EasterEggScreen() : Screen("easter_egg.stkgui")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void EasterEggScreen::loadedFromFile()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void EasterEggScreen::eventCallback(Widget* widget, const std::string& name, const int playerID)
|
||||||
|
{
|
||||||
|
// -- track selection screen
|
||||||
|
if (name == "tracks")
|
||||||
|
{
|
||||||
|
DynamicRibbonWidget* w2 = dynamic_cast<DynamicRibbonWidget*>(widget);
|
||||||
|
if (w2 != NULL)
|
||||||
|
{
|
||||||
|
const std::string selection = w2->getSelectionIDString(PLAYER_ID_GAME_MASTER);
|
||||||
|
if(UserConfigParams::logGUI())
|
||||||
|
std::cout << "Clicked on track " << selection.c_str()
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
UserConfigParams::m_last_track = selection;
|
||||||
|
|
||||||
|
if (selection == "random_track")
|
||||||
|
{
|
||||||
|
RibbonWidget* tabs = this->getWidget<RibbonWidget>("trackgroups");
|
||||||
|
assert( tabs != NULL );
|
||||||
|
|
||||||
|
if (m_random_track_list.empty()) return;
|
||||||
|
|
||||||
|
std::string track = m_random_track_list.front();
|
||||||
|
m_random_track_list.pop_front();
|
||||||
|
m_random_track_list.push_back(track);
|
||||||
|
Track* clickedTrack = track_manager->getTrack( track );
|
||||||
|
|
||||||
|
|
||||||
|
if (clickedTrack != NULL)
|
||||||
|
{
|
||||||
|
ITexture* screenshot =
|
||||||
|
irr_driver->getTexture( clickedTrack->getScreenshotFile(),
|
||||||
|
"While loading screenshot for track '%s':",
|
||||||
|
clickedTrack->getFilename() );
|
||||||
|
|
||||||
|
new TrackInfoDialog(selection, clickedTrack->getIdent(),
|
||||||
|
translations->fribidize(clickedTrack->getName()),
|
||||||
|
screenshot, 0.8f, 0.7f);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (selection == "locked")
|
||||||
|
{
|
||||||
|
unlock_manager->playLockSound();
|
||||||
|
}
|
||||||
|
else if (selection == RibbonWidget::NO_ITEM_ID)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Track* clickedTrack = track_manager->getTrack(selection);
|
||||||
|
if (clickedTrack != NULL)
|
||||||
|
{
|
||||||
|
ITexture* screenshot =
|
||||||
|
irr_driver->getTexture( clickedTrack->getScreenshotFile(),
|
||||||
|
"While loading screenshot for track '%s'",
|
||||||
|
clickedTrack->getFilename());
|
||||||
|
|
||||||
|
new TrackInfoDialog(selection, clickedTrack->getIdent(),
|
||||||
|
translations->fribidize(clickedTrack->getName()),
|
||||||
|
screenshot, 0.8f, 0.7f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (name == "trackgroups")
|
||||||
|
{
|
||||||
|
RibbonWidget* tabs = this->getWidget<RibbonWidget>("trackgroups");
|
||||||
|
assert( tabs != NULL );
|
||||||
|
UserConfigParams::m_last_used_track_group = tabs->getSelectionIDString(0);
|
||||||
|
buildTrackList();
|
||||||
|
}
|
||||||
|
else if (name == "back")
|
||||||
|
{
|
||||||
|
StateManager::get()->escapePressed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void EasterEggScreen::beforeAddingWidget()
|
||||||
|
{
|
||||||
|
Screen::init();
|
||||||
|
// Dynamically add tabs
|
||||||
|
RibbonWidget* tabs = this->getWidget<RibbonWidget>("trackgroups");
|
||||||
|
assert( tabs != NULL );
|
||||||
|
|
||||||
|
tabs->clearAllChildren();
|
||||||
|
|
||||||
|
const std::vector<std::string>& groups = track_manager->getAllTrackGroups();
|
||||||
|
const int group_amount = groups.size();
|
||||||
|
|
||||||
|
if (group_amount > 1)
|
||||||
|
{
|
||||||
|
//I18N: name of the tab that will show tracks from all groups
|
||||||
|
tabs->addTextChild( _("All"), ALL_TRACK_GROUPS_ID );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make group names being picked up by gettext
|
||||||
|
#define FOR_GETTEXT_ONLY(x)
|
||||||
|
//I18N: track group name
|
||||||
|
FOR_GETTEXT_ONLY( _("standard") )
|
||||||
|
//I18N: track group name
|
||||||
|
FOR_GETTEXT_ONLY( _("Add-Ons") )
|
||||||
|
|
||||||
|
// add others after
|
||||||
|
for (int n=0; n<group_amount; n++)
|
||||||
|
{
|
||||||
|
// try to translate the group name
|
||||||
|
tabs->addTextChild( _(groups[n].c_str()), groups[n] );
|
||||||
|
}
|
||||||
|
|
||||||
|
int num_of_arenas=0;
|
||||||
|
for (unsigned int n=0; n<track_manager->getNumberOfTracks(); n++) //iterate through tracks to find how many are arenas
|
||||||
|
{
|
||||||
|
Track* temp = track_manager->getTrack(n);
|
||||||
|
if(temp->hasEasterEggs())
|
||||||
|
num_of_arenas++;
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicRibbonWidget* tracks_widget = this->getWidget<DynamicRibbonWidget>("tracks");
|
||||||
|
assert( tracks_widget != NULL );
|
||||||
|
tracks_widget->setItemCountHint(num_of_arenas); //set the item hint to that number to prevent weird formatting
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void EasterEggScreen::init()
|
||||||
|
{
|
||||||
|
DynamicRibbonWidget* tracks_widget = this->getWidget<DynamicRibbonWidget>("tracks");
|
||||||
|
assert( tracks_widget != NULL );
|
||||||
|
|
||||||
|
RibbonWidget* tabs = this->getWidget<RibbonWidget>("trackgroups");
|
||||||
|
assert( tabs != NULL );
|
||||||
|
tabs->select(UserConfigParams::m_last_used_track_group, PLAYER_ID_GAME_MASTER);
|
||||||
|
|
||||||
|
|
||||||
|
buildTrackList();
|
||||||
|
|
||||||
|
// select old track for the game master (if found)
|
||||||
|
irr_driver->setTextureErrorMessage(
|
||||||
|
"While loading screenshot in track screen for last track '%s':",
|
||||||
|
UserConfigParams::m_last_track);
|
||||||
|
if (!tracks_widget->setSelection(UserConfigParams::m_last_track,
|
||||||
|
PLAYER_ID_GAME_MASTER, true))
|
||||||
|
{
|
||||||
|
tracks_widget->setSelection(0, PLAYER_ID_GAME_MASTER, true);
|
||||||
|
}
|
||||||
|
irr_driver->unsetTextureErrorMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void EasterEggScreen::buildTrackList()
|
||||||
|
{
|
||||||
|
DynamicRibbonWidget* tracks_widget = this->getWidget<DynamicRibbonWidget>("tracks");
|
||||||
|
assert( tracks_widget != NULL );
|
||||||
|
|
||||||
|
RibbonWidget* tabs = this->getWidget<RibbonWidget>("trackgroups");
|
||||||
|
assert( tabs != NULL );
|
||||||
|
|
||||||
|
// Reset track list everytime (accounts for locking changes, etc.)
|
||||||
|
tracks_widget->clearItems();
|
||||||
|
m_random_track_list.clear();
|
||||||
|
|
||||||
|
const std::string curr_group_name = tabs->getSelectionIDString(0);
|
||||||
|
|
||||||
|
// Build track list
|
||||||
|
if (curr_group_name == ALL_TRACK_GROUPS_ID)
|
||||||
|
{
|
||||||
|
const int trackAmount = track_manager->getNumberOfTracks();
|
||||||
|
|
||||||
|
for (int n=0; n<trackAmount; n++)
|
||||||
|
{
|
||||||
|
Track* curr = track_manager->getTrack( n );
|
||||||
|
if(race_manager->getMinorMode()==RaceManager::MINOR_MODE_EASTER_EGG
|
||||||
|
&& !curr->hasEasterEggs())
|
||||||
|
continue;
|
||||||
|
if (curr->isArena() || curr->isSoccer()) continue;
|
||||||
|
if (curr->isInternal()) continue;
|
||||||
|
|
||||||
|
if (unlock_manager->getCurrentSlot()->isLocked(curr->getIdent()))
|
||||||
|
{
|
||||||
|
tracks_widget->addItem( _("Locked : solve active challenges to gain access to more!"),
|
||||||
|
"locked", curr->getScreenshotFile(), LOCKED_BADGE,
|
||||||
|
IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tracks_widget->addItem(translations->fribidize(curr->getName()), curr->getIdent(),
|
||||||
|
curr->getScreenshotFile(), 0,
|
||||||
|
IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE );
|
||||||
|
m_random_track_list.push_back(curr->getIdent());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const std::vector<int>& curr_group = track_manager->getTracksInGroup( curr_group_name );
|
||||||
|
const int trackAmount = curr_group.size();
|
||||||
|
|
||||||
|
for (int n=0; n<trackAmount; n++)
|
||||||
|
{
|
||||||
|
Track* curr = track_manager->getTrack( curr_group[n] );
|
||||||
|
if(race_manager->getMinorMode()==RaceManager::MINOR_MODE_EASTER_EGG
|
||||||
|
&& !curr->hasEasterEggs())
|
||||||
|
continue;
|
||||||
|
if (curr->isArena()) continue;
|
||||||
|
if (curr->isSoccer()) continue;
|
||||||
|
if (curr->isInternal()) continue;
|
||||||
|
|
||||||
|
if (unlock_manager->getCurrentSlot()->isLocked(curr->getIdent()))
|
||||||
|
{
|
||||||
|
tracks_widget->addItem( _("Locked : solve active challenges to gain access to more!"),
|
||||||
|
"locked", curr->getScreenshotFile(), LOCKED_BADGE,
|
||||||
|
IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tracks_widget->addItem(translations->fribidize(curr->getName()), curr->getIdent(),
|
||||||
|
curr->getScreenshotFile(), 0 /* no badge */,
|
||||||
|
IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE );
|
||||||
|
m_random_track_list.push_back(curr->getIdent());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tracks_widget->addItem(_("Random Track"), "random_track", "/gui/track_random.png",
|
||||||
|
0 /* no badge */, IconButtonWidget::ICON_PATH_TYPE_RELATIVE);
|
||||||
|
|
||||||
|
tracks_widget->updateItemDisplay();
|
||||||
|
std::random_shuffle( m_random_track_list.begin(), m_random_track_list.end() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void EasterEggScreen::setFocusOnTrack(const std::string& trackName)
|
||||||
|
{
|
||||||
|
DynamicRibbonWidget* tracks_widget = this->getWidget<DynamicRibbonWidget>("tracks");
|
||||||
|
assert( tracks_widget != NULL );
|
||||||
|
|
||||||
|
// only the game master can select tracks, so it's safe to use 'PLAYER_ID_GAME_MASTER'
|
||||||
|
tracks_widget->setSelection(trackName, PLAYER_ID_GAME_MASTER, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
61
src/states_screens/easter_egg_screen.hpp
Normal file
61
src/states_screens/easter_egg_screen.hpp
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// SuperTuxKart - a fun racing game with go-kart
|
||||||
|
// Copyright (C) 2009-2013 Marianne Gagnon
|
||||||
|
//
|
||||||
|
// 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, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
|
#ifndef HEADER_EASTER_EGG_SCREEN_HPP
|
||||||
|
#define HEADER_EASTER_EGG_SCREEN_HPP
|
||||||
|
|
||||||
|
#include "guiengine/screen.hpp"
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
|
namespace GUIEngine { class Widget; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief screen where the user can select a track
|
||||||
|
* \ingroup states_screens
|
||||||
|
*/
|
||||||
|
class EasterEggScreen : public GUIEngine::Screen, public GUIEngine::ScreenSingleton<EasterEggScreen>
|
||||||
|
{
|
||||||
|
friend class GUIEngine::ScreenSingleton<EasterEggScreen>;
|
||||||
|
|
||||||
|
EasterEggScreen();
|
||||||
|
|
||||||
|
/** adds the tracks from the current track group into the tracks ribbon */
|
||||||
|
void buildTrackList();
|
||||||
|
|
||||||
|
std::deque<std::string> m_random_track_list;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** \brief implement callback from parent class GUIEngine::Screen */
|
||||||
|
virtual void loadedFromFile() OVERRIDE;
|
||||||
|
|
||||||
|
/** \brief implement callback from parent class GUIEngine::Screen */
|
||||||
|
virtual void eventCallback(GUIEngine::Widget* widget, const std::string& name,
|
||||||
|
const int playerID) OVERRIDE;
|
||||||
|
|
||||||
|
/** \brief implement callback from parent class GUIEngine::Screen */
|
||||||
|
virtual void init() OVERRIDE;
|
||||||
|
|
||||||
|
/** \brief implement callback from parent class GUIEngine::Screen */
|
||||||
|
virtual void beforeAddingWidget() OVERRIDE;
|
||||||
|
|
||||||
|
|
||||||
|
void setFocusOnTrack(const std::string& trackName);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -23,6 +23,7 @@
|
|||||||
#include "io/file_manager.hpp"
|
#include "io/file_manager.hpp"
|
||||||
#include "race/race_manager.hpp"
|
#include "race/race_manager.hpp"
|
||||||
#include "states_screens/arenas_screen.hpp"
|
#include "states_screens/arenas_screen.hpp"
|
||||||
|
#include "states_screens/easter_egg_screen.hpp"
|
||||||
#include "states_screens/soccer_setup_screen.hpp"
|
#include "states_screens/soccer_setup_screen.hpp"
|
||||||
#include "states_screens/state_manager.hpp"
|
#include "states_screens/state_manager.hpp"
|
||||||
#include "states_screens/tracks_screen.hpp"
|
#include "states_screens/tracks_screen.hpp"
|
||||||
@ -121,7 +122,7 @@ void RaceSetupScreen::eventCallback(Widget* widget, const std::string& name, con
|
|||||||
race_manager->setMinorMode(RaceManager::MINOR_MODE_EASTER_EGG);
|
race_manager->setMinorMode(RaceManager::MINOR_MODE_EASTER_EGG);
|
||||||
UserConfigParams::m_game_mode = CONFIG_CODE_EASTER;
|
UserConfigParams::m_game_mode = CONFIG_CODE_EASTER;
|
||||||
race_manager->setNumKarts( race_manager->getNumLocalPlayers() ); // no AI karts;
|
race_manager->setNumKarts( race_manager->getNumLocalPlayers() ); // no AI karts;
|
||||||
StateManager::get()->pushScreen( TracksScreen::getInstance() );
|
StateManager::get()->pushScreen( EasterEggScreen::getInstance() );
|
||||||
}
|
}
|
||||||
else if (selectedMode == IDENT_SOCCER)
|
else if (selectedMode == IDENT_SOCCER)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user