void EditorView::restoreState ( ) { QString guiKeyPrefix ( "user/sw/kdbe/gui/" ); char buf[300]; kdbGetValueByParent ( guiKeyPrefix, "width", buf, 300 ); int vwidth = atoi ( buf ); kdbGetValueByParent ( guiKeyPrefix, "height", buf, 300 ); int vheight = atoi ( buf ); kdbGetValueByParent ( guiKeyPrefix, "x", buf, 300 ); int vx = atoi ( buf ); kdbGetValueByParent ( guiKeyPrefix, "y", buf, 300 ); int vy = atoi ( buf ); QValueList<int> splittersizes; kdbGetValueByParent ( guiKeyPrefix + "splitter/", "left", buf, 300 ); int left = atoi ( buf ); kdbGetValueByParent ( guiKeyPrefix + "splitter/", "right", buf, 300 ); int right = atoi ( buf ); if ( left != 0 && right != 0 ) { splittersizes.push_back ( left ); splittersizes.push_back ( right ); splitter->setSizes ( splittersizes ); } if ( vx != 0 && vy != 0 ) move ( vx, vy ); if ( vwidth != 0 && vheight != 0 ) resize ( vwidth, vheight ); openedKeys.clear ( ); KeySet *opened = ksNew ( ); kdbGetChildKeys ( guiKeyPrefix + "openedKeys", opened, KDB_O_RECURSIVE ); for ( size_t i = 0; i < ksGetSize ( opened ); i++) { kdbGetValueByParent ( guiKeyPrefix + "openedKeys", QString ( ).setNum ( i ), buf, 300 ); //cout << "pushing back " << buf << endl; openedKeys.push_back ( buf ); } ksDel ( opened ); }
//BEGIN internal SLOTS void ThumbnailList::slotRequestVisiblePixmaps( int /*newContentsX*/, int newContentsY ) { // if an update is already scheduled or the widget is hidden, don't proceed if ( (m_delayTimer && m_delayTimer->isActive()) || !isShown() ) return; int vHeight = visibleHeight(), vOffset = newContentsY == -1 ? contentsY() : newContentsY; // scroll from the top to the last visible thumbnail m_visibleThumbnails.clear(); QValueList< PixmapRequest * > requestedPixmaps; QValueVector<ThumbnailWidget *>::iterator tIt = m_thumbnails.begin(), tEnd = m_thumbnails.end(); for ( ; tIt != tEnd; ++tIt ) { ThumbnailWidget * t = *tIt; int top = childY( t ) - vOffset; if ( top > vHeight ) break; if ( top + t->height() < 0 ) continue; // add ThumbnailWidget to visible list m_visibleThumbnails.push_back( t ); // if pixmap not present add it to requests if ( !t->page()->hasPixmap( THUMBNAILS_ID, t->pixmapWidth(), t->pixmapHeight() ) ) { PixmapRequest * p = new PixmapRequest( THUMBNAILS_ID, t->pageNumber(), t->pixmapWidth(), t->pixmapHeight(), THUMBNAILS_PRIO, true ); requestedPixmaps.push_back( p ); } } // actually request pixmaps if ( !requestedPixmaps.isEmpty() ) m_document->requestPixmaps( requestedPixmaps ); }
bool Coord_cl::lineOfSight( const Coord_cl &target, UI16 targetheight, bool touch ) { //Console::instance()->send( QString( "LOScheck: Source:%1,Target:%2,Targetheight:%3\n" ).arg( z ).arg( target.z ).arg( targetheight ) ); if( target.map != map ) return false; if( (x == target.x) && (y == target.y) && (z == target.z) ) return true; // if source and target are on the same position SI32 n = ( target.x - x ), m = ( target.y - y ), i = 0; SI08 sgn_x = ( x <= target.x ) ? 1 : (-1); // signum for x SI08 sgn_y = ( y <= target.y ) ? 1 : (-1); // signum for y SI08 sgn_z = ( z <= target.z ) ? 1 : (-1); // signum for z if( x == target.x ) sgn_x = 0; if( y == target.y ) sgn_y = 0; if( z == target.z ) sgn_z = 0; QValueList< Coord_cl > collisions; //first we get our x-y-coordinates if( sgn_x == 0 && sgn_y == 0 && !sgn_z == 0 ) // should fix shooting through floor issues { collisions.push_back( Coord_cl( x, y, 0, map ) ); } else if( sgn_x == 0 ) // if we are on the same x-level, just push every x/y coordinate in y-direction from src to trg into the array for( i = 0; i <= (sgn_y * m); ++i ) { collisions.push_back( Coord_cl( x, y + (sgn_y * i), 0, map ) ); } else if ( sgn_y == 0 ) // if we are on the same y-level, just push every x/y coordinate in x-direction from src to trg into the array for( i = 0; i <= (sgn_x * n); ++i ) { collisions.push_back( Coord_cl( x + (sgn_x * i), y, 0, map ) ); } else { SI32 oldpos = y; bool exaktpos = false; for( i = 0; (sgn_x * n >= sgn_y * m) && (i <= (sgn_x * n)); i++ ) { //Console::instance()->send( QString( "x:%1\n" ).arg( i ) ); SI32 gridx = x + (sgn_x * i); if( ( ( n == 0 ) && ( gridx == 0 ) ) || ( ( n + ( gridx * m ) == 0 ) ) ) continue; else { if( exaktpos ) { collisions.push_back( Coord_cl( gridx, oldpos-sgn_y, 0, map ) ); //Console::instance()->send( QString( "add exaktpos coordinate %1,%2\n" ).arg( gridx ).arg( oldpos-sgn_y ) ); exaktpos = false; } // linear evaluation of extended 2x2 matrix, abbreviated double t = (double)sgn_x * ((double)i+0.5) * (double)m / (double)n + (double)y; //Console::instance()->send( QString( "t:%1\n" ).arg( t ) ); if( ((sgn_y>0) && (specialFloor(t)==oldpos+0.5)) || ((sgn_y<0) && (specialFloor(t)==oldpos-0.5)) ) { exaktpos = true; } if( ((sgn_y>0) && (t<oldpos+0.5)) || ((sgn_y<0) && (t>oldpos-0.5)) || (oldpos==target.y) ) { collisions.push_back( Coord_cl( gridx, oldpos, 0, map ) ); //Console::instance()->send( QString( "add coordinate %1,%2\n" ).arg( gridx ).arg( oldpos ) ); } // but if not, we have to take BOTH coordinates, which the calculated collision is between! else { collisions.push_back( Coord_cl( gridx, oldpos, 0, map ) ); //Console::instance()->send( QString( "add coordinate %1,%2\n" ).arg( gridx ).arg( oldpos ) ); oldpos += sgn_y; collisions.push_back( Coord_cl( gridx, oldpos, 0, map ) ); //Console::instance()->send( QString( "add coordinate %1,%2\n" ).arg( gridx ).arg( oldpos ) ); } } } oldpos = x; exaktpos = false; for( i = 0; (sgn_y * m >= sgn_x * n) && (i <= (sgn_y * m)); ++i ) { //Console::instance()->send( QString( "y:%1\n" ).arg( i ) ); SI32 gridy = y + (sgn_y * i); if( ( ( m == 0 ) && ( gridy == 0 ) ) || ( ( m + ( gridy * n ) == 0 ) ) ) continue; else { if( exaktpos ) { collisions.push_back( Coord_cl( oldpos-sgn_x, gridy, 0, map ) ); //Console::instance()->send( QString( "add exaktpos coordinate %1,%2\n" ).arg( oldpos-sgn_x ).arg( gridy ) ); exaktpos = false; } double t = (double)x + (double)n / (double)m * (double)sgn_y * ((double)i+0.5); //Console::instance()->send( QString( "t:%1\n" ).arg( t ) ); if( ((sgn_x>0) && (specialFloor(t)==oldpos+0.5)) || ((sgn_x<0) && (specialFloor(t)==oldpos-0.5)) ) { exaktpos = true; } if( ((sgn_x>0) && (t<oldpos+0.5)) || ((sgn_x<0) && (t>oldpos-0.5)) || (oldpos==target.x) ) { collisions.push_back( Coord_cl( oldpos, gridy, 0, map ) ); //Console::instance()->send( QString( "add coordinate %1,%2\n" ).arg( oldpos ).arg( gridy ) ); } // but if not, we have to take BOTH coordinates, which the calculated collision is between! else { collisions.push_back( Coord_cl( oldpos, gridy, 0, map ) ); //Console::instance()->send( QString( "add coordinate %1,%2\n" ).arg( oldpos ).arg( gridy ) ); oldpos += sgn_x;; collisions.push_back( Coord_cl( oldpos, gridy, 0, map ) ); //Console::instance()->send( QString( "add coordinate %1,%2\n" ).arg( oldpos ).arg( gridy ) ); } } } } // the next will search for multis QPtrList< cItem > multis; RegionIterator4Items ri( *this ); for( ri.Begin(); !ri.atEnd(); ri++ ) { P_ITEM pi = ri.GetData(); if( pi && pi->id() >= 0x4000 ) { multis.append( pi ); } } //touch wird von notouch getrennt, da der notouch algorithmus wesentlich aufwändiger //ist (touch benötigt die erste for-schleife nicht), macht den code zwar bisserl //unübersichtlicher, aber ist wesentlich effizienter //touch is separated from notouch, because the notouch calculation is much more to do //( one additional for-loop ) if( targetheight > 0 ) { --targetheight; } if( !touch ) { for( i = target.z+targetheight; i >= target.z; --i ) { bool blocked = false; //Console::instance()->send( QString( "i:%1\n" ).arg( i ) ); double dz; double gradient; double offset; if( (sgn_x == 0) && (sgn_y == 0) ) { dz = (double)i - (double)z; gradient = 1; //only to avoid problems, isnt used offset = 1; } else { dz = ( (double)i -(double)z ) / sqrt( ((double)target.x - (double)x)*((double)target.x - (double)x) + ((double)target.y - (double)y)*((double)target.y - (double)y) ); gradient = (double)m / (double)n; offset = 0.5*( (double)y + (double)target.y - gradient*( x + target.x ) ); } map_st map1, map2; SI32 j; bool posHigherThanMap; map1 = Map->seekMap( (*this) ); if( map1.z > z ) { posHigherThanMap = false; } else { posHigherThanMap = true; } //Console::instance()->send( QString( "after first things\n" ) ); QValueList< Coord_cl >::iterator pit = collisions.begin(); while( pit != collisions.end() ) { //Console::instance()->send( QString( "coordinate:%1,%2 dz:%3\n" ).arg( (*pit).x ).arg( (*pit).y ).arg( dz ) ); //lets see what z-coordinates we have to test //we do our calculations exakt, because its the only way to solve all problems //of floor //"minimum" ist am anfang der platte, "maximum" am ende //our line is y = gradient * x + offset //or x = ( y - offset ) / gradient //we now have to test, where the line cuts one position //start and endposition has to be done alone double z1 = -300; double z2 = -300; SI08 zmin, zmax; if( (sgn_x == 0) && (sgn_y == 0) ) { if( dz > 0 ) { zmin = z+1; zmax = i; } else { zmin = i+1; zmax = z; } } else if( sgn_x == 0 ) { //gradient only in y-direction z1 = (double)i - dz*( fabs( (double)target.y - (double)((*pit).y) ) -0.5 ); z2 = (double)i - dz*( fabs( (double)target.y - (double)((*pit).y) ) +0.5 ); //Console::instance()->send( QString( "i:%1,ty:%2,cy:%3\n" ).arg( i ).arg( target.y ).arg( (*pit).y ) ); //Console::instance()->send( QString( "z1:%1,z2:%2\n" ).arg( z1 ).arg( z2 ) ); if( z1 > z2 ) { zmin = (SI08)floor( z2 ); zmax = (SI08)ceilf( z1 ); } else { zmin = (SI08)floor( z1 ); zmax = (SI08)ceilf( z2 ); } /*another try, but i think its needed for all positions, not only start and end... //target if( (*pit).y == target.y ) { if( dz > 0 ) { zmax = QMIN( zmax, i ); //Console::instance()->send( QString( "TargetY, zmax:%1, i:%2\n" ).arg( zmax ).arg( i ) ); } else { zmin = QMAX( zmin, i+1 ); //Console::instance()->send( QString( "TargetY, zmin:%1, i:%2\n" ).arg( zmin ).arg( i ) ); } } //source if( (*pit).y == y ) { if( dz > 0 ) { zmin = QMAX( zmin, z ); //Console::instance()->send( QString( "SourceY, zmin:%1, i:%2\n" ).arg( zmax ).arg( i ) ); } else { zmax = QMIN( zmax, z ); //Console::instance()->send( QString( "SourceY, zmax:%1, i:%2\n" ).arg( zmax ).arg( i ) ); } }*/ if( dz > 0 ) { zmax = QMIN( zmax, i ); zmin = QMAX( zmin, z ); } else { zmin = QMAX( zmin, i+1 ); zmax = QMIN( zmax, z ); } } else if( sgn_y == 0 ) { //gradient only in y-direction z1 = (double)i - dz*( fabs( (double)target.x - (double)((*pit).x) ) -0.5 ); z2 = (double)i - dz*( fabs( (double)target.x - (double)((*pit).x) ) +0.5 ); //Console::instance()->send( QString( "i:%1,tx:%2,cx:%3\n" ).arg( i ).arg( target.x ).arg( (*pit).x ) ); //Console::instance()->send( QString( "z1:%1,z2:%2\n" ).arg( z1 ).arg( z2 ) ); if( z1 > z2 ) { zmin = (SI08)floor( z2 ); zmax = (SI08)ceilf( z1 ); } else { zmin = (SI08)floor( z1 ); zmax = (SI08)ceilf( z2 ); } if( dz > 0 ) { zmax = QMIN( zmax, i ); zmin = QMAX( zmin, z ); } else { zmin = QMAX( zmin, i+1 ); zmax = QMIN( zmax, z ); } } else { //4 lines to test double gradx = ( (double)target.y*(double)z - (double)y*(double)i ) / ( (double)target.y*(double)x - (double)y*(double)target.x ); double grady = ( (double)target.x*(double)z - (double)x*(double)i ) / ( (double)y*(double)target.x - (double)target.y*(double)x ); //Console::instance()->send( QString( "gradx:%1,grady:%2\n" ).arg( gradx ).arg( grady ) ); //Console::instance()->send( QString( "Gradient:%1,Offset:%2\n" ).arg( gradient ).arg( offset ) ); double temp; temp = specialFloor( gradient*( (double)((*pit).x) - 0.5 ) + offset ); //Console::instance()->send( QString( "temp1:%1\n" ).arg( temp ) ); if( ( temp >= ((double)((*pit).y)-0.5) ) && ( temp <= ((double)((*pit).y)+0.5) ) ) { if( z1 > -300 ) { z2 = gradx * ( (double)((*pit).x)-0.5 ) + grady * temp; } else { z1 = gradx * ( (double)((*pit).x)-0.5 ) + grady * temp; } //Console::instance()->send( QString( "1:i:%1,tx:%2,ty:%3,cy:%4,cy:%5\n" ).arg( i ).arg( target.x ).arg( target.y ).arg( (*pit).x ).arg( (*pit).y ) ); //Console::instance()->send( QString( "z1:%1,z2:%2\n" ).arg( z1 ).arg( z2 ) ); } temp = specialFloor( gradient*( (double)((*pit).x) + 0.5 ) + offset ); //Console::instance()->send( QString( "temp2:%1\n" ).arg( temp ) ); if( ( temp >= ((double)((*pit).y)-0.5) ) && ( temp <= ((double)((*pit).y)+0.5) ) ) { if( z1 > -300 ) { z2 = gradx * ( (double)((*pit).x)+0.5 ) + grady * temp; } else { z1 = gradx * ( (double)((*pit).x)+0.5 ) + grady * temp; } //Console::instance()->send( QString( "2:i:%1,tx:%2,ty:%3,cy:%4,cy:%5\n" ).arg( i ).arg( target.x ).arg( target.y ).arg( (*pit).x ).arg( (*pit).y ) ); //Console::instance()->send( QString( "z1:%1,z2:%2\n" ).arg( z1 ).arg( z2 ) ); } temp = specialFloor( (double)((*pit).y) - 0.5 - offset ) / gradient; //Console::instance()->send( QString( "temp3:%1\n" ).arg( temp ) ); if( ( temp > ((double)((*pit).x)-0.5) ) && ( temp < ((double)((*pit).x)+0.5) ) ) { if( z1 > -300 ) { z2 = gradx * temp + grady * ((double)((*pit).y)-0.5); } else { z1 = gradx * temp + grady * ((double)((*pit).y)-0.5); } //Console::instance()->send( QString( "3:i:%1,tx:%2,ty:%3,cy:%4,cy:%5\n" ).arg( i ).arg( target.x ).arg( target.y ).arg( (*pit).x ).arg( (*pit).y ) ); //Console::instance()->send( QString( "z1:%1,z2:%2\n" ).arg( z1 ).arg( z2 ) ); } temp = specialFloor( (double)((*pit).y) + 0.5 - offset ) / gradient; //Console::instance()->send( QString( "temp4:%1\n" ).arg( temp ) ); if( ( temp > ((double)((*pit).x)-0.5) ) && ( temp < ((double)((*pit).x)+0.5) ) ) { if( z1 > -300 ) { z2 = gradx * temp + grady * ((double)((*pit).y)+0.5); } else { z1 = gradx * temp + grady * ((double)((*pit).y)+0.5); } //Console::instance()->send( QString( "4:i:%1,tx:%2,ty:%3,cy:%4,cy:%5\n" ).arg( i ).arg( target.x ).arg( target.y ).arg( (*pit).x ).arg( (*pit).y ) ); //Console::instance()->send( QString( "z1:%1,z2:%2\n" ).arg( z1 ).arg( z2 ) ); } //Console::instance()->send( QString( "z1:%1,z2:%2\n" ).arg( z1 ).arg( z2 ) ); if( z1 > z2 ) { zmin = (SI08)floor( z2 ); zmax = (SI08)ceilf( z1 ); } else { zmin = (SI08)floor( z1 ); zmax = (SI08)ceilf( z2 ); } if( z2 == -300 ) { zmin = (SI08)floor( z1 ); } if( dz > 0 ) { zmax = QMIN( zmax, i ); zmin = QMAX( zmin, z ); } else { zmin = QMAX( zmin, i+1 ); zmax = QMIN( zmax, z ); } //Console::instance()->send( QString( "zmin:%1,zmax:%2\n" ).arg( zmin ).arg( zmax ) ); } /*SI08 zmin = (SI08)floor( i - dz*sqrt( ((double)target.x - (double)(*pit).x)*((double)target.x - (double)(*pit).x) + ((double)target.y - (double)(*pit).y)*((double)target.y - (double)(*pit).y) ) ); SI08 zmax; //Console::instance()->send( QString( "zmin:%1,dz:%2\n" ).arg( zmin ).arg( dz ) ); if( dz > 0 ) { zmin = QMAX( (SI08)floor( zmin - dz/2 ), z+1 ); zmax = QMIN( zmin + dz + 1, target.z+targetheight+1 ); //to prevent floor-mistakes } else { zmin = QMIN( (SI08)floor( zmin + dz/2 ), target.z+1 ); zmax = QMAX( zmin - dz + 1, z ); //to prevent floor-mistakes }*/ // Texture mapping map1 = Map->seekMap( *pit ); map2 = Map->seekMap( Coord_cl( (*pit).x + sgn_x, (*pit).y + sgn_y, (*pit).z, map ) ); //Console::instance()->send( QString( "maphoehe:%1\n" ).arg( map1.z ) ); StaticsIterator msi = Map->staticsIterator( *pit ); if( (map1.id != 2) && (map2.id != 2) ) { if( ( map1.z >= zmin ) && ( map1.z <= zmax ) ) { //its just in our way //Console::instance()->send( QString( "Map gescheitert\n" ) ); blocked = true; break; } //now we have to test, if this tile is under our line and the next above or //vice verse //in this case, both dont cut our line, but the mapconnection between them //should do if( ( ( map1.z < map2.z ) && ( map1.z < zmin ) && ( map2.z > zmax+dz ) ) || // 1) lineofsight collides with a map "wall" ( ( map1.z > map2.z ) && ( map1.z > zmin ) && ( map2.z < zmax-dz ) ) || ( ( ( map1.id >= 431 && map1.id <= 432 ) || // 3) lineofsight cuts a mountain ( map1.id >= 467 && map1.id <= 475 ) || ( map1.id >= 543 && map1.id <= 560 ) || ( map1.id >= 1754 && map1.id <= 1757 ) || ( map1.id >= 1787 && map1.id <= 1789 ) || ( map1.id >= 1821 && map1.id <= 1824 ) || ( map1.id >= 1851 && map1.id <= 1854 ) || ( map1.id >= 1881 && map1.id <= 1884 ) ) && ( posHigherThanMap ) && ( msi.atEnd() ) ) ) // mountains cut only if we are not beneath them { //Console::instance()->send( QString( "map1:%1,map2:%2\n" ).arg( map1.z ).arg( map2.z ) ); blocked = true; break; } } //Console::instance()->send( QString( "after map\n" ) ); // Statics tile_st tile; while( !msi.atEnd() ) { tile = TileCache::instance()->getTile( msi->itemid ); //if it is in our way //Console::instance()->send( QString( "tilepos:%1,zmax:%2" ).arg( msi->zoff ).arg( zmax ) ); //Console::instance()->send( QString( "zmin:%3\n" ).arg( zmin ) ); if( ( zmax >= msi->zoff ) && ( zmin <= ( msi->zoff + tile.height ) ) ) { //Console::instance()->send( QString( "statictile, id: %1\n" ).arg( msi->itemid ) ); if( tile.isNoShoot() ) { blocked = true; break; } } ++msi; } if( blocked ) { break; } //Console::instance()->send( QString( "after statics\n" ) ); // Items RegionIterator4Items rj( (*pit), 0 ); for( rj.Begin(); !rj.atEnd(); rj++ ) { P_ITEM pi = rj.GetData(); if( pi && pi->id() < 0x4000 ) { tile = TileCache::instance()->getTile( pi->id() ); if( ( zmax >= pi->pos().z ) && ( zmin <= ( pi->pos().z + tile.height ) ) && ( pi->visible() == 0 ) ) { //Console::instance()->send( QString( "item, id: %1" ).arg( pi->id() ) ); if( tile.isNoShoot() ) { blocked = true; break; } } } } if( blocked ) { break; } //Console::instance()->send( QString( "after items\n" ) ); // Multis QPtrListIterator< cItem > mit( multis ); P_ITEM pi; while( ( pi = mit.current() ) ) { MultiDefinition* def = MultiCache::instance()->getMulti( pi->id() - 0x4000 ); if ( !def ) continue; QValueVector<multiItem_st> multi = def->getEntries(); for( j = 0; j < multi.size(); ++j ) { if( ( multi[j].visible ) && ( pi->pos().x + multi[j].x == (*pit).x ) && ( pi->pos().y + multi[j].y == (*pit).y ) ) { tile = TileCache::instance()->getTile( multi[j].tile ); if( ( zmax >= pi->pos().z + multi[j].z ) && ( zmin <= pi->pos().z + multi[j].z + tile.height ) ) { if( tile.isNoShoot() ) { blocked = true; break; } } } } ++mit; } //Console::instance()->send( QString( "after multis\n" ) ); ++pit; } if( !blocked ) return true; } //there was no line to see through return false; } //now touch=true else { //Console::instance()->send( "touch\n" ); double dz_up, dz_down; double gradient; double offset; if( (sgn_x == 0) && (sgn_y == 0) ) { dz_up = ( (double)targetheight + (double)target.z ) - (double)z; dz_down = (double)target.z - ( (double)z - (double)15 ); gradient = 1; //only to prevent problems, isnt used offset = 1; } else { //Console::instance()->send( QString( "xdiff:%1,ydiff:%2\n" ).arg( (double)target.x - (double)x ).arg( (double)target.y - (double)y ) ); dz_up = ( ( (double)targetheight + (double)target.z ) - (double)z ) / sqrt( ((double)target.x - (double)x)*((double)target.x - (double)x) + ((double)target.y - (double)y)*((double)target.y - (double)y) ); dz_down = ( (double)target.z - ( (double)z - (double)15 ) ) / sqrt( ((double)target.x - (double)x)*((double)target.x - (double)x) + ((double)target.y - (double)y)*((double)target.y - (double)y) ); gradient = (double)m / (double)n; offset = 0.5*( (double)y + (double)target.y - gradient*( x + target.x ) ); } map_st map1, map2; SI32 j; bool posHigherThanMap; map1 = Map->seekMap( (*this) ); if( map1.z > z ) { posHigherThanMap = false; } else { posHigherThanMap = true; } //Console::instance()->send( QString( "after first things\n" ) ); QValueList< Coord_cl >::iterator pit = collisions.begin(); while( pit != collisions.end() ) { //Console::instance()->send( QString( "coordinate:%1,%2\n" ).arg( (*pit).x ).arg( (*pit).y ) ); //lets see what z-coordinates we have to test //anmerkung: touch kommt nur für chars vor, grösse von chars ist 15 //SI08 zmin = (SI08)floor( (double)z - (double)sourceheight + dz_down*sqrt( ((double)target.x - (double)(*pit).x)*((double)target.x - (double)(*pit).x) + ((double)target.y - (double)(*pit).y)*((double)target.y - (double)(*pit).y) ) ); //SI08 zmax = (SI08)floor( (double)z + dz_up*sqrt( ((double)target.x - (double)(*pit).x)*((double)target.x - (double)(*pit).x) + ((double)target.y - (double)(*pit).y)*((double)target.y - (double)(*pit).y) ) ); SI08 zmin, zmax; double z1_up = -300; double z2_up = -300; double z1_down = -300; double z2_down = -300; bool targetpos = false; //Console::instance()->send( QString( "dz_down:%3,dz_up:%4\n" ).arg( dz_down ).arg( dz_up ) ); if( (sgn_x == 0) && (sgn_y == 0) ) { if( dz_up > 0 ) { zmin = z+1; zmax = target.z; } else { zmin = target.z+1; zmax = z; } targetpos = true; if( (dz_up >= 0) && (dz_down >= 0) ) { if( zmin < target.z ) { zmax = target.z -1; } else { //we ignore this coordinate ++pit; continue; } } else if( (dz_up <= 0) && (dz_down <= 0) ) { if( zmax > target.z + targetheight+1 ) { zmin = target.z + targetheight + 2; } else { ++pit; continue; } } else { //we may have to split the test into two if we would do it exactly //but i think we can throw away the test from down in this case if( zmax > target.z + targetheight+1 ) { zmin = target.z + targetheight + 2; } else if( zmin < target.z ) { zmax = target.z -1; } else { ++pit; continue; } } } else if( sgn_x == 0 ) { z1_up = target.z + targetheight - dz_up*( fabs( (double)target.y - (double)((*pit).y) ) -0.5 ); z2_up = target.z + targetheight - dz_up*( fabs( (double)target.y - (double)((*pit).y) ) +0.5 ); z1_down = target.z - dz_down*( fabs( (double)target.y - (double)((*pit).y) ) -0.5 ); z2_down = target.z - dz_down*( fabs( (double)target.y - (double)((*pit).y) ) +0.5 ); //Console::instance()->send( QString( "ty:%2,cy:%3\n" ).arg( target.y ).arg( (*pit).y ) ); //Console::instance()->send( QString( "z1_up:%1,z2_up:%2,z1_down:%3,z2_down:%4\n" ).arg( z1_up ).arg( z2_up ).arg( z1_down ).arg( z2_down ) ); zmax = QMAX( ceil( z1_up ), ceil( z2_up ) ); zmin = QMIN( floor( z1_down ), floor( z2_down ) ); //Console::instance()->send( QString( "y:zmin:%1,zmax:%2\n" ).arg( zmin ).arg( zmax ) ); if( dz_up > 0 ) { zmax = QMIN( zmax, target.z+targetheight ); } else { zmax = QMIN( zmax, z ); } //Console::instance()->send( QString( "y2:zmin:%1,zmax:%2\n" ).arg( zmin ).arg( zmax ) ); if( dz_down > 0 ) { zmin = QMAX( zmin, z-14 ); } else { zmin = QMAX( zmin, target.z+1 ); } //Console::instance()->send( QString( "y3:zmin:%1,zmax:%2\n" ).arg( zmin ).arg( zmax ) ); if( (*pit).y == target.y ) { targetpos = true; if( (dz_up >= 0) && (dz_down >= 0) ) { if( zmin < target.z ) { zmax = target.z -1; } else { //we ignore this coordinate ++pit; continue; } } else if( (dz_up <= 0) && (dz_down <= 0) ) { if( zmax > target.z + targetheight+1 ) { zmin = target.z + targetheight + 2; } else { ++pit; continue; } } else { //we may have to split the test into two if we would do it exactly //but i think we can throw away the test from down in this case if( zmax > target.z + targetheight+1 ) { zmin = target.z + targetheight + 2; } else if( zmin < target.z ) { zmax = target.z -1; } else { ++pit; continue; } } //Console::instance()->send( QString( "y4:zmin:%1,zmax:%2\n" ).arg( zmin ).arg( zmax ) ); } } else if( sgn_y == 0 ) { z1_up = target.z + targetheight - dz_up*( fabs( (double)target.x - (double)((*pit).x) ) -0.5 ); z2_up = target.z + targetheight - dz_up*( fabs( (double)target.x - (double)((*pit).x) ) +0.5 ); z1_down = target.z - dz_down*( fabs( (double)target.x - (double)((*pit).x) ) -0.5 ); z2_down = target.z - dz_down*( fabs( (double)target.x - (double)((*pit).x) ) +0.5 ); //Console::instance()->send( QString( "tx:%2,cx:%3\n" ).arg( target.x ).arg( (*pit).x ) ); //Console::instance()->send( QString( "z1_up:%1,z2_up:%2,z1_down:%3,z2_down:%4\n" ).arg( z1_up ).arg( z2_up ).arg( z1_down ).arg( z2_down ) ); zmax = QMAX( ceil( z1_up ), ceil( z2_up ) ); zmin = QMIN( floor( z1_down ), floor( z2_down ) ); if( dz_up > 0 ) { zmax = QMIN( zmax, target.z+targetheight ); } else { zmax = QMIN( zmax, z ); } if( dz_down > 0 ) { zmin = QMAX( zmin, z-14 ); } else { zmin = QMAX( zmin, target.z+1 ); } if( (*pit).x == target.x ) { targetpos = true; if( (dz_up >= 0) && (dz_down >= 0) ) { if( zmin < target.z ) { zmax = target.z -1; } else { //we ignore this coordinate ++pit; continue; } } else if( (dz_up <= 0) && (dz_down <= 0) ) { if( zmax > target.z + targetheight+1 ) { zmin = target.z + targetheight + 2; } else { ++pit; continue; } } else { //we may have to split the test into two if we would do it exactly //but i think we can throw away the test from down in this case if( zmax > target.z + targetheight+1 ) { zmin = target.z + targetheight + 2; } else if( zmin < target.z ) { zmax = target.z -1; } else { ++pit; continue; } } } } else { double gradx_up = ( (double)target.y*(double)z - (double)y*(double)(target.z + targetheight) ) / ( (double)target.y*(double)x - (double)y*(double)target.x ); double grady_up = ( (double)target.x*(double)z - (double)x*(double)(target.z + targetheight) ) / ( (double)y*(double)target.x - (double)target.y*(double)x ); double gradx_down = ( (double)target.y*(double)(z-15) - (double)y*(double)(target.z) ) / ( (double)target.y*(double)x - (double)y*(double)target.x ); double grady_down = ( (double)target.x*(double)(z-15) - (double)x*(double)(target.z) ) / ( (double)y*(double)target.x - (double)target.y*(double)x ); //Console::instance()->send( QString( "gradx_up:%1,grady_up:%2,gradx_down:%3,grady_down:%4\n" ).arg( gradx_up ).arg( grady_up ).arg( gradx_down ).arg( grady_down ) ); //Console::instance()->send( QString( "Gradient:%1,Offset:%2\n" ).arg( gradient ).arg( offset ) ); double temp = specialFloor( gradient*( (double)((*pit).x) - 0.5 ) + offset ); //Console::instance()->send( QString( "temp1:%1\n" ).arg( temp ) ); if( ( temp >= ((double)((*pit).y)-0.5) ) && ( temp <= ((double)((*pit).y)+0.5) ) ) { if( z1_up > -300 ) { z2_up = gradx_up * ( (double)((*pit).x)-0.5 ) + grady_up * temp; z2_down = gradx_down * ( (double)((*pit).x)-0.5 ) + grady_down * temp; } else { z1_up = gradx_up * ( (double)((*pit).x)-0.5 ) + grady_up * temp; z1_down = gradx_down * ( (double)((*pit).x)-0.5 ) + grady_down * temp; } //Console::instance()->send( QString( "tx:%1,ty:%2,cy:%3,cy:%4\n" ).arg( target.x ).arg( target.y ).arg( (*pit).x ).arg( (*pit).y ) ); //Console::instance()->send( QString( "z1_up:%1,z1_down:%2,z2_up:%3,z2_down:%4\n" ).arg( z1_up ).arg( z1_down ).arg( z2_up ).arg( z2_down ) ); } temp = specialFloor( gradient*( (double)((*pit).x) + 0.5 ) + offset ); //Console::instance()->send( QString( "temp2:%1\n" ).arg( temp ) ); if( ( temp >= ((double)((*pit).y)-0.5) ) && ( temp <= ((double)((*pit).y)+0.5) ) ) { if( z1_up > -300 ) { z2_up = gradx_up * ( (double)((*pit).x)+0.5 ) + grady_up * temp; z2_down = gradx_down * ( (double)((*pit).x)+0.5 ) + grady_down * temp; } else { z1_up = gradx_up * ( (double)((*pit).x)+0.5 ) + grady_up * temp; z1_down = gradx_down * ( (double)((*pit).x)+0.5 ) + grady_down * temp; } //Console::instance()->send( QString( "tx:%1,ty:%2,cy:%3,cy:%4\n" ).arg( target.x ).arg( target.y ).arg( (*pit).x ).arg( (*pit).y ) ); //Console::instance()->send( QString( "z1_up:%1,z1_down:%2,z2_up:%3,z2_down:%4\n" ).arg( z1_up ).arg( z1_down ).arg( z2_up ).arg( z2_down ) ); } temp = specialFloor( (double)((*pit).y) - 0.5 - offset ) / gradient; //Console::instance()->send( QString( "temp3:%1\n" ).arg( temp ) ); if( ( temp > ((double)((*pit).x)-0.5) ) && ( temp < ((double)((*pit).x)+0.5) ) ) { if( z1_up > -300 ) { z2_up = gradx_up * temp + grady_up * ((double)((*pit).y)-0.5); z2_down = gradx_down * temp + grady_down * ((double)((*pit).y)-0.5); } else { z1_up = gradx_up * temp + grady_up * ((double)((*pit).y)-0.5); z1_down = gradx_down * temp + grady_down * ((double)((*pit).y)-0.5); } //Console::instance()->send( QString( "tx:%1,ty:%2,cy:%3,cy:%4\n" ).arg( target.x ).arg( target.y ).arg( (*pit).x ).arg( (*pit).y ) ); //Console::instance()->send( QString( "z1_up:%1,z1_down:%2,z2_up:%3,z2_down:%4\n" ).arg( z1_up ).arg( z1_down ).arg( z2_up ).arg( z2_down ) ); } temp = specialFloor( (double)((*pit).y) + 0.5 - offset ) / gradient; //Console::instance()->send( QString( "temp4:%1\n" ).arg( temp ) ); if( ( temp > ((double)((*pit).x)-0.5) ) && ( temp < ((double)((*pit).x)+0.5) ) ) { if( z1_up > -300 ) { z2_up = gradx_up * temp + grady_up * ((double)((*pit).y)+0.5); z2_down = gradx_down * temp + grady_down * ((double)((*pit).y)+0.5); } else { z1_up = gradx_up * temp + grady_up * ((double)((*pit).y)+0.5); z1_down = gradx_down * temp + grady_down * ((double)((*pit).y)+0.5); } //Console::instance()->send( QString( "tx:%1,ty:%2,cy:%3,cy:%4\n" ).arg( target.x ).arg( target.y ).arg( (*pit).x ).arg( (*pit).y ) ); //Console::instance()->send( QString( "z1_up:%1,z1_down:%2,z2_up:%3,z2_down:%4\n" ).arg( z1_up ).arg( z1_down ).arg( z2_up ).arg( z2_down ) ); } //Console::instance()->send( QString( "ergebnis: z1_up:%1,z1_down:%2,z2_up:%3,z2_down:%4\n" ).arg( z1_up ).arg( z1_down ).arg( z2_up ).arg( z2_down ) ); if( z2_up == -300 ) { zmin = floor( z1_down ); zmax = ceil( z1_up ); } else { zmin = QMIN( floor( z1_down ), floor( z2_down ) ); zmax = QMAX( ceil( z1_up ), ceil( z2_up ) ); } //Console::instance()->send( QString( "zmin:%1,zmax:%2\n" ).arg( zmin ).arg( zmax ) ); if( dz_up > 0 ) { zmax = QMIN( zmax, target.z+targetheight ); } else { zmax = QMIN( zmax, z ); } if( dz_down > 0 ) { zmin = QMAX( zmin, z-14 ); } else { zmin = QMAX( zmin, target.z+1 ); } //Console::instance()->send( QString( "zmin:%1,zmax:%2\n" ).arg( zmin ).arg( zmax ) ); if( ((*pit).x == target.x) && ((*pit).y == target.y) ) { targetpos = true; if( (dz_up >= 0) && (dz_down >= 0) ) { if( zmin < target.z ) { zmax = target.z -1; } else { //we ignore this coordinate ++pit; continue; } } else if( (dz_up <= 0) && (dz_down <= 0) ) { if( zmax > target.z + targetheight+1) { zmin = target.z + targetheight + 2; } else { ++pit; continue; } } else { //we may have to split the test into two if we would do it exactly //but i think we can throw away the test from down in this case if( zmax > target.z + targetheight+1 ) { zmin = target.z + targetheight + 2; } else if( zmin < target.z ) { zmax = target.z -1; } else { ++pit; continue; } } } } //Console::instance()->send( QString( "zmin:%1,zmax:%2\n" ).arg( zmin ).arg( zmax ) ); // Texture mapping map1 = Map->seekMap( *pit ); map2 = Map->seekMap( Coord_cl( (*pit).x + sgn_x, (*pit).y + sgn_y, (*pit).z, map ) ); //Console::instance()->send( QString( "try2" ) ); StaticsIterator msi = Map->staticsIterator( *pit ); RegionIterator4Items rj( (*pit), 0 ); if( (map1.id != 2) && (map2.id != 2) ) { if( ( map1.z > zmin ) && ( map1.z < zmax ) ) { //its just in our way //Console::instance()->send( QString( "map cut 1\n" ) ); return false; } //now we have to test, if this tile is under our line and the next above or //vice verse //in this case, both dont cut our line, but the mapconnection between them //should do land_st tile = TileCache::instance()->getLand( map1.id ); if( ( ( map1.z < map2.z ) && ( map1.z < zmin ) && ( map2.z > zmax+dz_down ) && !targetpos ) || // 1) lineofsight collides with a map "wall" ( ( map1.z > map2.z ) && ( map1.z > zmin ) && ( map2.z < zmin+dz_down ) && !targetpos ) || ( tile.isBlocking() && posHigherThanMap && msi.atEnd() && rj.atEnd() ) ) { //Console::instance()->send( QString( "map1:%1,map2:%2,map1id:%3\n" ).arg( map1.z ).arg( map2.z ).arg( map1.id ) ); if( ( map1.z < map2.z ) && ( map1.z < zmin ) && ( map2.z > zmax+dz_down ) ) { //Console::instance()->send( QString( "mapcut1\n" ) ); } else if( ( map1.z > map2.z ) && ( map1.z > zmin ) && ( map2.z < zmin+dz_down ) ) { //Console::instance()->send( QString( "mapcut2\n" ) ); } else if( tile.isBlocking() && posHigherThanMap && msi.atEnd() && rj.atEnd() ) { //Console::instance()->send( QString( "mapcut3\n" ) ); } else { //Console::instance()->send( QString( "mapcut: this isnt possible\n" ) ); } return false; } } //Console::instance()->send( QString( "after map\n" ) ); // Statics tile_st tile; while( !msi.atEnd() ) { tile = TileCache::instance()->getTile( msi->itemid ); //Console::instance()->send( QString( "statictilepos:%1,zmax:%2,zmin:%3\n" ).arg( msi->zoff ).arg( zmax ).arg( zmin ) ); //if it is in our way if( ( zmax >= msi->zoff ) && ( zmin <= ( msi->zoff + tile.height ) ) ) { if( tile.isBlocking() || tile.isRoofOrFloorTile() ) { return false; } } ++msi; } //Console::instance()->send( QString( "after statics\n" ) ); // Items //Console::instance()->send( QString( "Items at: %1,%2,%3,%4\n" ).arg( (*pit).x ).arg( (*pit).y ).arg( (*pit).z ).arg( (*pit).map ) ); for( rj.Begin(); !rj.atEnd(); rj++ ) { //Console::instance()->send( QString( "foritem\n" ) ); P_ITEM pi = rj.GetData(); if( pi && pi->id() < 0x4000 ) { tile = TileCache::instance()->getTile( pi->id() ); //Console::instance()->send( QString( "itemtilepos:%1,zmax:%2,zmin:%3\n" ).arg( pi->pos().z ).arg( zmax ).arg( zmin ) ); if( ( zmax >= pi->pos().z ) && ( zmin <= ( pi->pos().z + tile.height ) ) && ( pi->visible() == 0 ) ) { if( tile.isBlocking() || tile.isRoofOrFloorTile() ) { //Console::instance()->send( QString( "Item:%1,Z:%2,Height:%3\n" ).arg( pi->id() ).arg( pi->pos().z ).arg( tile.height ) ); return false; } } } } //Console::instance()->send( QString( "after items\n" ) ); // Multis QPtrListIterator< cItem > mit( multis ); P_ITEM pi; while( ( pi = mit.current() ) ) { MultiDefinition* def = MultiCache::instance()->getMulti( pi->id() - 0x4000 ); if ( !def ) { ++mit; continue; } QValueVector<multiItem_st> multi = def->getEntries(); for( j = 0; j < multi.size(); ++j ) { if( ( multi[j].visible ) && ( pi->pos().x + multi[j].x == (*pit).x ) && ( pi->pos().y + multi[j].y == (*pit).y ) ) { tile = TileCache::instance()->getTile( multi[j].tile ); if( ( zmax >= pi->pos().z + multi[j].z ) && ( zmin <= pi->pos().z + multi[j].z + tile.height ) ) { if( tile.isBlocking() || tile.isRoofOrFloorTile() ) { return false; } } } } ++mit; } //Console::instance()->send( QString( "after multis\n" ) ); ++pit; } return true; } }
bool cMulti::canPlace( const Coord& pos, unsigned short multiid, QPtrList<cUObject>& moveOut, unsigned short yard ) { MultiDefinition *multi = MultiCache::instance()->getMulti( multiid ); if ( !multi ) { return false; } moveOut.setAutoDelete( false ); // Get the boundaries and build a list sorted by x,y int left = multi->getLeft(); int right = multi->getRight(); int bottom = multi->getBottom(); int top = multi->getTop(); int height = multi->getHeight(); int width = multi->getWidth(); Q_UNUSED( bottom ); QValueList<Coord> borderList; // a list of points around the foundation that need to be clear of impassables QValueList<Coord> yardList; // a list of points in the yard (front/back of the house that needs to be clear) for ( int x = 0; x < width; ++x ) { for ( int y = 0; y < height; ++y ) { Coord point = pos + Coord( x + left, y + top ); bool hasBase = false; // Has this multi tile a base below the floor? // See if there are any tiles at that position const QValueVector<multiItem_st> &multiItems = multi->itemsAt( x + left, y + top ); if ( multiItems.size() == 0 ) { continue; // Skip this tile since there are no items here } cTerritory *region = Territories::instance()->region( point ); if ( region && region->isNoHousing() ) { return false; // No housing is allowed in this region } // Collect data for the intersect checks StaticsIterator statics = Maps::instance()->staticsIterator( point ); MapItemsIterator items = MapObjects::instance()->listItemsAtCoord( point ); int top, bottom; unsigned short landId; Maps::instance()->mapTileSpan( point, landId, bottom, top ); // Check every tile of the multi at the current position // The following algorithm is more or less a ripoff of RunUOs idea. for ( unsigned int i = 0; i < multiItems.size(); ++i ) { multiItem_st multiItem = multiItems[i]; tile_st tile = TileCache::instance()->getTile( multiItem.tile ); // Calculcate the spawn of the tile int itemBottom = point.z + multiItem.z; // if the tile is a surface, someone has to be able to stand on it. int itemTop = itemBottom + tile.height + ( ( ( tile.flag2 & 0x02 ) != 0 ) ? 16 : 0 ); // There is special handling for floor tiles bool baseTile = multiItem.z == 0 && ( tile.flag1 & 0x10 ) != 0; bool isHovering = true; // This tile has not yet something to "stand" on Q_UNUSED( isHovering ); if ( baseTile ) hasBase = true; // Does the multi item intersect a land-tile? if ( ( itemTop < top && itemTop >= bottom ) || ( itemBottom < top && itemBottom >= bottom ) ) { return false; } // Since houses can only be built on land and not on items, it's enough to check for // a solid foundation here if ( pos.z != bottom || pos.z != top ) { return false; } // Check if the multi item is interfering with a static tile at the same position statics.reset(); while ( !statics.atEnd() ) { const staticrecord &staticTile = ( statics++ ).data(); tile_st staticInfo = TileCache::instance()->getTile( staticTile.itemid ); int staticBottom = staticTile.zoff; int staticTop = staticBottom + staticInfo.height; // The tile intersects a static tile if ( ( itemTop < staticTop && itemTop >= staticBottom ) || ( itemBottom < staticTop && itemBottom >= staticBottom ) ) { bool impassable = ( staticInfo.flag1 & 0x40 ) != 0; bool background = ( staticInfo.flag1 & 0x01 ) != 0; bool surface = ( staticInfo.flag2 & 0x02 ) != 0; // A normally blocking tile is intersecting our multi if ( impassable || ( !background && surface ) ) { return false; } } } // Do the same check (as above) with movable items, but make sure that movable items // are moved out of the house for ( P_ITEM pItem = items.first(); pItem; pItem = items.next() ) { tile_st itemInfo = TileCache::instance()->getTile( pItem->id() ); int dynamicBottom = pItem->pos().z; int dynamicTop = dynamicBottom + itemInfo.height; // Only handle the tile if it is intersecting the multi if ( ( itemTop < dynamicTop && itemTop >= dynamicBottom ) || ( itemBottom < dynamicTop && itemBottom >= dynamicBottom ) ) { // Move the item out of the multi space if possible if ( ( pItem->movable() == 0 && itemInfo.weight != 255 ) || pItem->movable() == 1 ) { moveOut.append( pItem ); } else { bool impassable = ( itemInfo.flag1 & 0x40 ) != 0; bool background = ( itemInfo.flag1 & 0x01 ) != 0; bool surface = ( itemInfo.flag2 & 0x02 ) != 0; // A normally blocking tile is intersecting our multi if ( impassable || ( !background && surface ) ) { return false; } } } } // Moves mobiles inside the multi out to the ban location MapCharsIterator chars = MapObjects::instance()->listCharsAtCoord( point ); for ( P_CHAR pChar = chars.first(); pChar; pChar = chars.next() ) { // Move them ALWAYS out, they could be trapped by the castle // otherwise (or other strange multi forms) moveOut.append( pChar ); } // To keep roads house free, here's a specialized check for roads if ( ( landId >= 0x71 && landId <= 0x8c ) || ( landId >= 0x14c && landId <= 0x14f ) || ( landId >= 0x161 && landId <= 0x174 ) || ( landId >= 0x1f0 && landId <= 0x1f3 ) || ( landId >= 0x26e && landId <= 0x279 ) || ( landId >= 0x27e && landId <= 0x281 ) || ( landId >= 0x324 && landId <= 0x3ac ) || ( landId >= 0x597 && landId <= 0x5a6 ) || ( landId >= 0x637 && landId <= 0x63a ) || ( landId >= 0x67d && landId <= 0x6a0 ) || ( landId >= 0x7ae && landId <= 0x7b1 ) || ( landId >= 0x442 && landId <= 0x479 ) || ( landId >= 0x501 && landId <= 0x510 ) || ( landId >= 0x009 && landId <= 0x015 ) || ( landId >= 0x150 && landId <= 0x15c ) ) { return false; // Road Blocked } // For houses (they have a base you know...) // we collect another list of points around the house that need to be checked if ( hasBase ) { int xOffset, yOffset; // We have to do two loops since the yard size does play a role here // but not for the border for ( xOffset = -1; xOffset <= 1; ++xOffset ) { for ( yOffset = -yard; yOffset <= yard; ++yOffset ) { Coord pos = point + Coord( xOffset, yOffset ); if ( !yardList.contains( pos ) ) { yardList.push_back( pos ); // Put this point into the yard checklist if it's not there } } } for ( xOffset = -1; xOffset <= 1; ++xOffset ) { for ( yOffset = -1; yOffset <= 1; ++yOffset ) { Coord pos = point + Coord( xOffset, yOffset ); // Only do the following if the current tiles position differs from the // check position. if ( xOffset != 0 || yOffset != 0 ) { // The border list should not contain tiles that are actually below the multis // floor and hence not visible and covered by a walkable multi tile. // So what we do here is check if within 8 z units of the multis floor there is a // walkable tile above the border tile int multiX = x + xOffset; // Offset to the upper left corner of the multi int multiY = y + yOffset; // Offset to the upper left corner of the multi bool found = false; // Assume there is no such tile // Only do this check if the to-be-checked tile is really within the multi // boundaries if ( multiX >= 0 && multiY >= 0 && multiX < width && multiY < height ) { // Get the multi tiles at the to-check position const QValueVector<multiItem_st> &tiles = multi->itemsAt( multiX + left, multiY + right ); QValueVector<multiItem_st>::const_iterator it; for ( it = tiles.begin(); it != tiles.end(); ++it ) { if ( it->z > 8 ) { continue; // Skip the tile if its above the base (2nd floor etc.) } // Get the tiledata info for this tile if it's below z8 tile_st tileInfo = TileCache::instance()->getTile( it->tile ); bool surface = ( tileInfo.flag2 & 0x02 ) != 0; if ( tileInfo.height == 0 && surface ) { found = true; break; } } // We found a tile that we could stand on. So it's not neccesary to check // that the house stands on something walkable here. if ( found ) { continue; } } // Add the tile to the list of border tiles. if ( !borderList.contains( pos ) ) { borderList.append( pos ); } } } } } } } } QValueList<Coord>::const_iterator it; // Now check all the accumulated border tiles for ( it = borderList.begin(); it != borderList.end(); ++it ) { map_st mapTile = Maps::instance()->seekMap( *it ); land_st mapTileInfo = TileCache::instance()->getLand( mapTile.id ); // Impassable map tiles are not allowed nearby bool impassable = ( mapTileInfo.flag1 & 0x40 ) != 0; if ( impassable ) { return false; } // Get Static Tiles StaticsIterator statics = Maps::instance()->staticsIterator( *it ); while ( !statics.atEnd() ) { const staticrecord &staticItem = statics.data(); tile_st staticInfo = TileCache::instance()->getTile( staticItem.itemid ); bool impassable = ( staticInfo.flag1 & 0x40 ) != 0; bool background = ( staticInfo.flag1 & 0x01 ) != 0; bool surface = ( staticInfo.flag2 & 0x02 ) != 0; // The tile is only of importance if it's not below the multi if ( ( staticItem.zoff > ( ( *it ).z + 2 ) ) && ( impassable || ( !background && surface ) ) ) { return false; // A normally blocking tile is intersecting our multi border } statics++; } // Do the same check (as above) with dynamic items MapItemsIterator items = MapObjects::instance()->listItemsAtCoord( *it ); for ( P_ITEM pItem = items.first(); pItem; pItem = items.next() ) { tile_st itemInfo = TileCache::instance()->getTile( pItem->id() ); // Move the item out of the multi space if possible if ( ( pItem->movable() == 0 && itemInfo.weight != 255 ) || pItem->movable() == 1 ) continue; if ( pItem->pos().z <= ( ( *it ).z + 2 ) ) continue; // Does not interfere with the border bool impassable = ( itemInfo.flag1 & 0x40 ) != 0; bool background = ( itemInfo.flag1 & 0x01 ) != 0; bool surface = ( itemInfo.flag2 & 0x02 ) != 0; // A normally blocking tile is intersecting our multi if ( impassable || ( !background && surface ) ) return false; } } // The yard has to be free of any multis at that position for ( it = yardList.begin(); it != yardList.end(); ++it ) { // Search for multis in the region MapMultisIterator multis = MapObjects::instance()->listMultisInCircle( *it, 18 ); for ( cMulti*multi = multis.first(); multi; multi = multis.next() ) { if ( multi->inMulti( *it ) ) { // This is a simplified check but it should be sufficient. return false; } } } return true; }