This commit is contained in:
parent
f3062464d2
commit
8ca70fa11e
@ -21,8 +21,8 @@ MarioBlock::MarioBlock( int x, int y,
|
||||
const std::shared_ptr<SDLPP::Renderer> &renderer,
|
||||
std::shared_ptr<SDLPP::Texture> texture, SDL_Rect src,
|
||||
bool can_be_destroyed, bool destructible)
|
||||
: RectangleRender( x * BLOCK_SIZE, 1 - ( 16 - y ) * BLOCK_SIZE,
|
||||
BLOCK_SIZE, BLOCK_SIZE, renderer, texture, src ) {
|
||||
: RectangleRender(x * BLOCK_SIZE, 1 - (16 - y) * BLOCK_SIZE, BLOCK_SIZE,
|
||||
BLOCK_SIZE, renderer, texture, src) {
|
||||
_can_be_destroyed = can_be_destroyed;
|
||||
_destructible = can_be_destroyed && destructible;
|
||||
setMovementSpeed(1);
|
||||
@ -53,7 +53,8 @@ void MarioBlock::visit( SDLPP::Visitor &visitor ) {
|
||||
|
||||
setPos(getPos() - SDLPP::Vec2D<double>(0, BLOCK_SIZE));
|
||||
if (getCollisions().size() < 2)
|
||||
addCollision( SDLPP::RectColider( 0.1, 0.1, 0.8, 0.8, BOUNCE_COLLISION ) );
|
||||
addCollision(
|
||||
SDLPP::RectColider(0.1, 0.1, 0.8, 0.8, BOUNCE_COLLISION));
|
||||
updateSizeAndPosition();
|
||||
g_playground->visitCollisions(*this, bv);
|
||||
setPos(getPos() + SDLPP::Vec2D<double>(0, BLOCK_SIZE));
|
||||
@ -63,7 +64,8 @@ void MarioBlock::visit( SDLPP::Visitor &visitor ) {
|
||||
}
|
||||
if (hasCoin()) {
|
||||
removeCoin();
|
||||
auto coin = createTerrainBlock(COIN_ID, LandType::OVERWORLD, renderer);
|
||||
auto coin =
|
||||
createTerrainBlock(COIN_ID, LandType::OVERWORLD, renderer);
|
||||
coin->setPos(getPos());
|
||||
std::dynamic_pointer_cast<CoinBlock>(coin)->setParent(this);
|
||||
dynamic_cast<MarioVisitor &>(visitor).setCoin();
|
||||
@ -71,7 +73,8 @@ void MarioBlock::visit( SDLPP::Visitor &visitor ) {
|
||||
}
|
||||
if (hasMushroom()) {
|
||||
removeMushroom();
|
||||
auto mushroom = createTerrainBlock(MUSHROOM_ID, LandType::OVERWORLD, renderer);
|
||||
auto mushroom =
|
||||
createTerrainBlock(MUSHROOM_ID, LandType::OVERWORLD, renderer);
|
||||
mushroom->setPos(getPos());
|
||||
std::dynamic_pointer_cast<MushroomBlock>(mushroom)->setParent(this);
|
||||
dynamic_cast<MarioVisitor &>(visitor).setMushroomBlock(mushroom);
|
||||
@ -158,14 +161,12 @@ void MarioBlock::custom_move( int ticks ) {
|
||||
}
|
||||
}
|
||||
if (_traveling) {
|
||||
bool overshot_x = (getMovement().getX() < 0 &&
|
||||
getPos().getX() <= _target.getX()) ||
|
||||
(getMovement().getX() > 0 &&
|
||||
getPos().getX() >= _target.getX());
|
||||
bool overshot_y = (getMovement().getY() < 0 &&
|
||||
getPos().getY() <= _target.getY()) ||
|
||||
(getMovement().getY() > 0 &&
|
||||
getPos().getY() >= _target.getY());
|
||||
bool overshot_x =
|
||||
(getMovement().getX() < 0 && getPos().getX() <= _target.getX()) ||
|
||||
(getMovement().getX() > 0 && getPos().getX() >= _target.getX());
|
||||
bool overshot_y =
|
||||
(getMovement().getY() < 0 && getPos().getY() <= _target.getY()) ||
|
||||
(getMovement().getY() > 0 && getPos().getY() >= _target.getY());
|
||||
if (overshot_x) {
|
||||
setPos(_target.getX(), getPos().getY());
|
||||
setMovement(0, getMovement().getY());
|
||||
@ -469,18 +470,15 @@ createBlockById( uint64_t id, int x, int y,
|
||||
break;
|
||||
case SIDEWAY_PIPE_MIDDLE_BOTTOM_ID:
|
||||
result = std::static_pointer_cast<MarioBlock>(
|
||||
std::make_shared< SidewayPipeMiddleBottomBlock >( x, y,
|
||||
renderer ) );
|
||||
std::make_shared<SidewayPipeMiddleBottomBlock>(x, y, renderer));
|
||||
break;
|
||||
case SIDEWAY_PIPE_CONNECTOR_TOP_ID:
|
||||
result = std::static_pointer_cast<MarioBlock>(
|
||||
std::make_shared< SidewayPipeConnectorTopBlock >( x, y,
|
||||
renderer ) );
|
||||
std::make_shared<SidewayPipeConnectorTopBlock>(x, y, renderer));
|
||||
break;
|
||||
case SIDEWAY_PIPE_CONNECTOR_BOTTOM_ID:
|
||||
result = std::static_pointer_cast<MarioBlock>(
|
||||
std::make_shared< SidewayPipeConnectorBottomBlock >( x, y,
|
||||
renderer ) );
|
||||
std::make_shared<SidewayPipeConnectorBottomBlock>(x, y, renderer));
|
||||
break;
|
||||
case TREE_PLATFORM_TOP_LEFT_ID:
|
||||
result = std::static_pointer_cast<MarioBlock>(
|
||||
@ -508,28 +506,23 @@ createBlockById( uint64_t id, int x, int y,
|
||||
break;
|
||||
case MUSHROOM_PLATFORM_TOP_LEFT_ID:
|
||||
result = std::static_pointer_cast<MarioBlock>(
|
||||
std::make_shared< MushroomPlatformTopLeftBlock >( x, y,
|
||||
renderer ) );
|
||||
std::make_shared<MushroomPlatformTopLeftBlock>(x, y, renderer));
|
||||
break;
|
||||
case MUSHROOM_PLATFORM_TOP_MIDDLE_ID:
|
||||
result = std::static_pointer_cast<MarioBlock>(
|
||||
std::make_shared< MushroomPlatformTopMiddleBlock >( x, y,
|
||||
renderer ) );
|
||||
std::make_shared<MushroomPlatformTopMiddleBlock>(x, y, renderer));
|
||||
break;
|
||||
case MUSHROOM_PLATFORM_TOP_RIGHT_ID:
|
||||
result = std::static_pointer_cast<MarioBlock>(
|
||||
std::make_shared< MushroomPlatformTopRightBlock >( x, y,
|
||||
renderer ) );
|
||||
std::make_shared<MushroomPlatformTopRightBlock>(x, y, renderer));
|
||||
break;
|
||||
case MUSHROOM_PLATFORM_BARK_TOP_ID:
|
||||
result = std::static_pointer_cast<MarioBlock>(
|
||||
std::make_shared< MushroomPlatformBarkTopBlock >( x, y,
|
||||
renderer ) );
|
||||
std::make_shared<MushroomPlatformBarkTopBlock>(x, y, renderer));
|
||||
break;
|
||||
case MUSHROOM_PLATFORM_BARK_BOTTOM_ID:
|
||||
result = std::static_pointer_cast<MarioBlock>(
|
||||
std::make_shared< MushroomPlatformBarkBottomBlock >( x, y,
|
||||
renderer ) );
|
||||
std::make_shared<MushroomPlatformBarkBottomBlock>(x, y, renderer));
|
||||
break;
|
||||
case TREE_BARK_ID:
|
||||
result = std::static_pointer_cast<MarioBlock>(
|
||||
@ -662,12 +655,14 @@ void MarioBlock::setBaseRect(SDL_Rect rect) {
|
||||
_base_src = rect;
|
||||
setType(getType());
|
||||
}
|
||||
|
||||
void MarioBlock::checkVisibility(double rightmost_x) {
|
||||
// we assume that object's X > 0 as otherwise it would be destroyed
|
||||
if (!getHidden() && getAbsolutePos().getX() < rightmost_x) {
|
||||
_was_visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool MarioBlock::wasVisible() const {
|
||||
return _was_visible;
|
||||
}
|
||||
|
@ -11,8 +11,7 @@ struct LandType {
|
||||
|
||||
class MarioBlock : public SDLPP::RectangleRender {
|
||||
public:
|
||||
MarioBlock( int x, int y,
|
||||
const std::shared_ptr< SDLPP::Renderer > &renderer,
|
||||
MarioBlock(int x, int y, const std::shared_ptr<SDLPP::Renderer> &renderer,
|
||||
std::shared_ptr<SDLPP::Texture> texture, SDL_Rect src,
|
||||
bool can_be_destroyed = false, bool destructible = false);
|
||||
void visit(SDLPP::Visitor &visitor) override;
|
||||
|
@ -3,7 +3,11 @@
|
||||
#include "blocks.hpp"
|
||||
#include "sprites.hpp"
|
||||
|
||||
EditBox::EditBox(int x, int y, float start_x, float start_y, int map_width, int map_height, std::shared_ptr<SDLPP::Renderer> renderer) : SDLPP::RectangleRender(start_x + x*BLOCK_SIZE, start_y + y*BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, renderer) {
|
||||
EditBox::EditBox(int x, int y, float start_x, float start_y, int map_width,
|
||||
int map_height, std::shared_ptr<SDLPP::Renderer> renderer)
|
||||
: SDLPP::RectangleRender(start_x + x * BLOCK_SIZE,
|
||||
start_y + y * BLOCK_SIZE, BLOCK_SIZE,
|
||||
BLOCK_SIZE, renderer) {
|
||||
_x = x;
|
||||
_y = y;
|
||||
setId(EDITOR_EDIT_SQUARE);
|
||||
|
@ -5,9 +5,11 @@
|
||||
|
||||
class EditBox : public SDLPP::RectangleRender {
|
||||
public:
|
||||
EditBox(int x, int y, float start_x, float start_y, int map_width, int map_height, std::shared_ptr<SDLPP::Renderer> renderer);
|
||||
EditBox(int x, int y, float start_x, float start_y, int map_width,
|
||||
int map_height, std::shared_ptr<SDLPP::Renderer> renderer);
|
||||
virtual SDLPP::Vec2D<int> getIndexes() const;
|
||||
virtual void visit(SDLPP::Visitor &visitor) override;
|
||||
|
||||
private:
|
||||
int _x;
|
||||
int _y;
|
||||
|
106
mario/editor.cpp
106
mario/editor.cpp
@ -123,19 +123,23 @@ void updateTool() {
|
||||
switch (tool_role) {
|
||||
case BlockRole::TERRAIN:
|
||||
target_texture = global_vars.translucent_terrain_texture;
|
||||
target_src = global_vars.tools[global_vars.tool.index]->getTextureSourceRect();
|
||||
target_src =
|
||||
global_vars.tools[global_vars.tool.index]->getTextureSourceRect();
|
||||
break;
|
||||
case BlockRole::MARIO:
|
||||
target_texture = global_vars.translucent_mario_texture;
|
||||
target_src = global_vars.characters[global_vars.tool.index]->getTextureSourceRect();
|
||||
target_src = global_vars.characters[global_vars.tool.index]
|
||||
->getTextureSourceRect();
|
||||
break;
|
||||
case BlockRole::MODIFIER:
|
||||
target_texture = global_vars.translucent_mod_texture;
|
||||
target_src = global_vars.mods[global_vars.tool.index]->getTextureSourceRect();
|
||||
target_src =
|
||||
global_vars.mods[global_vars.tool.index]->getTextureSourceRect();
|
||||
break;
|
||||
case BlockRole::CHARACTER:
|
||||
target_texture = global_vars.translucent_enemies_texture;
|
||||
target_src = global_vars.characters[global_vars.tool.index]->getTextureSourceRect();
|
||||
target_src = global_vars.characters[global_vars.tool.index]
|
||||
->getTextureSourceRect();
|
||||
break;
|
||||
}
|
||||
global_vars.current_tool->setHidden(true);
|
||||
@ -375,8 +379,7 @@ void selectPrevTool() {
|
||||
if (global_vars.tool.index % multiplier == 0) {
|
||||
subtraction = multiplier + 1;
|
||||
}
|
||||
if ( global_vars.tool.index == 0 ||
|
||||
global_vars.tool.index - subtraction >
|
||||
if (global_vars.tool.index == 0 || global_vars.tool.index - subtraction >
|
||||
static_cast<uint64_t>(-multiplier)) {
|
||||
return;
|
||||
}
|
||||
@ -533,14 +536,12 @@ void mouseUpAction( uint64_t flags, SDLPP::Scene &scene ) {
|
||||
if (MouseVisitor::moveModsLeft(flags) &&
|
||||
global_vars.tool.cur_page_mods != 0) {
|
||||
global_vars.tool.cur_page_mods--;
|
||||
updateToolSelection( global_vars.tool.cur_page_mods + 1,
|
||||
ToolType::MOD );
|
||||
updateToolSelection(global_vars.tool.cur_page_mods + 1, ToolType::MOD);
|
||||
}
|
||||
if (MouseVisitor::moveModsRight(flags) &&
|
||||
global_vars.tool.cur_page_mods != global_vars.tool.max_page_mods) {
|
||||
global_vars.tool.cur_page_mods++;
|
||||
updateToolSelection( global_vars.tool.cur_page_mods - 1,
|
||||
ToolType::MOD );
|
||||
updateToolSelection(global_vars.tool.cur_page_mods - 1, ToolType::MOD);
|
||||
}
|
||||
if (MouseVisitor::moveCharactersLeft(flags) &&
|
||||
global_vars.tool.cur_page_characters != 0) {
|
||||
@ -621,8 +622,7 @@ void placeTool( SDLPP::Scene &scene ) {
|
||||
case VisitorType::Character:
|
||||
if (tool_type == BlockRole::MARIO) {
|
||||
obj.setCharacter(MARIO_ID, global_vars.current_world_type);
|
||||
new_obj =
|
||||
createMario( global_vars.current_world_type, renderer,
|
||||
new_obj = createMario(global_vars.current_world_type, renderer,
|
||||
global_vars.mouse.edit_box.getX(),
|
||||
global_vars.mouse.edit_box.getY(), true);
|
||||
// remove mario if exists
|
||||
@ -632,11 +632,14 @@ void placeTool( SDLPP::Scene &scene ) {
|
||||
new_obj->getCollisions()[0]->setId(EDITOR_CHARACTER_ID);
|
||||
z_index = scene.getObjects().size() - 1;
|
||||
} else {
|
||||
obj.setCharacter(global_vars.current_tool->getId(), global_vars.current_world_type);
|
||||
new_obj = createTerrainBlock(obj.getCharacterId(), obj.getCharacterType(), renderer, global_vars.mouse.edit_box.getX(), global_vars.mouse.edit_box.getY(), false, true);
|
||||
obj.setCharacter(global_vars.current_tool->getId(),
|
||||
global_vars.current_world_type);
|
||||
new_obj = createTerrainBlock(
|
||||
obj.getCharacterId(), obj.getCharacterType(), renderer,
|
||||
global_vars.mouse.edit_box.getX(),
|
||||
global_vars.mouse.edit_box.getY(), false, true);
|
||||
new_obj->getCollisions()[0]->setId(EDITOR_CHARACTER_ID);
|
||||
dynamic_cast< MarioBlock * >( new_obj.get() )
|
||||
->setTerrain( false );
|
||||
dynamic_cast<MarioBlock *>(new_obj.get())->setTerrain(false);
|
||||
z_index = scene.getObjects().size() - 1;
|
||||
}
|
||||
break;
|
||||
@ -647,13 +650,11 @@ void placeTool( SDLPP::Scene &scene ) {
|
||||
obj.getModifierId(), LandType::OVERWORLD, renderer,
|
||||
global_vars.mouse.edit_box.getX(),
|
||||
global_vars.mouse.edit_box.getY(), false, true);
|
||||
new_obj->setTextureKeepSRC(
|
||||
global_vars.translucent_mod_texture );
|
||||
new_obj->setTextureKeepSRC(global_vars.translucent_mod_texture);
|
||||
new_obj->setData(global_vars.current_tool->getData());
|
||||
new_obj->getCollisions()[0]->setId(EDITOR_TERRAIN_ID);
|
||||
// TODO createModifierBlock
|
||||
dynamic_cast< MarioBlock * >( new_obj.get() )
|
||||
->setTerrain( false );
|
||||
dynamic_cast<MarioBlock *>(new_obj.get())->setTerrain(false);
|
||||
z_index = scene.getObjects().size() - 1;
|
||||
break;
|
||||
default:
|
||||
@ -779,9 +780,9 @@ void createGrid( double start_x, double start_y, int count_x, int count_y,
|
||||
|
||||
std::pair<std::shared_ptr<SDLPP::TextRenderer>,
|
||||
std::shared_ptr<SDLPP::TextRenderer>>
|
||||
createArrowControls(
|
||||
double left_x, double right_x, double start_y, double height,
|
||||
uint64_t left_id, uint64_t right_id, std::shared_ptr< SDLPP::Scene > &scene,
|
||||
createArrowControls(double left_x, double right_x, double start_y,
|
||||
double height, uint64_t left_id, uint64_t right_id,
|
||||
std::shared_ptr<SDLPP::Scene> &scene,
|
||||
std::shared_ptr<SDLPP::FontConfiguration> &font_config) {
|
||||
auto renderer = scene->getRendererShared();
|
||||
// white rectangles
|
||||
@ -838,20 +839,18 @@ void populateToolGrid(
|
||||
switch (type) {
|
||||
case ToolType::CHARACTER:
|
||||
if (block == MARIO_ID) {
|
||||
tool_store.push_back( createMario(
|
||||
global_vars.current_world_type, renderer, 0, 0, true ) );
|
||||
tool_store.push_back(createMario(global_vars.current_world_type,
|
||||
renderer, 0, 0, true));
|
||||
break;
|
||||
}
|
||||
// fall through
|
||||
case ToolType::MOD:
|
||||
tool_store.push_back(
|
||||
createTerrainBlock( block, global_vars.current_world_type,
|
||||
renderer, false, true ) );
|
||||
tool_store.push_back(createTerrainBlock(
|
||||
block, global_vars.current_world_type, renderer, false, true));
|
||||
break;
|
||||
case ToolType::BLOCK:
|
||||
tool_store.push_back(
|
||||
createTerrainBlock( block, global_vars.current_world_type,
|
||||
renderer, false, true ) );
|
||||
tool_store.push_back(createTerrainBlock(
|
||||
block, global_vars.current_world_type, renderer, false, true));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -877,9 +876,8 @@ void populateToolGrid(
|
||||
}
|
||||
}
|
||||
auto tool_text = std::make_shared<SDLPP::TextRenderer>(
|
||||
start_x - BLOCK_SIZE, start_y - BLOCK_SIZE,
|
||||
( count_x + 2 ) * BLOCK_SIZE, BLOCK_SIZE, renderer, title, font_config,
|
||||
SDLPP_TEXT_CENTER );
|
||||
start_x - BLOCK_SIZE, start_y - BLOCK_SIZE, (count_x + 2) * BLOCK_SIZE,
|
||||
BLOCK_SIZE, renderer, title, font_config, SDLPP_TEXT_CENTER);
|
||||
tool_text->setAlignment(SDLPP::OBJ_CENTER, SDLPP::OBJ_CENTER);
|
||||
tool_text->setPermanent();
|
||||
scene->addObject(tool_text);
|
||||
@ -921,8 +919,7 @@ void checkArrowsEnabled( uint64_t cur_page, uint64_t max_page,
|
||||
uint64_t left_flag, uint64_t right_flag,
|
||||
std::shared_ptr<SDLPP::TextRenderer> &left_arrow,
|
||||
std::shared_ptr<SDLPP::TextRenderer> &right_arrow,
|
||||
std::shared_ptr< SDLPP::Font > &font,
|
||||
bool map = false ) {
|
||||
std::shared_ptr<SDLPP::Font> &font, bool map = false) {
|
||||
if (cur_page == 0 && getFlag(left_flag)) {
|
||||
setFlag(UPDATE_FLAG);
|
||||
unsetFlag(left_flag);
|
||||
@ -965,8 +962,8 @@ int main() {
|
||||
auto font = std::make_shared<SDLPP::Font>("testfont.ttf", 36);
|
||||
auto font_config = std::make_shared<SDLPP::FontConfiguration>(
|
||||
font, "#000000", "#282828", 0.05);
|
||||
g_text_config = std::make_shared< SDLPP::FontConfiguration >(
|
||||
font, "#FFFFFF", "#000000", 0.15 );
|
||||
g_text_config = std::make_shared<SDLPP::FontConfiguration>(font, "#FFFFFF",
|
||||
"#000000", 0.15);
|
||||
|
||||
auto renderer = std::make_shared<SDLPP::Renderer>(w);
|
||||
renderer->setBlendMode(SDL_BLENDMODE_BLEND);
|
||||
@ -1029,8 +1026,8 @@ int main() {
|
||||
scene, "TERRAIN", font_config);
|
||||
arrows = createArrowControls(
|
||||
(MAP_WIDTH - TOOLS_WIDTH - 1) * BLOCK_SIZE, MAP_WIDTH * BLOCK_SIZE,
|
||||
1 - ( MAP_HEIGHT + 3 ) * BLOCK_SIZE, 2 * BLOCK_SIZE,
|
||||
EDITOR_LEFT_TOOL_ID, EDITOR_RIGHT_TOOL_ID, scene, font_config );
|
||||
1 - (MAP_HEIGHT + 3) * BLOCK_SIZE, 2 * BLOCK_SIZE, EDITOR_LEFT_TOOL_ID,
|
||||
EDITOR_RIGHT_TOOL_ID, scene, font_config);
|
||||
auto left_tool_arrow = arrows.first;
|
||||
auto right_tool_arrow = arrows.second;
|
||||
createGrid((MAP_WIDTH - TOOLS_WIDTH) * BLOCK_SIZE,
|
||||
@ -1040,38 +1037,36 @@ int main() {
|
||||
1 - (MAP_HEIGHT + 3) * BLOCK_SIZE, ToolType::MOD,
|
||||
possibleMods, global_vars.mods, global_vars.mod_boxes,
|
||||
scene, "MODS", font_config);
|
||||
arrows = createArrowControls(
|
||||
4 * BLOCK_SIZE, ( MOD_WIDTH + 5 ) * BLOCK_SIZE,
|
||||
1 - ( MAP_HEIGHT + 3 ) * BLOCK_SIZE, 2 * BLOCK_SIZE, EDITOR_LEFT_MOD_ID,
|
||||
arrows = createArrowControls(4 * BLOCK_SIZE, (MOD_WIDTH + 5) * BLOCK_SIZE,
|
||||
1 - (MAP_HEIGHT + 3) * BLOCK_SIZE,
|
||||
2 * BLOCK_SIZE, EDITOR_LEFT_MOD_ID,
|
||||
EDITOR_RIGHT_MOD_ID, scene, font_config);
|
||||
auto left_mod_arrow = arrows.first;
|
||||
auto right_mod_arrow = arrows.second;
|
||||
createGrid( 5 * BLOCK_SIZE, 1 - ( MAP_HEIGHT + 3 ) * BLOCK_SIZE, MOD_WIDTH,
|
||||
2, scene );
|
||||
createGrid(5 * BLOCK_SIZE, 1 - (MAP_HEIGHT + 3) * BLOCK_SIZE, MOD_WIDTH, 2,
|
||||
scene);
|
||||
// characters
|
||||
populateToolGrid(CHARACTER_WIDTH, 2, (MOD_WIDTH + 8) * BLOCK_SIZE,
|
||||
1 - (MAP_HEIGHT + 3) * BLOCK_SIZE, ToolType::CHARACTER,
|
||||
possibleCharacters, global_vars.characters,
|
||||
global_vars.character_boxes, scene, "CHARACTERS",
|
||||
font_config);
|
||||
arrows =
|
||||
createArrowControls( ( MOD_WIDTH + 7 ) * BLOCK_SIZE,
|
||||
arrows = createArrowControls((MOD_WIDTH + 7) * BLOCK_SIZE,
|
||||
(MOD_WIDTH + 8 + CHARACTER_WIDTH) * BLOCK_SIZE,
|
||||
1 - (MAP_HEIGHT + 3) * BLOCK_SIZE,
|
||||
2 * BLOCK_SIZE, EDITOR_LEFT_CHARACTER_ID,
|
||||
EDITOR_RIGHT_CHARACTER_ID, scene, font_config);
|
||||
auto left_char_arrow = arrows.first;
|
||||
auto right_char_arrow = arrows.second;
|
||||
createGrid( ( MOD_WIDTH + 8 ) * BLOCK_SIZE,
|
||||
1 - ( MAP_HEIGHT + 3 ) * BLOCK_SIZE, CHARACTER_WIDTH, 2,
|
||||
scene );
|
||||
createGrid((MOD_WIDTH + 8) * BLOCK_SIZE, 1 - (MAP_HEIGHT + 3) * BLOCK_SIZE,
|
||||
CHARACTER_WIDTH, 2, scene);
|
||||
|
||||
// world type
|
||||
populateWorldType(OVERWORLD_WIDTH, 2, BLOCK_SIZE,
|
||||
1 - (MAP_HEIGHT + 3) * BLOCK_SIZE, scene, "WORLD",
|
||||
font_config);
|
||||
createGrid( BLOCK_SIZE, 1 - ( MAP_HEIGHT + 3 ) * BLOCK_SIZE,
|
||||
OVERWORLD_WIDTH, 2, scene );
|
||||
createGrid(BLOCK_SIZE, 1 - (MAP_HEIGHT + 3) * BLOCK_SIZE, OVERWORLD_WIDTH,
|
||||
2, scene);
|
||||
|
||||
global_vars.map.max_page = global_vars.objects.size() - MAP_WIDTH;
|
||||
|
||||
@ -1082,8 +1077,8 @@ int main() {
|
||||
global_vars.tool.max_page_characters =
|
||||
(possibleCharacters.size() - 1) / (2 * CHARACTER_WIDTH);
|
||||
|
||||
auto mouse = std::make_shared< SDLPP::RectangleRender >( 0.01, 0.01, 0, 0,
|
||||
renderer );
|
||||
auto mouse =
|
||||
std::make_shared<SDLPP::RectangleRender>(0.01, 0.01, 0, 0, renderer);
|
||||
mouse->setMinWidth(1);
|
||||
mouse->setMinHeight(1);
|
||||
mouse->setAlignment(SDLPP::OBJ_CENTER, SDLPP::OBJ_CENTER);
|
||||
@ -1110,8 +1105,7 @@ int main() {
|
||||
COIN_MODIFIER_ID, LandType::OVERWORLD, renderer, 0, 0, false, true);
|
||||
global_vars.coin_tool->setData(1);
|
||||
global_vars.coin_tool->removeCollisions();
|
||||
global_vars.coin_tool->addCollision(
|
||||
SDLPP::RectColider( 0.1, 0.1, 0.8, 0.8 ) );
|
||||
global_vars.coin_tool->addCollision(SDLPP::RectColider(0.1, 0.1, 0.8, 0.8));
|
||||
global_vars.translucent_mod_texture = g_translucent_mod_texture;
|
||||
global_vars.translucent_enemies_texture = g_translucent_enemies_texture;
|
||||
dynamic_cast<MarioBlock &>(*global_vars.current_tool).setTool();
|
||||
|
@ -97,16 +97,16 @@ void ToolVisitor::visit( const SDLPP::RenderObject &obj ) {
|
||||
remove_block = true;
|
||||
if (obj.getId() == source_id &&
|
||||
((m_obj.getType() == source_type &&
|
||||
getVisitorType() == VisitorType::Terrain) || ( m_obj.getData() == _data && getVisitorType() == VisitorType::Modifier))) {
|
||||
getVisitorType() == VisitorType::Terrain) ||
|
||||
(m_obj.getData() == _data &&
|
||||
getVisitorType() == VisitorType::Modifier))) {
|
||||
add_block = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
case EDITOR_CHARACTER_ID: {
|
||||
const auto &m_obj = dynamic_cast<const MarioBlock &>(obj);
|
||||
remove_block = true;
|
||||
if ( obj.getId() == source_id &&
|
||||
m_obj.getType() == source_type &&
|
||||
if (obj.getId() == source_id && m_obj.getType() == source_type &&
|
||||
getVisitorType() == VisitorType::Character) {
|
||||
add_block = false;
|
||||
}
|
||||
|
@ -92,7 +92,8 @@ void moveToMarioPosition( SDLPP::Scene &scene,
|
||||
// sometimes there is a concurrency problem and prev_pos == cur_pos, in
|
||||
// that case move everything so Mario is standing on the left edge of the
|
||||
// screen
|
||||
if(mario_pos_difference.getX() < 0.01 && mario_pos_difference.getX() > -0.01) {
|
||||
if (mario_pos_difference.getX() < 0.01 &&
|
||||
mario_pos_difference.getX() > -0.01) {
|
||||
// 0.01 is the width of visible leftStop
|
||||
scene.moveEverything(-(mario->getAbsolutePos().getX() - 0.01), 0);
|
||||
} else {
|
||||
@ -150,11 +151,12 @@ void doInput( std::shared_ptr< SDLPP::Scene > scene ) {
|
||||
if (!moving_objects[i]->wasVisible()) {
|
||||
continue;
|
||||
}
|
||||
auto visitor =
|
||||
getVisitor( *moving_objects[i], *scene, quit, coin_count, moving_objects );
|
||||
auto visitor = getVisitor(*moving_objects[i], *scene, quit,
|
||||
coin_count, moving_objects);
|
||||
scene->visitCollisions(*moving_objects[i], *visitor);
|
||||
moving_objects[i]->handleVisitor(*visitor);
|
||||
auto rightmost_pos = moving_objects[i]->getAbsolutePos().getX() +
|
||||
auto rightmost_pos =
|
||||
moving_objects[i]->getAbsolutePos().getX() +
|
||||
moving_objects[i]->getDoubleRect().second.getX();
|
||||
if (rightmost_pos < 0 && moving_objects[i] != mario) {
|
||||
moving_objects[i]->destroy();
|
||||
@ -180,8 +182,7 @@ void doInput( std::shared_ptr< SDLPP::Scene > scene ) {
|
||||
auto rightBarrier = width * 0.5;
|
||||
auto rightmostX =
|
||||
scene->rightmost()->getRect().x + scene->rightmost()->getRect().w;
|
||||
scene->moveEverything(
|
||||
( playerX > rightBarrier && rightmostX > width ) *
|
||||
scene->moveEverything((playerX > rightBarrier && rightmostX > width) *
|
||||
(rightBarrier - playerX) / width,
|
||||
0);
|
||||
update = update || (playerX > rightBarrier && rightmostX > width);
|
||||
@ -235,8 +236,8 @@ int main() {
|
||||
|
||||
scene->addObject(defeat);
|
||||
|
||||
leftStop = std::make_shared< SDLPP::RectangleRender >( -0.1, 0, 0.11, 0,
|
||||
renderer );
|
||||
leftStop =
|
||||
std::make_shared<SDLPP::RectangleRender>(-0.1, 0, 0.11, 0, renderer);
|
||||
leftStop->setId(STOP_MOVEMENT);
|
||||
leftStop->setAlignment(SDLPP::OBJ_CENTER, SDLPP::OBJ_CENTER);
|
||||
leftStop->setPermanent();
|
||||
@ -276,12 +277,15 @@ int main() {
|
||||
update = true;
|
||||
|
||||
std::unordered_set<uint64_t> background_ids = {
|
||||
HILL_INCLINE_ID, HILL_DECLINE_ID, HILL_DOTS_RIGHT_ID, HILL_DOTS_LEFT_ID,
|
||||
HILL_FILL_ID, HILL_TOP_ID, BUSH_LEFT_ID, BUSH_MIDDLE_ID, BUSH_RIGHT_ID,
|
||||
HILL_INCLINE_ID, HILL_DECLINE_ID, HILL_DOTS_RIGHT_ID,
|
||||
HILL_DOTS_LEFT_ID, HILL_FILL_ID, HILL_TOP_ID,
|
||||
BUSH_LEFT_ID, BUSH_MIDDLE_ID, BUSH_RIGHT_ID,
|
||||
CLOUD_LEFT_BOTTOM_ID, CLOUD_MIDDLE_BOTTOM_ID, CLOUD_RIGHT_BOTTOM_ID,
|
||||
CLOUD_LEFT_TOP_ID, CLOUD_MIDDLE_TOP_ID, CLOUD_RIGHT_TOP_ID,
|
||||
CASTLE_LEFT_ID, CASTLE_RIGHT_ID, CASTLE_BLACK_ID, CASTLE_ENTRY_ID,
|
||||
CASTLE_TOWER_ID, CASTLE_TOWER_FILLED_ID, WATER_TOP_ID, WATER_FILL_ID };
|
||||
CASTLE_LEFT_ID, CASTLE_RIGHT_ID, CASTLE_BLACK_ID,
|
||||
CASTLE_ENTRY_ID, CASTLE_TOWER_ID, CASTLE_TOWER_FILLED_ID,
|
||||
WATER_TOP_ID, WATER_FILL_ID
|
||||
};
|
||||
scene->setBackgroundObjectIDs(background_ids);
|
||||
scene->updateBackgroundObjectZIndex();
|
||||
|
||||
|
@ -90,9 +90,8 @@ MapObject parseBlock( std::ifstream &map_file ) {
|
||||
// editor loader
|
||||
void loadMap(std::shared_ptr<SDLPP::Scene> &scene,
|
||||
std::shared_ptr<SDLPP::RenderObject> &mario,
|
||||
const std::string &file,
|
||||
std::vector< mapColumnType > &objects, bool editor,
|
||||
size_t editor_width ) {
|
||||
const std::string &file, std::vector<mapColumnType> &objects,
|
||||
bool editor, size_t editor_width) {
|
||||
auto renderer = scene->getRendererShared();
|
||||
std::ifstream map_file;
|
||||
map_file.open(file, std::ios::in | std::ios::binary);
|
||||
@ -116,17 +115,14 @@ void loadMap( std::shared_ptr< SDLPP::Scene > &scene,
|
||||
bool removeCollisions = false;
|
||||
int coinCount = 0;
|
||||
bool mushroom = false;
|
||||
if ( !editor &&
|
||||
block.getModifierId() == DESTRUCTIBLE_MODIFIER_ID ) {
|
||||
if (!editor && block.getModifierId() == DESTRUCTIBLE_MODIFIER_ID) {
|
||||
destructible = true;
|
||||
}
|
||||
if ( !editor &&
|
||||
block.getModifierId() == BACKGROUND_MODIFIER_ID ) {
|
||||
if (!editor && block.getModifierId() == BACKGROUND_MODIFIER_ID) {
|
||||
destructible = false;
|
||||
removeCollisions = true;
|
||||
}
|
||||
if ( !editor &&
|
||||
block.getModifierId() == COIN_MODIFIER_ID ) {
|
||||
if (!editor && block.getModifierId() == COIN_MODIFIER_ID) {
|
||||
coinCount = block.getModifierData();
|
||||
}
|
||||
if (!editor && block.getModifierId() == MUSHROOM_MODIFIER_ID) {
|
||||
@ -134,9 +130,9 @@ void loadMap( std::shared_ptr< SDLPP::Scene > &scene,
|
||||
}
|
||||
// TODO add modifiers to createTerrainBlock
|
||||
if (block.getTerrainId() != 0) {
|
||||
auto obj = createTerrainBlock(
|
||||
block.getTerrainId(), block.getTerrainType(),
|
||||
renderer, i, j, destructible, editor );
|
||||
auto obj = createTerrainBlock(block.getTerrainId(),
|
||||
block.getTerrainType(), renderer,
|
||||
i, j, destructible, editor);
|
||||
if (obj != nullptr) {
|
||||
obj->setCoinCount(coinCount);
|
||||
if (mushroom) {
|
||||
@ -156,8 +152,7 @@ void loadMap( std::shared_ptr< SDLPP::Scene > &scene,
|
||||
if (block.hasCharacter()) {
|
||||
if (block.getCharacterId() == MARIO_ID) {
|
||||
if (editor) {
|
||||
scene->addObject( createMario(
|
||||
block.getCharacterType(),
|
||||
scene->addObject(createMario(block.getCharacterType(),
|
||||
renderer, i, j, true));
|
||||
mario =
|
||||
scene->getObject(scene->getObjects().size() - 1);
|
||||
@ -178,9 +173,9 @@ void loadMap( std::shared_ptr< SDLPP::Scene > &scene,
|
||||
}
|
||||
if (editor && block.hasModifier()) {
|
||||
// TODO createModifierBlock with data
|
||||
auto mod = createTerrainBlock(
|
||||
block.getModifierId(), LandType::OVERWORLD, renderer, i, j,
|
||||
false, editor );
|
||||
auto mod = createTerrainBlock(block.getModifierId(),
|
||||
LandType::OVERWORLD, renderer, i,
|
||||
j, false, editor);
|
||||
mod->setData(block.getModifierData());
|
||||
mod->setTextureKeepSRC(g_translucent_mod_texture);
|
||||
mod->getCollisions()[0]->setId(EDITOR_TERRAIN_ID);
|
||||
@ -202,7 +197,8 @@ void saveMap( const std::string &file, std::vector< mapColumnType > &objects ) {
|
||||
for (auto &col : objects) {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
auto &block = col[i];
|
||||
auto wide_terrain = combineTerrain(block.getTerrainId(), block.getTerrainType());
|
||||
auto wide_terrain =
|
||||
combineTerrain(block.getTerrainId(), block.getTerrainType());
|
||||
// if block has additional data it needs to indicate it
|
||||
if (block.hasCharacter() || block.hasModifier()) {
|
||||
wide_terrain |= WIDE_TERRAIN_HAS_ADDITIONAL;
|
||||
@ -210,11 +206,14 @@ void saveMap( const std::string &file, std::vector< mapColumnType > &objects ) {
|
||||
write16Bits(output_file, wide_terrain);
|
||||
uint8_t additional_data = 0;
|
||||
if (block.hasCharacter()) {
|
||||
additional_data = combineAdditionalData(block.getCharacterId(), block.getCharacterType());
|
||||
additional_data = combineAdditionalData(
|
||||
block.getCharacterId(), block.getCharacterType());
|
||||
} else if (block.hasModifier()) {
|
||||
// TODO seriously change order of id/data!!!
|
||||
// we have IDs like 0x600X but only X is useful data, the 0x6 at the beginning is to differentiate mods from characters
|
||||
additional_data = combineAdditionalData(block.getModifierData(), block.getModifierId() & 0x000F);
|
||||
// we have IDs like 0x600X but only X is useful data, the 0x6 at
|
||||
// the beginning is to differentiate mods from characters
|
||||
additional_data = combineAdditionalData(
|
||||
block.getModifierData(), block.getModifierId() & 0x000F);
|
||||
additional_data |= ADDITIONAL_IS_MOD;
|
||||
}
|
||||
if (additional_data) {
|
||||
|
@ -12,8 +12,8 @@ void loadMap( std::shared_ptr< SDLPP::Scene > &scene,
|
||||
const std::string &file);
|
||||
void loadMap(std::shared_ptr<SDLPP::Scene> &scene,
|
||||
std::shared_ptr<SDLPP::RenderObject> &mario,
|
||||
const std::string &file,
|
||||
std::vector< mapColumnType > &objects, bool editor = false, size_t editor_width = 0 );
|
||||
const std::string &file, std::vector<mapColumnType> &objects,
|
||||
bool editor = false, size_t editor_width = 0);
|
||||
void saveMap(const std::string &file, std::vector<mapColumnType> &objects);
|
||||
|
||||
#endif
|
||||
|
@ -14,8 +14,7 @@ MapObject::MapObject( uint16_t terrain_id, uint8_t terrain_type,
|
||||
uint8_t character_id, uint8_t character_type,
|
||||
uint32_t modifier_id, uint8_t modifier_data)
|
||||
: MapObject(terrain_id, static_cast<LandType::Value>(terrain_type),
|
||||
character_id,
|
||||
static_cast< LandType::Value >( character_type ),
|
||||
character_id, static_cast<LandType::Value>(character_type),
|
||||
modifier_id, modifier_data) {}
|
||||
|
||||
void MapObject::setTerrain(uint16_t id, LandType::Value land_type) {
|
||||
|
@ -4,7 +4,8 @@
|
||||
#include "sprites.hpp"
|
||||
#include "visitors/mario_visitor.hpp"
|
||||
|
||||
Mario::Mario(int x, int y, const std::shared_ptr< SDLPP::Renderer > &renderer) : MarioBlock(x, y, renderer, g_mario_texture, MARIO_STANDING_SRC) {
|
||||
Mario::Mario(int x, int y, const std::shared_ptr<SDLPP::Renderer> &renderer)
|
||||
: MarioBlock(x, y, renderer, g_mario_texture, MARIO_STANDING_SRC) {
|
||||
setAnimationFrames(MARIO_WALK_ANIM);
|
||||
setId(MARIO_ID);
|
||||
setAlignment(SDLPP::OBJ_CENTER, SDLPP::OBJ_CENTER);
|
||||
@ -17,22 +18,21 @@ Mario::Mario(int x, int y, const std::shared_ptr< SDLPP::Renderer > &renderer) :
|
||||
bottom_detect.setOutlineColor("#FF0000");
|
||||
bottom_detect.setMinHeight(1);
|
||||
addCollision(bottom_detect);
|
||||
addCollision(
|
||||
SDLPP::RectColider( 0, 0.25, 0.1, 0.6, MARIO_LEFT_SIDE_DETECT ) );
|
||||
addCollision(SDLPP::RectColider(0, 0.25, 0.1, 0.6, MARIO_LEFT_SIDE_DETECT));
|
||||
addCollision(
|
||||
SDLPP::RectColider(0.9, 0.25, 0.1, 0.6, MARIO_RIGHT_SIDE_DETECT));
|
||||
addCollision(
|
||||
SDLPP::RectColider( 0, 0, 0.1, 0.1, MARIO_TOP_LEFT_DETECT ) );
|
||||
addCollision(
|
||||
SDLPP::RectColider( 0.9, 0, 0.1, 0.1, MARIO_TOP_LEFT_DETECT ) );
|
||||
top_collision = std::make_shared<SDLPP::RectColider>( 0.5, 0, 0.2, 0.15, MARIO_TOP_DETECT );
|
||||
addCollision(SDLPP::RectColider(0, 0, 0.1, 0.1, MARIO_TOP_LEFT_DETECT));
|
||||
addCollision(SDLPP::RectColider(0.9, 0, 0.1, 0.1, MARIO_TOP_LEFT_DETECT));
|
||||
top_collision = std::make_shared<SDLPP::RectColider>(0.5, 0, 0.2, 0.15,
|
||||
MARIO_TOP_DETECT);
|
||||
addCollision(top_collision);
|
||||
addCollision(SDLPP::RectColider(0, 1, 1, 0.2, MARIO_ENEMY_DETECT));
|
||||
setColiderColor("#FF0000");
|
||||
setStatic(false);
|
||||
bounce_speed *= 4;
|
||||
}
|
||||
Mario::Mario(const std::shared_ptr< SDLPP::Renderer > &renderer) : Mario(0, 0, renderer) {}
|
||||
Mario::Mario(const std::shared_ptr<SDLPP::Renderer> &renderer)
|
||||
: Mario(0, 0, renderer) {}
|
||||
void Mario::walkLeft() {
|
||||
if (on_ground)
|
||||
resumeAnimation();
|
||||
@ -65,7 +65,8 @@ void Mario::setStanding() {
|
||||
|
||||
void Mario::handleVisitor(SDLPP::Visitor &visitor) {
|
||||
#ifndef EDITOR
|
||||
// TODO - https://web.archive.org/web/20130807122227/http://i276.photobucket.com/albums/kk21/jdaster64/smb_playerphysics.png
|
||||
// TODO -
|
||||
// https://web.archive.org/web/20130807122227/http://i276.photobucket.com/albums/kk21/jdaster64/smb_playerphysics.png
|
||||
auto &m_visitor = dynamic_cast<MarioVisitor &>(visitor);
|
||||
// handle gravity
|
||||
on_ground = m_visitor.isOnGround();
|
||||
@ -95,9 +96,18 @@ void Mario::handleVisitor(SDLPP::Visitor &visitor) {
|
||||
// TODO more readable function names
|
||||
if (m_visitor.isStopped()) {
|
||||
setPos(m_visitor.getStopX(), getPos().getY());
|
||||
} else if ( m_visitor.canGoLeft() != m_visitor.canGoRight() && !(on_ground && m_visitor.getMovementBlockage().getY() > getPos().getY() + BLOCK_SIZE/2) ) {
|
||||
// only stop mario on ground if the block obstructs at least half of him (important for bug when mario lands from a high jump and is teleported if visitor is fired at wrong moment)
|
||||
SDLPP::Vec2D<double> next_pos = { m_visitor.getMovementBlockage().getX() + (m_visitor.canGoLeft() * -1 + m_visitor.canGoRight() * 1) * BLOCK_SIZE, getPos().getY() };
|
||||
} else if (m_visitor.canGoLeft() != m_visitor.canGoRight() &&
|
||||
!(on_ground && m_visitor.getMovementBlockage().getY() >
|
||||
getPos().getY() + BLOCK_SIZE / 2)) {
|
||||
// only stop mario on ground if the block obstructs at least half of him
|
||||
// (important for bug when mario lands from a high jump and is
|
||||
// teleported if visitor is fired at wrong moment)
|
||||
SDLPP::Vec2D<double> next_pos = {
|
||||
m_visitor.getMovementBlockage().getX() +
|
||||
(m_visitor.canGoLeft() * -1 + m_visitor.canGoRight() * 1) *
|
||||
BLOCK_SIZE,
|
||||
getPos().getY()
|
||||
};
|
||||
setPos(next_pos);
|
||||
} else if (m_visitor.moveTop() && jumping && !stop_jump) {
|
||||
auto objPos = m_visitor.getRightLeftPos();
|
||||
|
@ -14,9 +14,9 @@ const SDL_Rect MARIO_JUMP_SRC = { 119, 9, 16, 16 };
|
||||
|
||||
const SDL_Rect MARIO_STANDING_BIG_SRC = { 1, 26, 16, 32 };
|
||||
const SDL_Rect MARIO_DEATH_BIG_SRC = { 22, 26, 16, 32 };
|
||||
const std::vector< SDL_Rect > MARIO_WALK_BIG_ANIM = {
|
||||
{ 43, 26, 16, 32 }, { 60, 9, 16, 32 }, { 77, 9, 16, 32 }
|
||||
};
|
||||
const std::vector<SDL_Rect> MARIO_WALK_BIG_ANIM = { { 43, 26, 16, 32 },
|
||||
{ 60, 9, 16, 32 },
|
||||
{ 77, 9, 16, 32 } };
|
||||
const SDL_Rect MARIO_CHANGE_DIR_BIG_SRC = { 98, 26, 16, 32 };
|
||||
const SDL_Rect MARIO_JUMP_BIG_SRC = { 119, 26, 16, 32 };
|
||||
|
||||
|
@ -3,7 +3,11 @@
|
||||
#include "blocks.hpp"
|
||||
#include "sprites.hpp"
|
||||
|
||||
ToolBox::ToolBox(int x, int y, double start_x, double start_y, std::shared_ptr<SDLPP::Renderer> renderer, bool coliders) : SDLPP::RectangleRender(start_x + x*BLOCK_SIZE, start_y + y*BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, renderer) {
|
||||
ToolBox::ToolBox(int x, int y, double start_x, double start_y,
|
||||
std::shared_ptr<SDLPP::Renderer> renderer, bool coliders)
|
||||
: SDLPP::RectangleRender(start_x + x * BLOCK_SIZE,
|
||||
start_y + y * BLOCK_SIZE, BLOCK_SIZE,
|
||||
BLOCK_SIZE, renderer) {
|
||||
_x = x;
|
||||
_y = y;
|
||||
setId(EDITOR_TOOL_ID);
|
||||
|
@ -5,7 +5,8 @@
|
||||
|
||||
class ToolBox : public SDLPP::RectangleRender {
|
||||
public:
|
||||
ToolBox(int x, int y, double start_x, double start_y, std::shared_ptr<SDLPP::Renderer> renderer, bool coliders = true);
|
||||
ToolBox(int x, int y, double start_x, double start_y,
|
||||
std::shared_ptr<SDLPP::Renderer> renderer, bool coliders = true);
|
||||
virtual SDLPP::Vec2D<int> getIndexes() const;
|
||||
virtual void visit(SDLPP::Visitor &visitor) override;
|
||||
uint64_t getType() const {
|
||||
@ -14,6 +15,7 @@ public:
|
||||
void setType(uint64_t type) {
|
||||
_type = type;
|
||||
}
|
||||
|
||||
private:
|
||||
int _x;
|
||||
int _y;
|
||||
|
Loading…
Reference in New Issue
Block a user