Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix invalid calculation of "short" object passability #8429

Draft
wants to merge 10 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 36 additions & 40 deletions src/fheroes2/maps/maps_tiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <cassert>
#include <cstdint>
#include <cstdlib>
#include <deque>
#include <iostream>
#include <limits>
#include <set>
Expand Down Expand Up @@ -248,46 +249,39 @@ namespace
}
#endif

bool isShortObject( const MP2::MapObjectType objectType )
bool isShortObject( const uint32_t uid, const int32_t startIndex )
{
// Some objects allow middle moves even being attached to the bottom.
// These object actually don't have any sprites on tiles above them within addon 2 level objects.
// TODO: find a better way to do not hardcode values here.
const int32_t startY = startIndex / world.w();

switch ( objectType ) {
case MP2::OBJ_HALFLING_HOLE:
case MP2::OBJ_NON_ACTION_HALFLING_HOLE:
case MP2::OBJ_LEAN_TO:
case MP2::OBJ_WATER_LAKE:
case MP2::OBJ_TAR_PIT:
case MP2::OBJ_MERCENARY_CAMP:
case MP2::OBJ_NON_ACTION_MERCENARY_CAMP:
case MP2::OBJ_STANDING_STONES:
case MP2::OBJ_SHRINE_FIRST_CIRCLE:
case MP2::OBJ_SHRINE_SECOND_CIRCLE:
case MP2::OBJ_SHRINE_THIRD_CIRCLE:
case MP2::OBJ_MAGIC_GARDEN:
case MP2::OBJ_RUINS:
case MP2::OBJ_NON_ACTION_RUINS:
case MP2::OBJ_SIGN:
case MP2::OBJ_IDOL:
case MP2::OBJ_STONE_LITHS:
case MP2::OBJ_NON_ACTION_STONE_LITHS:
case MP2::OBJ_WAGON:
case MP2::OBJ_WAGON_CAMP:
case MP2::OBJ_NON_ACTION_WAGON_CAMP:
case MP2::OBJ_GOBLIN_HUT:
case MP2::OBJ_FAERIE_RING:
case MP2::OBJ_NON_ACTION_FAERIE_RING:
case MP2::OBJ_BARRIER:
case MP2::OBJ_MAGIC_WELL:
case MP2::OBJ_NOTHING_SPECIAL:
return true;
default:
break;
std::deque<int32_t> indexToTraverse{ startIndex };
std::set<int32_t> traversedIndex;

const Directions & directions = Direction::All();

while ( !indexToTraverse.empty() ) {
traversedIndex.emplace( indexToTraverse.front() );

for ( const int direction : directions ) {
if ( !Maps::isValidDirection( indexToTraverse.front(), direction ) ) {
continue;
}

const int32_t newIndex = Maps::GetDirectionIndex( indexToTraverse.front(), direction );
const Maps::Tiles & tile = world.GetTiles( newIndex );

if ( Maps::doesTileHaveObjectUID( tile, uid ) && traversedIndex.count( newIndex ) == 0 ) {
if ( ( newIndex / world.w() ) != startY ) {
return false;
}

indexToTraverse.emplace_back( newIndex );
}
}

indexToTraverse.pop_front();
}

return false;
return true;
}

bool isDetachedObjectType( const MP2::MapObjectType objectType )
Expand Down Expand Up @@ -507,7 +501,7 @@ void Maps::Tiles::Init( int32_t index, const MP2::mp2tile_t & mp2 )
_isTileMarkedAsRoad = true;
}

if ( mp2.mapObjectType == MP2::OBJ_NONE && ( layerType == Maps::ObjectLayerType::SHADOW_LAYER || layerType == Maps::ObjectLayerType::TERRAIN_LAYER ) ) {
if ( _mainObjectType == MP2::OBJ_NONE && ( layerType == Maps::ObjectLayerType::SHADOW_LAYER || layerType == Maps::ObjectLayerType::TERRAIN_LAYER ) ) {
// If an object sits on shadow or terrain layer then we should put it as a bottom layer add-on.
if ( bottomObjectIcnType != MP2::ObjectIcnType::OBJ_ICN_TYPE_UNKNOWN ) {
_addonBottomLayer.emplace_back( layerType, mp2.level1ObjectUID, bottomObjectIcnType, mp2.bottomIcnImageIndex );
Expand Down Expand Up @@ -790,9 +784,11 @@ void Maps::Tiles::updatePassability()
const MP2::MapObjectType bottomTileObjectType = bottomTile.GetObject( false );
const MP2::MapObjectType correctedObjectType = MP2::getBaseActionObjectType( bottomTileObjectType );

const bool isBottomObjectShort = isShortObject( bottomTile.GetObjectUID(), bottomTile.GetIndex() );

if ( MP2::isActionObject( bottomTileObjectType ) ) {
if ( ( MP2::getActionObjectDirection( bottomTileObjectType ) & Direction::TOP ) == 0 ) {
if ( isShortObject( bottomTileObjectType ) ) {
if ( isBottomObjectShort ) {
_tilePassabilityDirections &= ~Direction::BOTTOM;
}
else {
Expand All @@ -802,10 +798,10 @@ void Maps::Tiles::updatePassability()
}
}
else if ( bottomTile._mainObjectType != MP2::OBJ_NONE && correctedObjectType != bottomTileObjectType && MP2::isActionObject( correctedObjectType )
&& isShortObject( correctedObjectType ) && ( bottomTile.getOriginalPassability() & Direction::TOP ) == 0 ) {
&& isBottomObjectShort && ( bottomTile.getOriginalPassability() & Direction::TOP ) == 0 ) {
ihhub marked this conversation as resolved.
Show resolved Hide resolved
_tilePassabilityDirections &= ~Direction::BOTTOM;
}
else if ( isShortObject( bottomTileObjectType )
else if ( isBottomObjectShort
|| ( !bottomTile.containsAnyObjectIcnType( getValidObjectIcnTypes() )
&& ( isCombinedObject( objectType ) || isCombinedObject( bottomTileObjectType ) ) ) ) {
_tilePassabilityDirections &= ~Direction::BOTTOM;
Expand Down
21 changes: 21 additions & 0 deletions src/fheroes2/maps/maps_tiles_helper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3120,6 +3120,27 @@ namespace Maps
}
}

bool doesTileHaveObjectUID( const Tiles & tile, const uint32_t uid )
{
if ( tile.GetObjectUID() == uid ) {
return true;
}

for ( const TilesAddon & addon : tile.getBottomLayerAddons() ) {
if ( addon._uid == uid ) {
return true;
}
}

for ( const TilesAddon & addon : tile.getTopLayerAddons() ) {
ihhub marked this conversation as resolved.
Show resolved Hide resolved
if ( addon._uid == uid ) {
return true;
}
}

return false;
}

bool removeObjectTypeFromTile( Tiles & tile, const MP2::ObjectIcnType objectIcnType )
{
if ( tile.getObjectIdByObjectIcnType( objectIcnType ) == 0 ) {
Expand Down
2 changes: 2 additions & 0 deletions src/fheroes2/maps/maps_tiles_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ namespace Maps
// Determine the fog direction in the area between min and max positions for given player(s) color code and store it in corresponding tile data.
void updateFogDirectionsInArea( const fheroes2::Point & minPos, const fheroes2::Point & maxPos, const int32_t color );

bool doesTileHaveObjectUID( const Tiles & tile, const uint32_t uid );

// The functions below are used only in the map Editor.

void setTerrainOnTiles( const int32_t startTileId, const int32_t endTileId, const int groundId );
Expand Down
Loading