Пример #1
0
void CWorld::GetHeightPoint( const CPointMap & pt, CGrayMapBlockState & block, bool fHouseCheck )
{
	ADDTOCALLSTACK("CWorld::GetHeightPoint");
	CItemBase * pItemDef = NULL;
	CItemBaseDupe * pDupeDef = NULL;
	CItem * pItem = NULL;
	DWORD wBlockThis = 0;
	signed char z = 0;
	height_t zHeight = 0;
	int x2 = 0, y2 = 0;

	// Height of statics at/above given coordinates
	// do gravity here for the z.
	const CGrayMapBlock * pMapBlock = GetMapBlock( pt );
	if (pMapBlock == NULL)
		return;

	size_t iQty = pMapBlock->m_Statics.GetStaticQty();
	if ( iQty > 0 )  // no static items here.
	{
		x2 = pMapBlock->GetOffsetX(pt.m_x);
		y2 = pMapBlock->GetOffsetY(pt.m_y);
		const CUOStaticItemRec * pStatic = NULL;
		for ( size_t i = 0; i < iQty; ++i, z = 0, zHeight = 0, pStatic = NULL, pDupeDef = NULL )
		{
			if ( ! pMapBlock->m_Statics.IsStaticPoint( i, x2, y2 ))
				continue;

			pStatic = pMapBlock->m_Statics.GetStatic( i );
			if ( pStatic == NULL )
				continue;

			z = pStatic->m_z;

			//DEBUG_ERR(("z (%d)  block.m_zHeight (%d) block.m_Bottom.m_z (%d)\n",z,block.m_zHeight,block.m_Bottom.m_z));
			if ( ! block.IsUsableZ( z, block.m_zHeight ))
				continue;

			// This static is at the coordinates in question.
			// enough room for me to stand here ?

			pItemDef = CItemBase::FindItemBase( pStatic->GetDispID() );
			if ( pItemDef )
			{
				//DEBUG_ERR(("pItemDef->GetID(0%x) pItemDef->GetDispID(0%x) pStatic->GetDispID(0%x)\n",pItemDef->GetID(),pItemDef->GetDispID(),pStatic->GetDispID()));
				if ( pItemDef->GetID() == pStatic->GetDispID() ) //parent item
				{
					zHeight = pItemDef->GetHeight();
					wBlockThis = ( pItemDef->m_Can & CAN_I_MOVEMASK ); //Use only Block flags, other remove
				}
				else //non-parent item
				{
					pDupeDef = CItemBaseDupe::GetDupeRef(static_cast<ITEMID_TYPE>(pStatic->GetDispID()));
					if ( ! pDupeDef )
					{
						g_Log.EventDebug("Failed to get non-parent reference (static) (DispID 0%x) (X: %d Y: %d Z: %d)\n",pStatic->GetDispID(),pStatic->m_x+pMapBlock->m_x,pStatic->m_y+pMapBlock->m_y,pStatic->m_z);
						zHeight = pItemDef->GetHeight();
						wBlockThis = ( pItemDef->m_Can & CAN_I_MOVEMASK );
					}
					else
					{
						zHeight = pDupeDef->GetHeight();
						wBlockThis = ( pDupeDef->m_Can & CAN_I_MOVEMASK ); //Use only Block flags, other remove - CAN flags cannot be inherited from the parent item due to bad script pack...
					}
				}
			}
			else if ( pStatic->GetDispID() )
				CItemBase::GetItemTiledataFlags(wBlockThis,pStatic->GetDispID());

			block.CheckTile_Item( wBlockThis, z, zHeight, pStatic->GetDispID() + TERRAIN_QTY );
		}
	}

	pItemDef = NULL;
	pDupeDef = NULL;
	pItem = NULL;
	wBlockThis = 0;
	z = 0;
	zHeight = 0;
	x2 = y2 = 0;
	iQty = 0;

	// Any multi items here ?
	// Check all of them
	if ( fHouseCheck )
	{
		CRegionLinks rlinks;
		size_t iRegionQty = pt.GetRegions( REGION_TYPE_MULTI, rlinks );
		if ( iRegionQty > 0 )
		{
			//  ------------ For variables --------------------
			CRegionBase * pRegion = NULL;
			const CGrayMulti * pMulti = NULL;
			const CUOMultiItemRec2 * pMultiItem = NULL;
			x2 = 0;
			y2 = 0;
			//  ------------ For variables --------------------

			for ( size_t iRegion = 0; iRegion < iRegionQty; ++iRegion, pRegion = NULL, pItem = NULL, pMulti = NULL, x2 = 0, y2 = 0 )
			{
				pRegion = rlinks.GetAt(iRegion);
				if ( pRegion != NULL )
					pItem = pRegion->GetResourceID().ItemFind();

				if ( pItem != NULL )
				{
					pMulti = g_Cfg.GetMultiItemDefs(pItem);
					if ( pMulti )
					{
						x2 = pt.m_x - pItem->GetTopPoint().m_x;
						y2 = pt.m_y - pItem->GetTopPoint().m_y;

						iQty = pMulti->GetItemCount();
						for ( size_t ii = 0; ii < iQty; ++ii, pMultiItem = NULL, z = 0, zHeight = 0 )
						{
							pMultiItem = pMulti->GetItem(ii);

							if ( !pMultiItem )
								break;

							if ( ! pMultiItem->m_visible )
								continue;

							if ( pMultiItem->m_dx != x2 || pMultiItem->m_dy != y2 )
								continue;

							z = static_cast<signed char>( pItem->GetTopZ() + pMultiItem->m_dz );
							if ( ! block.IsUsableZ(z,block.m_zHeight))
								continue;

							pItemDef = CItemBase::FindItemBase( pMultiItem->GetDispID() );
							if ( pItemDef != NULL )
							{
								if ( pItemDef->GetID() == pMultiItem->GetDispID() ) //parent item
								{
									zHeight = pItemDef->GetHeight();
									wBlockThis = ( pItemDef->m_Can & CAN_I_MOVEMASK ); //Use only Block flags, other remove
								}
								else //non-parent item
								{
									pDupeDef = CItemBaseDupe::GetDupeRef(static_cast<ITEMID_TYPE>(pMultiItem->GetDispID()));
									if ( pDupeDef == NULL )
									{
										g_Log.EventDebug("Failed to get non-parent reference (multi) (DispID 0%x) (X: %d Y: %d Z: %d)\n",pMultiItem->GetDispID(),pMultiItem->m_dx+pItem->GetTopPoint().m_x,pMultiItem->m_dy+pItem->GetTopPoint().m_y,pMultiItem->m_dz+pItem->GetTopPoint().m_z);
										zHeight = pItemDef->GetHeight();
										wBlockThis = ( pItemDef->m_Can & CAN_I_MOVEMASK );
									}
									else
									{
										zHeight = pDupeDef->GetHeight();
										wBlockThis = ( pDupeDef->m_Can & CAN_I_MOVEMASK ); //Use only Block flags, other remove - CAN flags cannot be inherited from the parent item due to bad script pack...
									}
								}
							}
							else if ( pMultiItem->GetDispID() )
								CItemBase::GetItemTiledataFlags(wBlockThis,pMultiItem->GetDispID());

							block.CheckTile_Item( wBlockThis, z, zHeight, pMultiItem->GetDispID() + TERRAIN_QTY );
						}
					}
				}
			}
		}
	}

	pItemDef = NULL;
	pDupeDef = NULL;
	pItem = NULL;
	wBlockThis = 0;
	x2 = y2 = iQty = 0;
	zHeight = 0;
	z = 0;

	// Any dynamic items here ?
	// NOTE: This could just be an item that an NPC could just move ?
	CWorldSearch Area( pt );

	for (;;)
	{
		pItem = Area.GetItem();
		if ( !pItem )
			break;

		z = pItem->GetTopZ();
		if ( !block.IsUsableZ( z, block.m_zHeight ) )
			continue;

		// Invis items should not block ???
		pItemDef = CItemBase::FindItemBase( pItem->GetDispID() );

		if ( pItemDef )
		{
			if ( pItemDef->GetDispID() == pItem->GetDispID() )//parent item
			{
				zHeight = pItemDef->GetHeight();
				wBlockThis = ( pItemDef->m_Can & CAN_I_MOVEMASK ); //Use only Block flags, other remove
			}
			else //non-parent item
			{
				pDupeDef = CItemBaseDupe::GetDupeRef(static_cast<ITEMID_TYPE>(pItem->GetDispID()));
				if ( ! pDupeDef )
				{
					g_Log.EventDebug("Failed to get non-parent reference (dynamic) (DispID 0%x) (X: %d Y: %d Z: %d)\n",pItem->GetDispID(),pItem->GetTopPoint().m_x,pItem->GetTopPoint().m_y,pItem->GetTopPoint().m_z);
					zHeight = pItemDef->GetHeight();
					wBlockThis = ( pItemDef->m_Can & CAN_I_MOVEMASK );
				}
				else
				{
					zHeight = pDupeDef->GetHeight();
					wBlockThis = ( pDupeDef->m_Can & CAN_I_MOVEMASK ); //Use only Block flags, other remove - CAN flags cannot be inherited from the parent item due to bad script pack...
				}
			}
		}
		else if (pItem->GetDispID())
			CItemBase::GetItemTiledataFlags(wBlockThis,pItem->GetDispID());

		block.CheckTile_Item(wBlockThis, z, zHeight, pItem->GetDispID() + TERRAIN_QTY);
	}

	wBlockThis = 0;
	// Terrain height is screwed. Since it is related to all the terrain around it.
	const CUOMapMeter * pMeter = pMapBlock->GetTerrain( UO_BLOCK_OFFSET(pt.m_x), UO_BLOCK_OFFSET(pt.m_y));
	if ( ! pMeter )
		return;

	if ( block.IsUsableZ( pMeter->m_z,block.m_zHeight ) )
	{
		//DEBUG_ERR(("pMeter->m_wTerrainIndex 0%x wBlockThis (0%x)\n",pMeter->m_wTerrainIndex,wBlockThis));
		if ( pMeter->m_wTerrainIndex == TERRAIN_HOLE )
		{
			wBlockThis = 0;
		}
		else if ( CUOMapMeter::IsTerrainNull( pMeter->m_wTerrainIndex ) )	// inter dungeon type.
		{
			wBlockThis = CAN_I_BLOCK;
		}
		else
		{
			CGrayTerrainInfo land( pMeter->m_wTerrainIndex );
			//DEBUG_ERR(("Terrain flags - land.m_flags 0%x wBlockThis (0%x)\n",land.m_flags,wBlockThis));
			if ( land.m_flags & UFLAG1_WATER )
				wBlockThis |= CAN_I_WATER;
			if ( land.m_flags & UFLAG1_DAMAGE )
				wBlockThis |= CAN_I_FIRE;
			if ( land.m_flags & UFLAG1_BLOCK )
				wBlockThis |= CAN_I_BLOCK;
			if (( ! wBlockThis ) || ( land.m_flags & UFLAG2_PLATFORM )) // Platform items should take precendence over non-platforms.
				wBlockThis = CAN_I_PLATFORM;
		}
		//DEBUG_ERR(("TERRAIN wBlockThis (0%x)\n",wBlockThis));
		block.CheckTile_Terrain( wBlockThis, pMeter->m_z, pMeter->m_wTerrainIndex );
	}

	if ( block.m_Bottom.m_z == UO_SIZE_MIN_Z )
	{
		block.m_Bottom = block.m_Lowest;
		if ( block.m_Top.m_z == block.m_Bottom.m_z )
		{
			block.m_Top.m_dwBlockFlags = 0;
			block.m_Top.m_dwTile = 0;
			block.m_Top.m_z = UO_SIZE_Z;
		}
	}
}
Пример #2
0
CPointMap CWorld::FindTypeNear_Top( const CPointMap & pt, IT_TYPE iType, int iDistance )
{
	ADDTOCALLSTACK("CWorld::FindTypeNear_Top");
#define RESOURCE_Z_CHECK 8
	CPointMap ptFound;
	CItemBase * pItemDef = NULL;
	CItem * pItem = NULL;
	CItemBaseDupe * pDupeDef = NULL;
	height_t Height = 0;
	BYTE z = 0;
	CPointMap ptTest;

	unsigned int iRetElem = 4;

	CPointMap ptElem[5];
	memset(ptElem, 0, sizeof(ptElem));
	//for ( iQty = 0; iQty < 4; ++iQty )
	//	ptElem[iQty].m_z = UO_SIZE_MIN_Z;
	ptElem[0].m_z = ptElem[1].m_z  = ptElem[2].m_z  = ptElem[3].m_z = UO_SIZE_MIN_Z;
	ptElem[4] = CPointMap(USHRT_MAX, USHRT_MAX, UO_SIZE_MIN_Z);

	bool fElem[4] = { false, false, false, false };

	// Check dynamics
	CWorldSearch Area( pt, iDistance );
	Area.SetAllShow( true );
	for (;;)
	{
		z = 0;
		Height = 0;
		pItem = Area.GetItem();
		if ( pItem == NULL )
			break;

		if ( pt.GetDist( pItem->GetTopPoint() ) > iDistance )
			continue;

		pItemDef = CItemBase::FindItemBase( pItem->GetDispID() );
		if ( pItemDef == NULL )
			continue;

		Height = pItemDef->GetHeight();
		if ( pItemDef->GetID() != pItem->GetDispID() ) //not a parent item
		{
			pDupeDef = CItemBaseDupe::GetDupeRef(static_cast<ITEMID_TYPE>(pItem->GetDispID()));
			if ( ! pDupeDef )
			{
				g_Log.EventDebug("Failed to get non-parent reference (dynamic) (DispID 0%x) (X: %d Y: %d Z: %d)\n",pItem->GetDispID(),ptTest.m_x,ptTest.m_y,ptTest.m_z);
				Height = pItemDef->GetHeight();
			}
			else
				Height = pDupeDef->GetHeight();
		}
		z = minimum( Height + pItem->GetTopPoint().m_z, UO_SIZE_Z ); //height + current position = the top point

		if ( ptElem[0].m_z > z ) //if ( ptElem[0].m_z > pItem->GetTopPoint().m_z )
			continue;

		if ( ((( z - pt.m_z ) > 0) && ( z - pt.m_z ) > RESOURCE_Z_CHECK ) || ((( pt.m_z - z ) < 0) && (( pt.m_z - z ) < - RESOURCE_Z_CHECK ))) //if ( ((( pItem->GetTopPoint().m_z - pt.m_z ) > 0) && ( pItem->GetTopPoint().m_z - pt.m_z ) > RESOURCE_Z_CHECK ) || ((( pt.m_z - pItem->GetTopPoint().m_z ) < 0) && (( pt.m_z - pItem->GetTopPoint().m_z ) < - RESOURCE_Z_CHECK )))
			continue;

		if (( z < ptElem[0].m_z ) || (( z == ptElem[0].m_z ) && ( fElem[0] )))
			continue;
        
		ptElem[0] = pItem->GetTopPoint();
		ptElem[0].m_z = z;
		fElem[0] = false;

		//DEBUG_ERR(("dynamic pItem->IsType( iType %d) %d\n",iType,pItem->IsType( iType )));
		if ( pItem->IsType( iType ) )  //( pItem->Item_GetDef()->IsType(iType) ) )
		{
			fElem[0] = true;
			iRetElem = 0;
		}
	}

	// Parts of multis ?
	const CGrayMulti * pMulti 			= NULL;		// Multi Def (multi check)
	const CUOMultiItemRec2 * pMultiItem = NULL;		// Multi item iterator
	CRegionBase * pRegion				= NULL;
	CRegionLinks rlinks;
	size_t iRegionQty = pt.GetRegions( REGION_TYPE_MULTI, rlinks );
	if ( iRegionQty > 0 )
	{
		for ( size_t iRegion = 0; iRegion < iRegionQty; pMulti = NULL, ++iRegion)
		{
			pRegion = rlinks.GetAt(iRegion);
			pItem = pRegion->GetResourceID().ItemFind();
			if ( !pItem )
				continue;
			pMulti = g_Cfg.GetMultiItemDefs(pItem);
			if ( !pMulti )
				continue;
			size_t iMultiQty = pMulti->GetItemCount();
			for ( size_t iMulti = 0; iMulti < iMultiQty; pItemDef = NULL, pMultiItem = NULL, Height = 0, ++iMulti )
			{
				pMultiItem = pMulti->GetItem(iMulti);
				
				if ( !pMultiItem )
					break;

				//DEBUG_ERR(("abs( pMultiItem->m_dx ) %x, abs( pMultiItem->m_dy ) %x, abs( pMultiItem->m_dz ) %x,\n             iDistance %x IF STATEMENT %x %x\n", abs( pMultiItem->m_dx ), abs( pMultiItem->m_dy ), abs( pMultiItem->m_dz ), iDistance, ( abs( pMultiItem->m_dx ) <= iDistance ), ( abs( pMultiItem->m_dy ) <= iDistance ) ));

				if ( !pMultiItem->m_visible )
					continue;

				ptTest = CPointMap( pMultiItem->m_dx + pt.m_x, pMultiItem->m_dy + pt.m_y, static_cast<signed char>( pMultiItem->m_dz + pt.m_z ), pt.m_map );

				pItemDef = CItemBase::FindItemBase( pMultiItem->GetDispID() );
				if ( pItemDef == NULL )
					continue;

				Height = pItemDef->GetHeight();
				if ( pItemDef->GetID() != pMultiItem->GetDispID() ) //not a parent item
				{
					pDupeDef = CItemBaseDupe::GetDupeRef(static_cast<ITEMID_TYPE>(pMultiItem->GetDispID()));
					if ( ! pDupeDef )
					{
						g_Log.EventDebug("Failed to get non-parent reference (multi) (DispID 0%x) (X: %d Y: %d Z: %d)\n",pMultiItem->GetDispID(),ptTest.m_x,ptTest.m_y,ptTest.m_z);
						Height = pItemDef->GetHeight();
					}
					else
						Height = pDupeDef->GetHeight();
				}
				ptTest.m_z = minimum(ptTest.m_z + Height, UO_SIZE_Z); //height + current position = the top point

				if ( pt.GetDist( ptTest ) > iDistance )
					continue;

				if ( ptElem[1].m_z > ptTest.m_z )
					continue;
		
				if ( ((( ptTest.m_z - pt.m_z ) > 0) && ( ptTest.m_z - pt.m_z ) > RESOURCE_Z_CHECK ) || ((( pt.m_z - ptTest.m_z ) < 0) && (( pt.m_z - ptTest.m_z ) < - RESOURCE_Z_CHECK )))
					continue;
	
				if (( ptTest.m_z < ptElem[1].m_z ) || (( ptTest.m_z == ptElem[1].m_z ) && ( fElem[1] )))
					continue;
		        //DEBUG_ERR(("pMultiItem->GetDispID()%x\n",pMultiItem->GetDispID()));
				ptElem[1] = ptTest;
				fElem[1] = false;

				//DEBUG_ERR(("multi pItemDef->IsType( iType %d) %d\n",iType,pItemDef->IsType( iType )));
				if ( pItemDef->IsType( iType ) )
				{
					fElem[1] = true;
					//if ( ptElem[iRetElem].m_z > ptElem[1].m_z )
					if ( ptElem[1].m_z > ptElem[iRetElem].m_z )
						iRetElem = 1;
				}

				//DEBUG_ERR(( "DISPID: %x X %d Y %d Z %d\n", pMultiItem->GetDispID(), (pMultiItem->m_dx), (pMultiItem->m_dy), (pMultiItem->m_dz) ));
			}
		}
	}

	// STATIC - checks one 8x8 block
	const CGrayMapBlock * pMapBlock = GetMapBlock( pt );
	ASSERT( pMapBlock );

	size_t iStaticQty = pMapBlock->m_Statics.GetStaticQty();
	if ( iStaticQty > 0 )  // no static items here.
	{
		const CUOStaticItemRec * pStatic = NULL;

		for ( size_t i = 0; i < iStaticQty; ++i, pStatic = NULL, Height = 0, pItemDef = NULL )
		{
			pStatic = pMapBlock->m_Statics.GetStatic( i );

			ptTest = CPointMap( pStatic->m_x + pMapBlock->m_x, pStatic->m_y + pMapBlock->m_y, pStatic->m_z, pt.m_map );

			pItemDef = CItemBase::FindItemBase( pStatic->GetDispID() );
			if ( pItemDef == NULL )
				continue;

			//DEBUG_ERR(("pStatic->GetDispID() %d; name %s; pStatic->m_z %d\n",pStatic->GetDispID(),pItemDef->GetName(),pStatic->m_z));
			Height = pItemDef->GetHeight();
			if ( pItemDef->GetID() != pStatic->GetDispID() ) //not a parent item
			{
				pDupeDef = CItemBaseDupe::GetDupeRef(static_cast<ITEMID_TYPE>(pStatic->GetDispID()));
				if ( ! pDupeDef )
				{
					g_Log.EventDebug("Failed to get non-parent reference (static) (DispID 0%x) (X: %d Y: %d Z: %d)\n",pStatic->GetDispID(),ptTest.m_x,ptTest.m_y,ptTest.m_z);
					Height = pItemDef->GetHeight();
				}
				else
					Height = pDupeDef->GetHeight();
			}
			ptTest.m_z = minimum(ptTest.m_z + Height, UO_SIZE_Z); //height + current position = the top point

			if ( pt.GetDist( ptTest ) > iDistance )
				continue;

			if ( pt.GetDist( ptTest ) > iDistance )
				continue;

			//if ( ptElem[2].m_z > pStatic->m_z )
			if ( ptElem[2].m_z > ptTest.m_z )
				continue;

			if ( ((( pStatic->m_z - pt.m_z ) > 0) && ( pStatic->m_z - pt.m_z ) > RESOURCE_Z_CHECK ) || ((( pt.m_z - pStatic->m_z ) < 0) && (( pt.m_z - pStatic->m_z ) < - RESOURCE_Z_CHECK )))
				continue;

			if (( ptTest.m_z < ptElem[2].m_z ) || (( ptTest.m_z == ptElem[2].m_z ) && ( fElem[2] )))
				continue;

			ptElem[2] = ptTest;
			fElem[2] = false;

			//DEBUG_ERR(("static pItemDef->IsType( iType %d) %d;pItemDef->GetType() %d;pItemDef->GetID() %d;pItemDef->GetDispID() %d\n",iType,pItemDef->IsType( iType ),pItemDef->GetType(),pItemDef->GetID(),pItemDef->GetDispID()));
			if ( pItemDef->IsType( iType ) )
			{
				//DEBUG_ERR(("found %d; ptTest: %d,%d,%d\n",__LINE__,ptTest.m_x,ptTest.m_y,ptTest.m_z));
				fElem[2] = true;
				//DEBUG_ERR(("ptElem[iRetElem].m_z %d, ptElem[2].m_z %d\n",ptElem[iRetElem].m_z,ptElem[2].m_z));
				//if ( ptElem[iRetElem].m_z > ptElem[2].m_z )
				if ( ptElem[2].m_z > ptElem[iRetElem].m_z )
					iRetElem = 2;
			}
		}
	}

	// Check for appropriate terrain type
	CRectMap rect;
	rect.SetRect( pt.m_x - iDistance, pt.m_y - iDistance,
		pt.m_x + iDistance + 1, pt.m_y + iDistance + 1,
		pt.m_map);

	const CUOMapMeter * pMeter = NULL;
	for ( int x = rect.m_left; x < rect.m_right; ++x, pMeter = NULL )
	{
		for ( int y = rect.m_top; y < rect.m_bottom; ++y, pMeter = NULL )
		{
			ptTest = CPointMap(static_cast<WORD>(x), static_cast<WORD>(y), pt.m_z, pt.m_map);
			pMeter = GetMapMeter(ptTest);
			if ( !pMeter )
				continue;
			if ( pt.GetDist( ptTest ) > iDistance )
				continue;
			if ( ptElem[3].m_z > pMeter->m_z )
				continue;

			//DEBUG_ERR(("(( pMeter->m_z (%d) - pt.m_z (%d) ) > 0) && ( pMeter->m_z (%d) - pt.m_z (%d) ) > RESOURCE_Z_CHECK (%d) >> %d\n",pMeter->m_z,pt.m_z,pMeter->m_z,pt.m_z,RESOURCE_Z_CHECK,(( pMeter->m_z - pt.m_z ) > 0) && ( pMeter->m_z - pt.m_z ) > RESOURCE_Z_CHECK));
			//DEBUG_ERR(("(( pt.m_z (%d) - pMeter->m_z (%d) ) < 0) && (( pt.m_z (%d) - pMeter->m_z (%d) ) < - RESOURCE_Z_CHECK (%d) )) >> %d\n",pt.m_z,pMeter->m_z,pt.m_z,pMeter->m_z,- RESOURCE_Z_CHECK,((( pt.m_z - pMeter->m_z ) < 0) && (( pt.m_z - pMeter->m_z ) < - RESOURCE_Z_CHECK ))));
			if ( ((( pMeter->m_z - pt.m_z ) > 0) && ( pMeter->m_z - pt.m_z ) > RESOURCE_Z_CHECK ) || ((( pt.m_z - pMeter->m_z ) < 0) && (( pt.m_z - pMeter->m_z ) < - RESOURCE_Z_CHECK )))
				continue;

			//DEBUG_ERR(("pMeter->m_z (%d) < ptElem[3].m_z (%d) >> %d\n",pMeter->m_z,ptElem[3].m_z,pMeter->m_z < ptElem[3].m_z));
			if (( pMeter->m_z < ptElem[3].m_z ) || (( pMeter->m_z == ptElem[3].m_z ) && ( fElem[3] )))
				continue;

			ptElem[3] = ptTest;
			fElem[3] = false;

			//DEBUG_ERR(("iType %x, TerrainType %x\n",iType,g_World.GetTerrainItemType( pMeter->m_wTerrainIndex )));
			if ( iType == g_World.GetTerrainItemType( pMeter->m_wTerrainIndex ) )
			{
				fElem[3] = true;
				//if ( ptElem[iRetElem].m_z > ptElem[3].m_z )
				//DEBUG_ERR(("ptElem[3].m_z %d; ptElem[iRetElem].m_z %d\n",ptElem[3].m_z, ptElem[iRetElem].m_z));
				if ( ptElem[3].m_z > ptElem[iRetElem].m_z )
						iRetElem = 3;
				//DEBUG_ERR(("fElem3 %d %d\n",ptElem[3].m_z, fElem[3]));
				continue;
			}

			rect.SetRect( pt.m_x - iDistance, pt.m_y - iDistance, pt.m_x + iDistance + 1, pt.m_y + iDistance + 1, pt.m_map);
		}
	}

	/*CPointMap a;
	a.m_z = maximum(
	// priority dynamic->multi->static->terrain
	int iRetElem;
	if (( ptElem[0].m_z >= ptElem[1].m_z ) && ( fElem[0] ))
		iRetElem = 0;
	else if (( ptElem[1].m_z >= ptElem[2].m_z ) && ( fElem[1] ))
		iRetElem = 1;
	else if (( ptElem[2].m_z >= ptElem[3].m_z ) && ( fElem[2] ))
		iRetElem = 2;
	else if ( fElem[3] )
		iRetElem = 3;
	else
		iRetElem = 4;*/

	ASSERT(iRetElem < COUNTOF(ptElem));
	if ( 0 != iRetElem && ptElem[0].m_z > ptElem[iRetElem].m_z )
			 iRetElem = 4;
	else if ( 1 != iRetElem && ptElem[1].m_z > ptElem[iRetElem].m_z )
		     iRetElem = 4;
	else if ( 2 != iRetElem && ptElem[2].m_z > ptElem[iRetElem].m_z )
		     iRetElem = 4;
	else if ( 3 != iRetElem && ptElem[3].m_z > ptElem[iRetElem].m_z )
		     iRetElem = 4;

	//DEBUG_ERR(("iRetElem %d; %d %d %d %d; %d %d %d ISVALID: %d\n",iRetElem,ptElem[1].m_z,ptElem[2].m_z,ptElem[3].m_z,ptElem[4].m_z,pt.m_x,pt.m_y,pt.m_z,ptElem[iRetElem].IsValidPoint()));
	//DEBUG_ERR(("X: %d  Y: %d  Z: %d\n",ptElem[iRetElem].m_x,ptElem[iRetElem].m_y,ptElem[iRetElem].m_z));
	return ( ptElem[iRetElem] );
#undef RESOURCE_Z_CHECK
}
Пример #3
0
void CWorld::GetFixPoint( const CPointMap & pt, CGrayMapBlockState & block)
{
	//Will get the highest CAN_I_PLATFORM|CAN_I_CLIMB and places it into block.Bottom
	ADDTOCALLSTACK("CWorld::GetFixPoint");
	CItemBase * pItemDef = NULL;
	CItemBaseDupe * pDupeDef = NULL;
	CItem * pItem = NULL;
	DWORD wBlockThis = 0;
	signed char z = 0;
	int x2 = 0, y2 = 0;

	// Height of statics at/above given coordinates
	// do gravity here for the z.
	const CGrayMapBlock * pMapBlock = GetMapBlock( pt );
	if (pMapBlock == NULL)
		return;

	size_t iQty = pMapBlock->m_Statics.GetStaticQty();
	if ( iQty > 0 )  // no static items here.
	{
		x2 = pMapBlock->GetOffsetX(pt.m_x);
		y2 = pMapBlock->GetOffsetY(pt.m_y);
		const CUOStaticItemRec * pStatic = NULL;
		for ( size_t i = 0; i < iQty; ++i, z = 0, pStatic = NULL, pDupeDef = NULL )
		{
			if ( ! pMapBlock->m_Statics.IsStaticPoint( i, x2, y2 ))
				continue;

			pStatic = pMapBlock->m_Statics.GetStatic( i );
			if ( pStatic == NULL )
				continue;

			z = pStatic->m_z;

			pItemDef = CItemBase::FindItemBase( pStatic->GetDispID() );
			if ( pItemDef )
			{
				if (pItemDef->GetID() == pStatic->GetDispID()) //parent item
				{
					wBlockThis = (pItemDef->m_Can & CAN_I_MOVEMASK);
					z += ((wBlockThis & CAN_I_CLIMB) ? pItemDef->GetHeight()/2 : pItemDef->GetHeight());
				}
				else //non-parent item
				{
					pDupeDef = CItemBaseDupe::GetDupeRef(static_cast<ITEMID_TYPE>(pStatic->GetDispID()));
					if ( ! pDupeDef )
					{
						g_Log.EventDebug("Failed to get non-parent reference (static) (DispID 0%x) (X: %d Y: %d Z: %d)\n",pStatic->GetDispID(),pStatic->m_x+pMapBlock->m_x,pStatic->m_y+pMapBlock->m_y,pStatic->m_z);
						wBlockThis = ( pItemDef->m_Can & CAN_I_MOVEMASK );
						z += ((wBlockThis & CAN_I_CLIMB) ? pItemDef->GetHeight()/2 : pItemDef->GetHeight());
					}
					else
					{
						wBlockThis = (pDupeDef->m_Can & CAN_I_MOVEMASK);
						z += ((wBlockThis & CAN_I_CLIMB) ? pDupeDef->GetHeight()/2 : pDupeDef->GetHeight());
					}
				}
			}
			else if ( pStatic->GetDispID() )
				CItemBase::GetItemTiledataFlags(wBlockThis,pStatic->GetDispID());

			if (block.m_Bottom.m_z < z)
			{
				if ((z < pt.m_z+PLAYER_HEIGHT) && (wBlockThis & (CAN_I_PLATFORM|CAN_I_CLIMB|CAN_I_WATER)))
				{
					block.m_Bottom.m_dwBlockFlags = wBlockThis;
					block.m_Bottom.m_dwTile = pStatic->GetDispID() + TERRAIN_QTY;
					block.m_Bottom.m_z = z;
				}
				else if (block.m_Top.m_z > z)
				{
					block.m_Top.m_dwBlockFlags = wBlockThis;
					block.m_Top.m_dwTile = pStatic->GetDispID() + TERRAIN_QTY;
					block.m_Top.m_z = z;
				}
			}
		}
	}

	pItemDef = NULL;
	pDupeDef = NULL;
	pItem = NULL;
	wBlockThis = 0;
	z = 0;
	x2 = y2 = 0;
	iQty = 0;

	// Any multi items here ?
	// Check all of them
	CRegionLinks rlinks;
	size_t iRegionQty = pt.GetRegions( REGION_TYPE_MULTI, rlinks );
	if ( iRegionQty > 0 )
	{
		//  ------------ For variables --------------------
		CRegionBase * pRegion = NULL;
		const CGrayMulti * pMulti = NULL;
		const CUOMultiItemRec2 * pMultiItem = NULL;
		x2 = 0;
		y2 = 0;
		//  ------------ For variables --------------------

		for ( size_t iRegion = 0; iRegion < iRegionQty; ++iRegion, pRegion = NULL, pItem = NULL, pMulti = NULL, x2 = 0, y2 = 0 )
		{
			pRegion = rlinks.GetAt(iRegion);
			if ( pRegion != NULL )
				pItem = pRegion->GetResourceID().ItemFind();

			if ( pItem != NULL )
			{
				pMulti = g_Cfg.GetMultiItemDefs(pItem);
				if ( pMulti )
				{
					x2 = pt.m_x - pItem->GetTopPoint().m_x;
					y2 = pt.m_y - pItem->GetTopPoint().m_y;
					iQty = pMulti->GetItemCount();
					for ( size_t ii = 0; ii < iQty; ++ii, pMultiItem = NULL, z = 0 )
					{
						pMultiItem = pMulti->GetItem(ii);

						if ( !pMultiItem )
							break;

						if ( ! pMultiItem->m_visible )
							continue;

						if ( pMultiItem->m_dx != x2 || pMultiItem->m_dy != y2 )
							continue;

						z = static_cast<signed char>(pItem->GetTopZ() + pMultiItem->m_dz);

						pItemDef = CItemBase::FindItemBase( pMultiItem->GetDispID() );
						if ( pItemDef != NULL )
						{
							if ( pItemDef->GetID() == pMultiItem->GetDispID() ) //parent item
							{
								wBlockThis = ( pItemDef->m_Can & CAN_I_MOVEMASK );
								z += ((wBlockThis & CAN_I_CLIMB) ? pItemDef->GetHeight()/2 : pItemDef->GetHeight());
							}
							else //non-parent item
							{
								pDupeDef = CItemBaseDupe::GetDupeRef(static_cast<ITEMID_TYPE>(pMultiItem->GetDispID()));
								if ( pDupeDef == NULL )
								{
									g_Log.EventDebug("Failed to get non-parent reference (multi) (DispID 0%x) (X: %d Y: %d Z: %d)\n",pMultiItem->GetDispID(),pMultiItem->m_dx+pItem->GetTopPoint().m_x,pMultiItem->m_dy+pItem->GetTopPoint().m_y,pMultiItem->m_dz+pItem->GetTopPoint().m_z);
									wBlockThis = ( pItemDef->m_Can & CAN_I_MOVEMASK );
									z += ((wBlockThis & CAN_I_CLIMB) ? pItemDef->GetHeight()/2 : pItemDef->GetHeight());
								}
								else
								{
									wBlockThis = ( pDupeDef->m_Can & CAN_I_MOVEMASK );
									z += ((wBlockThis & CAN_I_CLIMB) ? pDupeDef->GetHeight()/2 : pDupeDef->GetHeight());
								}
							}
						}
						else if ( pMultiItem->GetDispID() )
							CItemBase::GetItemTiledataFlags(wBlockThis,pMultiItem->GetDispID());

						if (block.m_Bottom.m_z < z)
						{
							if ((z < pt.m_z+PLAYER_HEIGHT) && (wBlockThis & (CAN_I_PLATFORM|CAN_I_CLIMB|CAN_I_WATER)))
							{
								block.m_Bottom.m_dwBlockFlags = wBlockThis;
								block.m_Bottom.m_dwTile = pMultiItem->GetDispID() + TERRAIN_QTY;
								block.m_Bottom.m_z = z;
							}
							else if (block.m_Top.m_z > z)
							{
								block.m_Top.m_dwBlockFlags = wBlockThis;
								block.m_Top.m_dwTile = pMultiItem->GetDispID() + TERRAIN_QTY;
								block.m_Top.m_z = z;
							}
						}
					}
				}
			}
		}
	}

	pItemDef = NULL;
	pDupeDef = NULL;
	pItem = NULL;
	wBlockThis = 0;
	x2 = y2 = iQty = 0;
	z = 0;

	// Any dynamic items here ?
	// NOTE: This could just be an item that an NPC could just move ?
	CWorldSearch Area( pt );

	for (;;)
	{
		pItem = Area.GetItem();
		if ( !pItem )
			break;

		z = pItem->GetTopZ();

		// Invis items should not block ???
		pItemDef = CItemBase::FindItemBase( pItem->GetDispID() );

		if ( pItemDef )
		{
			if ( pItemDef->GetDispID() == pItem->GetDispID() )//parent item
			{
				wBlockThis = ( pItemDef->m_Can & CAN_I_MOVEMASK );
				z += ((wBlockThis & CAN_I_CLIMB) ? pItemDef->GetHeight()/2 : pItemDef->GetHeight());
			}
			else //non-parent item
			{
				pDupeDef = CItemBaseDupe::GetDupeRef(static_cast<ITEMID_TYPE>(pItem->GetDispID()));
				if ( ! pDupeDef )
				{
					g_Log.EventDebug("Failed to get non-parent reference (dynamic) (DispID 0%x) (X: %d Y: %d Z: %d)\n",pItem->GetDispID(),pItem->GetTopPoint().m_x,pItem->GetTopPoint().m_y,pItem->GetTopPoint().m_z);
					wBlockThis = ( pItemDef->m_Can & CAN_I_MOVEMASK );
					z += ((wBlockThis & CAN_I_CLIMB) ? pItemDef->GetHeight()/2 : pItemDef->GetHeight());
				}
				else
				{
					wBlockThis = ( pDupeDef->m_Can & CAN_I_MOVEMASK );
					z += ((wBlockThis & CAN_I_CLIMB) ? pDupeDef->GetHeight()/2 : pDupeDef->GetHeight());
				}
			}

			if ( block.m_Bottom.m_z < z )
			{
				if ( (z < pt.m_z + PLAYER_HEIGHT) && (wBlockThis & (CAN_I_PLATFORM|CAN_I_CLIMB|CAN_I_WATER)) )
				{
					block.m_Bottom.m_dwBlockFlags = wBlockThis;
					block.m_Bottom.m_dwTile = pItemDef->GetDispID() + TERRAIN_QTY;
					block.m_Bottom.m_z = z;
				}
				else if ( block.m_Top.m_z > z )
				{
					block.m_Top.m_dwBlockFlags = wBlockThis;
					block.m_Top.m_dwTile = pItemDef->GetDispID() + TERRAIN_QTY;
					block.m_Top.m_z = z;
				}
			}
		}
		else if (pItem->GetDispID())
			CItemBase::GetItemTiledataFlags(wBlockThis,pItem->GetDispID());
	}

	wBlockThis = 0;
	// Terrain height is screwed. Since it is related to all the terrain around it.
	const CUOMapMeter * pMeter = pMapBlock->GetTerrain( UO_BLOCK_OFFSET(pt.m_x), UO_BLOCK_OFFSET(pt.m_y));
	if ( ! pMeter )
		return;

	if ( pMeter->m_wTerrainIndex == TERRAIN_HOLE )
	{
		wBlockThis = 0;
	}
	else if ( CUOMapMeter::IsTerrainNull( pMeter->m_wTerrainIndex ) )	// inter dungeon type.
	{
		wBlockThis = CAN_I_BLOCK;
	}
	else
	{
		CGrayTerrainInfo land( pMeter->m_wTerrainIndex );
		//DEBUG_ERR(("Terrain flags - land.m_flags 0%x wBlockThis (0%x)\n",land.m_flags,wBlockThis));
		if ( land.m_flags & UFLAG1_WATER )
			wBlockThis |= CAN_I_WATER;
		if ( land.m_flags & UFLAG1_DAMAGE )
			wBlockThis |= CAN_I_FIRE;
		if ( land.m_flags & UFLAG1_BLOCK )
			wBlockThis |= CAN_I_BLOCK;
		if (( ! wBlockThis ) || ( land.m_flags & UFLAG2_PLATFORM )) // Platform items should take precendence over non-platforms.
			wBlockThis = CAN_I_PLATFORM;
	}

	if (block.m_Bottom.m_z < pMeter->m_z)
	{
		if (((pMeter->m_z < pt.m_z+PLAYER_HEIGHT) && (wBlockThis & (CAN_I_PLATFORM|CAN_I_CLIMB|CAN_I_WATER))) || (block.m_Bottom.m_z == UO_SIZE_MIN_Z))
		{
			block.m_Bottom.m_dwBlockFlags = wBlockThis;
			block.m_Bottom.m_dwTile = pMeter->m_wTerrainIndex;
			block.m_Bottom.m_z = pMeter->m_z;
		}
		else if (block.m_Top.m_z > pMeter->m_z)
		{
			block.m_Top.m_dwBlockFlags = wBlockThis;
			block.m_Top.m_dwTile = pMeter->m_wTerrainIndex;
			block.m_Top.m_z = pMeter->m_z;
		}
	}

	if ( block.m_Bottom.m_z == UO_SIZE_MIN_Z )
	{
		//Fail safe...  Reset to 0z with no top block;
		block.m_Bottom.m_dwBlockFlags = 0;
		block.m_Bottom.m_dwTile = 0;
		block.m_Bottom.m_z = 0;

		block.m_Top.m_dwBlockFlags = 0;
		block.m_Top.m_dwTile = 0;
		block.m_Top.m_z = UO_SIZE_Z;
	}
}
Пример #4
0
bool CChar::CanSeeLOS_New( const CPointMap &ptDst, CPointMap *pptBlock, int iMaxDist, word flags, bool bCombatCheck ) const
{
	ADDTOCALLSTACK("CChar::CanSeeLOS_New");
	// WARNING: CanSeeLOS is an expensive function (lot of calculations but	most importantly it has to read the UO files, and file I/O is slow).

	if ( !bCombatCheck && IsPriv(PRIV_GM) )	// If i'm checking the LOS during a combat, i don't want to shoot through the walls even if i'm a GM
	{
		WARNLOS(("GM Pass\n"));
		return true;
	}

	CPointMap ptSrc = GetTopPoint();
	CPointMap ptNow(ptSrc);

	if ( ptSrc.m_map != ptDst.m_map )	// Different map
		return this->CanSeeLOS_New_Failed(pptBlock, ptNow);

	if ( ptSrc == ptDst )	// Same point ^^
		return true;

	short iTotalZ = ptSrc.m_z + GetHeightMount(true);
	ptSrc.m_z = (char)minimum(iTotalZ, UO_SIZE_Z);	//true - substract one from the height because of eyes height
	WARNLOS(("Total Z: %d\n", ptSrc.m_z));

	int dx, dy, dz;
	dx = ptDst.m_x - ptSrc.m_x;
	dy = ptDst.m_y - ptSrc.m_y;
	dz = ptDst.m_z - ptSrc.m_z;

    float dist2d, dist3d;
	dist2d = sqrt((float)(dx*dx + dy*dy));
	if ( dz )
		dist3d = sqrt((float)(dist2d*dist2d + dz*dz));
	else
		dist3d = dist2d;

	if ( APPROX(dist2d) > (float)iMaxDist )
	{
		WARNLOS(("( APPROX(dist2d)(%f) > ((double)iMaxDist)(%f) ) --> NOLOS\n", APPROX(dist2d), (float)iMaxDist));
		return CanSeeLOS_New_Failed(pptBlock, ptNow);
	}

	float dFactorX, dFactorY, dFactorZ;
	dFactorX = dx / dist3d;
	dFactorY = dy / dist3d;
	dFactorZ = dz / dist3d;

    float nPx, nPy, nPz;
	nPx = ptSrc.m_x;
	nPy = ptSrc.m_y;
	nPz = ptSrc.m_z;

	std::vector<CPointMap> path;
	for (;;)
	{
		if ( BETWEENPOINT(nPx, ptDst.m_x, ptSrc.m_x) && BETWEENPOINT(nPy, ptDst.m_y, ptSrc.m_y) && BETWEENPOINT(nPz, ptDst.m_z, ptSrc.m_z) )
		{
			dx = (int)APPROX(nPx);
			dy = (int)APPROX(nPy);
			dz = (int)APPROX(nPz);

			// Add point to vector
			if ( !path.empty() )
			{
				CPointMap ptEnd = path[path.size() - 1];
				if ( ptEnd.m_x != dx || ptEnd.m_y != dy || ptEnd.m_z != dz )
					path.emplace_back((word)dx, (word)dy, (char)dz, ptSrc.m_map);
			}
			else
			{
				path.emplace_back((word)dx, (word)dy, (char)dz, ptSrc.m_map);
			}
			WARNLOS(("PATH X:%d Y:%d Z:%d\n", dx, dy, dz));

			nPx += dFactorX;
			nPy += dFactorY;
			nPz += dFactorZ;
		}
		else
			break;
	}

	if ( !path.empty() )
	{
		if ( path[path.size() - 1] != ptDst )
			path.emplace_back(ptDst.m_x, ptDst.m_y, ptDst.m_z, ptDst.m_map);
	}
	else
	{
		path.clear();
		return CanSeeLOS_New_Failed(pptBlock, ptNow);
	}

	WARNLOS(("Path calculated %" PRIuSIZE_T "\n", path.size()));
	// Ok now we should loop through all the points and checking for maptile, staticx, items, multis.
	// If something is in the way and it has the wrong flags LOS return false

	const CServerMapBlock *pBlock			= nullptr;		// Block of the map (for statics)
	const CUOStaticItemRec *pStatic			= nullptr;		// Statics iterator (based on SphereMapBlock)
	const CSphereMulti *pMulti 				= nullptr;		// Multi Def (multi check)
	const CUOMultiItemRec_HS *pMultiItem	= nullptr;		// Multi item iterator
	CRegion *pRegion					= nullptr;		// Nulti regions
	CRegionLinks rlinks;								// Links to multi regions
	CItem *pItem						= nullptr;
	CItemBase *pItemDef 				= nullptr;
	CItemBaseDupe *pDupeDef				= nullptr;

	dword wTFlags = 0;
	height_t Height = 0;
	word terrainid = 0;
	bool bPath = true;
	bool bNullTerrain = false;

	CRegion *pSrcRegion = ptSrc.GetRegion(REGION_TYPE_AREA|REGION_TYPE_ROOM|REGION_TYPE_MULTI);
	CRegion *pNowRegion = nullptr;

	int lp_x = 0, lp_y = 0;
	short min_z = 0, max_z = 0;

	for (uint i = 0, pathSize = uint(path.size()); i < pathSize; lp_x = ptNow.m_x, lp_y = ptNow.m_y, pItemDef = nullptr, pStatic = nullptr, pMulti = nullptr, pMultiItem = nullptr, min_z = 0, max_z = 0, ++i )
	{
		ptNow = path[i];
		WARNLOS(("---------------------------------------------\n"));
		WARNLOS(("Point %d,%d,%d \n", ptNow.m_x, ptNow.m_y, ptNow.m_z));

		pNowRegion = ptNow.GetRegion(REGION_TYPE_AREA|REGION_TYPE_ROOM|REGION_TYPE_MULTI);

		if ( (flags & LOS_NO_OTHER_REGION) && (pSrcRegion != pNowRegion) )
		{
			WARNLOS(("flags & 0200 and path is leaving my region - BLOCK\n"));
			bPath = false;
			break;
		}

		if ( (flags & LOS_NC_MULTI) && ptNow.GetRegion(REGION_TYPE_MULTI) && (ptNow.GetRegion(REGION_TYPE_MULTI) != ptSrc.GetRegion(REGION_TYPE_MULTI)) )
		{
			WARNLOS(("flags & 0400 and path is crossing another multi - BLOCK\n"));
			bPath = false;
			break;
		}

		if ( (lp_x != ptNow.m_x) || (lp_y != ptNow.m_y) )
		{
			WARNLOS(("\tLoading new map block.\n"));
			pBlock = g_World.GetMapBlock(ptNow);
		}

		if ( !pBlock ) // something is wrong
		{
			WARNLOS(("GetMapBlock Failed\n"));
			bPath = false;
			break;
		}

		if ( !(flags & LOS_NB_TERRAIN) )
		{
			if ( !((flags & LOS_NB_LOCAL_TERRAIN) && (pSrcRegion == pNowRegion)) )
			{
				// ------ MapX.mul Check ----------
				terrainid = pBlock->GetTerrain(UO_BLOCK_OFFSET(ptNow.m_x), UO_BLOCK_OFFSET(ptNow.m_y))->m_wTerrainIndex;
				WARNLOS(("Terrain %d\n", terrainid));

				if ( (flags & LOS_FISHING) && (ptSrc.GetDist(ptNow) >= 2) && (g_World.GetTerrainItemType(terrainid) != IT_WATER) && (g_World.GetTerrainItemType(terrainid) != IT_NORMAL) )
				{
					WARNLOS(("Terrain %d blocked - flags & LOS_FISHING, distance >= 2 and type of pItemDef is not IT_WATER\n", terrainid));
					WARNLOS(("ptSrc: %d,%d,%d; ptNow: %d,%d,%d; terrainid: %d; terrainid type: %d\n", ptSrc.m_x, ptSrc.m_y, ptSrc.m_z, ptNow.m_x, ptNow.m_y, ptNow.m_z, terrainid, g_World.GetTerrainItemType(terrainid)));
					bPath = false;
					break;
				}

				//#define MAPTILEMIN minimum(minimum(minimum(pBlock->GetTerrain(0,0)->m_z, pBlock->GetTerrain(0,1)->m_z), pBlock->GetTerrain(1,0)->m_z), pBlock->GetTerrain(1,1)->m_z)
				//#define MAPTILEMAX maximum(maximum(maximum(pBlock->GetTerrain(0,0)->m_z, pBlock->GetTerrain(0,1)->m_z), pBlock->GetTerrain(1,0)->m_z), pBlock->GetTerrain(1,1)->m_z);
				//#define MAPTILEZ pBlock->GetTerrain(UO_BLOCK_OFFSET(ptNow.m_x), UO_BLOCK_OFFSET(ptNow.m_y))->m_z;

				if ( (terrainid != TERRAIN_HOLE) && (terrainid != 475) )
				{
					if ( terrainid < 430 || terrainid > 437 )
					{
						/*this stuff should do some checking for surrounding items:
						aaa
						aXa
						aaa
						min_z is determined as a minimum of all a/X terrain, where X is ptNow
						*/
						byte pos_x = UO_BLOCK_OFFSET(ptNow.m_x) > 1 ? UO_BLOCK_OFFSET(ptNow.m_x - 1) : 0;
						byte pos_y = UO_BLOCK_OFFSET(ptNow.m_y) > 1 ? UO_BLOCK_OFFSET(ptNow.m_y - 1) : 0;
						const byte defx = UO_BLOCK_OFFSET(ptNow.m_x);
						const byte defy = UO_BLOCK_OFFSET(ptNow.m_y);
						min_z = pBlock->GetTerrain(pos_x, pos_y)->m_z;
						max_z = pBlock->GetTerrain(defx, defy)->m_z;
						for ( byte posy = pos_y; (abs(defx - UO_BLOCK_OFFSET(pos_x)) <= 1 && pos_x <= 7); ++pos_x )
						{
							for ( pos_y = posy; (abs(defy - UO_BLOCK_OFFSET(pos_y)) <= 1 && pos_y <= 7); ++pos_y )
							{
								char terrain_z = pBlock->GetTerrain(pos_x, pos_y)->m_z;
								min_z = minimum(min_z, terrain_z);
							}
						}
						//min_z = MAPTILEZ;
						//max_z = MAPTILEZ;
						WARNLOS(("Terrain %d - m:%d M:%d\n", terrainid, min_z, max_z));
						if ( CUOMapMeter::IsTerrainNull(terrainid) )
							bNullTerrain = true; //what if there are some items on that hole?
						if ( (min_z <= ptNow.m_z && max_z >= ptNow.m_z) && (ptNow.m_x != ptDst.m_x || ptNow.m_y != ptDst.m_y || min_z > ptDst.m_z || max_z < ptDst.m_z) )
						{
							WARNLOS(("Terrain %d - m:%d M:%d - block\n", terrainid, min_z, max_z));
							bPath = false;
							break;
						}
						CUOTerrainInfo land(terrainid);
						if ( (land.m_flags & UFLAG1_WATER) && (flags & LOS_NC_WATER) )
							bNullTerrain = true;
					}
				}
				//#undef MAPTILEMIN
				//#undef MAPTILEMAX
				//#undef MAPTILEZ
			}
		}

		// ------ StaticsX.mul Check --------
		if ( !(flags & LOS_NB_STATIC) )
		{
			if ( !((flags & LOS_NB_LOCAL_STATIC) && (pSrcRegion == pNowRegion)) )
			{
                uint uiStaticMaxQty = pBlock->m_Statics.GetStaticQty();
				for ( uint s = 0; s < uiStaticMaxQty; pStatic = nullptr, pItemDef = nullptr, ++s )
				{
					pStatic = pBlock->m_Statics.GetStatic(s);
					if ( (pStatic->m_x + pBlock->m_x != ptNow.m_x) || (pStatic->m_y + pBlock->m_y != ptNow.m_y) )
						continue;

					//Fix for Stacked items blocking view
					if ( (pStatic->m_x == ptDst.m_x) && (pStatic->m_y == ptDst.m_y) && (pStatic->m_z >= GetTopZ()) && (pStatic->m_z <= ptSrc.m_z) )
						continue;

					pItemDef = CItemBase::FindItemBase(pStatic->GetDispID());
					wTFlags = 0;
					Height = 0;
					bNullTerrain = false;

					if ( !pItemDef )
					{
						WARNLOS(("STATIC - Cannot get pItemDef for item (0%x)\n", pStatic->GetDispID()));
					}
					else
					{
                        if (pItemDef->Can(CAN_I_BLOCKLOS))
                        {
                            WARNLOS(("pStatic blocked by CAN_I_BLOCKLOS"));
                            bPath = false;
                            break;
                        }

						if ( (flags & LOS_FISHING) && (ptSrc.GetDist(ptNow) >= 2) && (pItemDef->GetType() != IT_WATER) &&
							( pItemDef->Can(CAN_I_DOOR | CAN_I_PLATFORM | CAN_I_BLOCK | CAN_I_CLIMB | CAN_I_FIRE | CAN_I_ROOF | CAN_I_BLOCKLOS | CAN_I_BLOCKLOS_HEIGHT)) )
						{
							WARNLOS(("pStatic blocked - flags & 0800, distance >= 2 and type of pItemDef is not IT_WATER\n"));
							bPath = false;
							break;
						}

						wTFlags = pItemDef->GetTFlags();
						Height = pItemDef->GetHeight();

						if ( pItemDef->GetID() != pStatic->GetDispID() ) //not a parent item
						{
							WARNLOS(("Not a parent item (STATIC)\n"));
							pDupeDef = CItemBaseDupe::GetDupeRef((ITEMID_TYPE)(pStatic->GetDispID()));
							if ( !pDupeDef )
							{
								g_Log.EventDebug("AdvancedLoS: Failed to get non-parent reference (static) (DispID 0%x) (X: %d Y: %d Z: %hhd M: %hhu)\n", pStatic->GetDispID(), ptNow.m_x, ptNow.m_y, pStatic->m_z, ptNow.m_map);
							}
							else
							{
								wTFlags = pDupeDef->GetTFlags();
								Height = pDupeDef->GetHeight();
							}
						}
						else
						{
							WARNLOS(("Parent item (STATIC)\n"));
						}

						Height = (wTFlags & UFLAG2_CLIMBABLE) ? Height / 2 : Height;

						if ( ((wTFlags & (UFLAG1_WALL|UFLAG1_BLOCK|UFLAG2_PLATFORM)) || (pItemDef->Can(CAN_I_BLOCKLOS_HEIGHT))) && !((wTFlags & UFLAG2_WINDOW) && (flags & LOS_NB_WINDOWS)) )
						{
							WARNLOS(("pStatic %0x %d,%d,%d - %d\n", pStatic->GetDispID(), pStatic->m_x, pStatic->m_y, pStatic->m_z, Height));
							min_z = pStatic->m_z;
							max_z = minimum(Height + min_z, UO_SIZE_Z);
							WARNLOS(("wTFlags(0%x)\n", wTFlags));

							WARNLOS(("pStatic %0x Z check: %d,%d (Now: %d) (Dest: %d).\n", pStatic->GetDispID(), min_z, max_z, ptNow.m_z, ptDst.m_z));
							if ( (min_z <= ptNow.m_z) && (max_z >= ptNow.m_z) )
							{
								if ( ptNow.m_x != ptDst.m_x || ptNow.m_y != ptDst.m_y || min_z > ptDst.m_z || max_z < ptDst.m_z )
								{
									WARNLOS(("pStatic blocked - m:%d M:%d\n", min_z, max_z));
									bPath = false;
									break;
								}
							}
						}
					}
				}
			}
		}

		if ( !bPath )
			break;

		// --------- In game items ----------
		if ( !(flags & LOS_NB_DYNAMIC) )
		{
			if ( !((flags & LOS_NB_LOCAL_DYNAMIC) && (pSrcRegion == pNowRegion)) )
			{
				CWorldSearch AreaItems(ptNow, 0);
				for (;;)
				{
					pItem = AreaItems.GetItem();
					if ( !pItem )
						break;
					if ( pItem->GetUnkPoint().m_x != ptNow.m_x || pItem->GetUnkPoint().m_y != ptNow.m_y )
						continue;
					if ( !CanSeeItem(pItem) )
						continue;

					//Fix for Stacked items blocking view
					if ( (pItem->GetUnkPoint().m_x == ptDst.m_x) && (pItem->GetUnkPoint().m_y == ptDst.m_y) && (pItem->GetUnkPoint().m_z >= GetTopZ()) && (pItem->GetUnkPoint().m_z <= ptSrc.m_z) )
						continue;

					pItemDef = static_cast<CItemBase*>(pItem->Base_GetDef());
					wTFlags = 0;
					Height = 0;
					bNullTerrain = false;

					if ( !pItemDef )
					{
						WARNLOS(("DYNAMIC - Cannot get pItemDef for item (0%x)\n", pItem->GetDispID()));
					}
					else
					{
                        if (pItem->Can(CAN_I_BLOCKLOS))
                        {
                            WARNLOS(("pItem blocked by CAN_I_BLOCKLOS"));
                            bPath = false;
                            break;
                        }

						if ( (flags & LOS_FISHING) && (ptSrc.GetDist(ptNow) >= 2) && (pItem->GetType() != IT_WATER) &&
							( pItem->Can(CAN_I_DOOR | CAN_I_PLATFORM | CAN_I_BLOCK | CAN_I_CLIMB | CAN_I_FIRE | CAN_I_ROOF | CAN_I_BLOCKLOS | CAN_I_BLOCKLOS_HEIGHT) ) )
						{
							WARNLOS(("pItem blocked - flags & 0800, distance >= 2 and type of pItemDef is not IT_WATER\n"));
							bPath = false;
							break;
							//return CanSeeLOS_New_Failed(pptBlock, ptNow);
						}

						wTFlags = pItemDef->GetTFlags();
						Height = pItemDef->GetHeight();

						if ( pItemDef->GetID() != pItem->GetDispID() )	//not a parent item
						{
							WARNLOS(("Not a parent item (DYNAMIC)\n"));
							pDupeDef = CItemBaseDupe::GetDupeRef((ITEMID_TYPE)(pItem->GetDispID()));
							if ( !pDupeDef )
							{
                                // Not an error: i have changed the DISPID of the item.
                                CItemBase* pParentDef = CItemBase::FindItemBase(pItem->GetDispID());
                                if (pParentDef)
                                {
                                    wTFlags = pParentDef->GetTFlags();
                                    Height = pParentDef->GetHeight();
                                }
                                else
                                    g_Log.EventDebug("AdvancedLoS: Failed to get reference (dynamic): non-dupe, baseless dispid (DispID 0%x) (X: %d Y: %d Z: %hhd M: %hhu)\n", pItem->GetDispID(), ptNow.m_x, ptNow.m_y, pItem->GetUnkZ(), ptNow.m_map);
							}
							else
							{
                                // It's a dupe item
								wTFlags = pDupeDef->GetTFlags();
								Height = pDupeDef->GetHeight();
							}
						}
						else
						{
							WARNLOS(("Parent item (DYNAMIC)\n"));
						}

						Height = (wTFlags & UFLAG2_CLIMBABLE) ? Height / 2 : Height;

						if ( ((wTFlags & (UFLAG1_WALL|UFLAG1_BLOCK|UFLAG2_PLATFORM)) || pItem->Can(CAN_I_BLOCKLOS_HEIGHT)) && !((wTFlags & UFLAG2_WINDOW) && (flags & LOS_NB_WINDOWS)) )
						{
							WARNLOS(("pItem %0x(%0x) %d,%d,%d - %d\n", (dword)pItem->GetUID(), pItem->GetDispID(), pItem->GetUnkPoint().m_x, pItem->GetUnkPoint().m_y, pItem->GetUnkPoint().m_z, Height));
							min_z = pItem->GetUnkPoint().m_z;
							max_z = minimum(Height + min_z, UO_SIZE_Z);
							WARNLOS(("wTFlags(0%x)\n", wTFlags));

							WARNLOS(("pItem %0x(%0x) Z check: %d,%d (Now: %d) (Dest: %d).\n", (dword)pItem->GetUID(), pItem->GetDispID(), min_z, max_z, ptNow.m_z, ptDst.m_z));
							if ( min_z <= ptNow.m_z && max_z >= ptNow.m_z )
							{
								if ( ptNow.m_x != ptDst.m_x || ptNow.m_y != ptDst.m_y || min_z > ptDst.m_z || max_z < ptDst.m_z )
								{
									WARNLOS(("pItem blocked - m:%d M:%d\n", min_z, max_z));
									bPath = false;
									break;
								}
							}
						}
					}
				}
			}
		}

		if ( !bPath )
			break;

		// ----------- Multis ---------------

		if ( !(flags & LOS_NB_MULTI) )
		{
			if ( !((flags & LOS_NB_LOCAL_MULTI) && (pSrcRegion == pNowRegion)) )
			{
				size_t iQtyr = ptNow.GetRegions(REGION_TYPE_MULTI, &rlinks);
				if ( iQtyr > 0 )
				{
					for ( size_t ii = 0; ii < iQtyr; pMulti = nullptr, ++ii, pItem = nullptr, pRegion = nullptr )
					{
						pRegion = rlinks[ii];
						if ( pRegion )
							pItem = pRegion->GetResourceID().ItemFindFromResource();

						if ( !pItem )
							continue;

						pMulti = g_Cfg.GetMultiItemDefs(pItem);
						if ( !pMulti )
							continue;

						uint iQty = pMulti->GetItemCount();
						for ( uint iii = 0; iii < iQty; pItemDef = nullptr, pMultiItem = nullptr, ++iii )
						{
							pMultiItem = pMulti->GetItem(iii);
							if ( !pMultiItem )
								break;
							if ( !pMultiItem->m_visible )
								continue;
							if ( (pMultiItem->m_dx + pItem->GetTopPoint().m_x != ptNow.m_x) || (pMultiItem->m_dy + pItem->GetTopPoint().m_y != ptNow.m_y) )
								continue;

							pItemDef = CItemBase::FindItemBase(pMultiItem->GetDispID());
							wTFlags = 0;
							Height = 0;
							bNullTerrain = false;

							if ( !pItemDef )
							{
								WARNLOS(("MULTI - Cannot get pItemDef for item (0%x)\n", pMultiItem->GetDispID()));
							}
							else
							{
                                if (pItemDef->Can(CAN_I_BLOCKLOS))
                                {
                                    WARNLOS(("pMultiItem blocked by CAN_I_BLOCKLOS"));
                                    bPath = false;
                                    break;
                                }

								if ( (flags & LOS_FISHING) && (ptSrc.GetDist(ptNow) >= 2) && (pItemDef->GetType() != IT_WATER) &&
									( pItemDef->Can(CAN_I_DOOR | CAN_I_PLATFORM | CAN_I_BLOCK | CAN_I_CLIMB | CAN_I_FIRE | CAN_I_ROOF | CAN_I_BLOCKLOS | CAN_I_BLOCKLOS_HEIGHT) ) )
								{
									WARNLOS(("pMultiItem blocked - flags & 0800, distance >= 2 and type of pItemDef is not IT_WATER\n"));
									bPath = false;
									break;
									//return CanSeeLOS_New_Failed(pptBlock, ptNow);
								}

								wTFlags = pItemDef->GetTFlags();
								Height = pItemDef->GetHeight();

								if ( pItemDef->GetID() != pMultiItem->GetDispID() ) //not a parent item
								{
									WARNLOS(("Not a parent item (MULTI)\n"));
									pDupeDef = CItemBaseDupe::GetDupeRef((ITEMID_TYPE)(pMultiItem->GetDispID()));
									if ( !pDupeDef )
									{
										g_Log.EventDebug("AdvancedLoS: Failed to get non-parent reference (multi) (DispID 0%x) (X: %d Y: %d Z: %hhd M: %hhu)\n", pMultiItem->GetDispID(), ptNow.m_x, ptNow.m_y, pMultiItem->m_dz + pItem->GetTopPoint().m_z, ptNow.m_map);
									}
									else
									{
										wTFlags = pDupeDef->GetTFlags();
										Height = pDupeDef->GetHeight();
									}
								}
								else
								{
									WARNLOS(("Parent item (MULTI)\n"));
								}

								Height = (wTFlags & UFLAG2_CLIMBABLE) ? Height / 2 : Height;

								if ( ((wTFlags & (UFLAG1_WALL|UFLAG1_BLOCK|UFLAG2_PLATFORM) || pItemDef->Can(CAN_I_BLOCKLOS_HEIGHT))) && !((wTFlags & UFLAG2_WINDOW) && (flags & LOS_NB_WINDOWS)) )
								{
									WARNLOS(("pMultiItem %0x %d,%d,%d - %d\n", pMultiItem->GetDispID(), pMultiItem->m_dx, pMultiItem->m_dy, pMultiItem->m_dz, Height));
									min_z = (char)(pMultiItem->m_dz) + pItem->GetTopPoint().m_z;
									max_z = minimum(Height + min_z, UO_SIZE_Z);
									WARNLOS(("wTFlags(0%x)\n", wTFlags));

									if ( min_z <= ptNow.m_z && max_z >= ptNow.m_z )
									{
										if ( ptNow.m_x != ptDst.m_x || ptNow.m_y != ptDst.m_y || min_z > ptDst.m_z || max_z < ptDst.m_z )
										{
											WARNLOS(("pMultiItem blocked - m:%d M:%d\n", min_z, max_z));
											bPath = false;
											break;
										}
									}
								}
							}
						}

						if ( !bPath )
							break;
					}
				}
			}
		}

		if ( bNullTerrain )
			bPath = false;

		if ( !bPath )
			break;
	}

	path.clear();

	if ( !bPath )
		return CanSeeLOS_New_Failed(pptBlock, ptNow);

	return true;
}