void FeatureSet::exclude( const FeatureSet &features ) { PROFILE_SCOPE( FeatureSet_Exclude ); for ( U32 i=0; i < features.mFeatures.size(); i++ ) removeFeature( *features.mFeatures[i].type ); mDescription.clear(); }
void CSTimeView::removeObjectsUsingBaseId(uint16 baseId) { uint16 groupId = getGroupFromBaseId(baseId); Feature *node = _rootNode->_next; while (node->_next) { Feature *curr = node; node = node->_next; if (curr->_data.compoundSHAPIndex == groupId) { removeFeature(curr, true); } } }
// /////////////////////////////////////////////////////////////// void processMultiPlayerArtifacts(void) { static UDWORD lastCall; FEATURE *pF,*pFN; UDWORD x,y,pl; Position position; BOOL found=false; // only do this every now and again. if(lastCall > gameTime)lastCall= 0; if ( (gameTime - lastCall) <2000) { return; } lastCall = gameTime; for(pF = apsFeatureLists[0]; pF ; pF = pFN) { pFN = pF->psNext; // artifacts if(pF->psStats->subType == FEAT_GEN_ARTE) { found = objectInRange((BASE_OBJECT *)apsDroidLists[selectedPlayer], pF->pos.x, pF->pos.y, (TILE_UNITS+(TILE_UNITS/3)) ); if(found) { position = pF->pos; // Add an effect addEffect(&position,EFFECT_EXPLOSION,EXPLOSION_TYPE_DISCOVERY,false,NULL,false); x = pF->pos.x; y = pF->pos.y; pl= pF->player; removeFeature(pF); // remove artifact+ send info. giftArtifact(pl,x,y); // reward player. pF->player = 0; audio_QueueTrack( ID_SOUND_ARTIFACT_RECOVERED ); } } } }
/* Remove a Feature and free it's memory */ bool destroyFeature(FEATURE *psDel) { UDWORD widthScatter,breadthScatter,heightScatter, i; EFFECT_TYPE explosionSize; Vector3i pos; UDWORD width,breadth; UDWORD mapX,mapY; ASSERT_OR_RETURN(false, psDel != NULL, "Invalid feature pointer"); /* Only add if visible and damageable*/ if(psDel->visible[selectedPlayer] && psDel->psStats->damageable) { /* Set off a destruction effect */ /* First Explosions */ widthScatter = TILE_UNITS/2; breadthScatter = TILE_UNITS/2; heightScatter = TILE_UNITS/4; //set which explosion to use based on size of feature if (psDel->psStats->baseWidth < 2 && psDel->psStats->baseBreadth < 2) { explosionSize = EXPLOSION_TYPE_SMALL; } else if (psDel->psStats->baseWidth < 3 && psDel->psStats->baseBreadth < 3) { explosionSize = EXPLOSION_TYPE_MEDIUM; } else { explosionSize = EXPLOSION_TYPE_LARGE; } for(i=0; i<4; i++) { pos.x = psDel->pos.x + widthScatter - rand()%(2*widthScatter); pos.z = psDel->pos.y + breadthScatter - rand()%(2*breadthScatter); pos.y = psDel->pos.z + 32 + rand()%heightScatter; addEffect(&pos,EFFECT_EXPLOSION,explosionSize,false,NULL,0); } if(psDel->psStats->subType == FEAT_SKYSCRAPER) { pos.x = psDel->pos.x; pos.z = psDel->pos.y; pos.y = psDel->pos.z; addEffect(&pos,EFFECT_DESTRUCTION,DESTRUCTION_TYPE_SKYSCRAPER,true,psDel->sDisplay.imd,0); initPerimeterSmoke(psDel->sDisplay.imd, pos); shakeStart(); } /* Then a sequence of effects */ pos.x = psDel->pos.x; pos.z = psDel->pos.y; pos.y = map_Height(pos.x,pos.z); addEffect(&pos,EFFECT_DESTRUCTION,DESTRUCTION_TYPE_FEATURE,false,NULL,0); //play sound // ffs gj if(psDel->psStats->subType == FEAT_SKYSCRAPER) { audio_PlayStaticTrack( psDel->pos.x, psDel->pos.y, ID_SOUND_BUILDING_FALL ); } else { audio_PlayStaticTrack( psDel->pos.x, psDel->pos.y, ID_SOUND_EXPLOSION ); } } if (psDel->psStats->subType == FEAT_SKYSCRAPER) { // ----- Flip all the tiles under the skyscraper to a rubble tile // smoke effect should disguise this happening mapX = map_coord(psDel->pos.x) - psDel->psStats->baseWidth/2; mapY = map_coord(psDel->pos.y) - psDel->psStats->baseBreadth/2; for (width = 0; width < psDel->psStats->baseWidth; width++) { for (breadth = 0; breadth < psDel->psStats->baseBreadth; breadth++) { MAPTILE *psTile = mapTile(mapX+width,mapY+breadth); // stops water texture chnaging for underwateer festures if (terrainType(psTile) != TER_WATER) { if (terrainType(psTile) != TER_CLIFFFACE) { /* Clear feature bits */ psTile->texture = TileNumber_texture(psTile->texture) | RUBBLE_TILE; } else { /* This remains a blocking tile */ psTile->psObject = NULL; psTile->texture = TileNumber_texture(psTile->texture) | BLOCKING_RUBBLE_TILE; } } } } } removeFeature(psDel); return true; }
/* Create a feature on the map */ FEATURE * buildFeature(FEATURE_STATS *psStats, UDWORD x, UDWORD y,BOOL FromSave) { UDWORD mapX, mapY; UDWORD width,breadth, foundationMin,foundationMax, height; UDWORD startX,startY,max,min; SDWORD i; UBYTE vis; //try and create the Feature FEATURE* psFeature = createFeature(); if (psFeature == NULL) { debug(LOG_WARNING, "Feature couldn't be built."); return NULL; } psFeature->psStats = psStats; // features are not in the cluster system // this will cause an assert when they still end up there psFeature->cluster = ~0; //add the feature to the list - this enables it to be drawn whilst being built addFeature(psFeature); // get the terrain average height startX = map_coord(x); startY = map_coord(y); foundationMin = TILE_MAX_HEIGHT; foundationMax = TILE_MIN_HEIGHT; for (breadth = 0; breadth < psStats->baseBreadth; breadth++) { for (width = 0; width < psStats->baseWidth; width++) { getTileMaxMin(startX + width, startY + breadth, &max, &min); if (foundationMin > min) { foundationMin = min; } if (foundationMax < max) { foundationMax = max; } } } //return the average of max/min height height = (foundationMin + foundationMax) / 2; // snap the coords to a tile if (!FromSave) { x = (x & ~TILE_MASK) + psStats->baseWidth %2 * TILE_UNITS/2; y = (y & ~TILE_MASK) + psStats->baseBreadth%2 * TILE_UNITS/2; } else { if ((x & TILE_MASK) != psStats->baseWidth %2 * TILE_UNITS/2 || (y & TILE_MASK) != psStats->baseBreadth%2 * TILE_UNITS/2) { debug(LOG_WARNING, "Feature not aligned. position (%d,%d), size (%d,%d)", x, y, psStats->baseWidth, psStats->baseBreadth); } } psFeature->pos.x = x; psFeature->pos.y = y; /* Dump down the building wrecks at random angles - still looks shit though */ if(psStats->subType == FEAT_BUILD_WRECK || psStats->subType == FEAT_TREE) { psFeature->rot.direction = gameRand(DEG_360); } else { psFeature->rot.direction = 0; } psFeature->selected = false; psFeature->body = psStats->body; psFeature->player = MAX_PLAYERS+1; //set the player out of range to avoid targeting confusions objSensorCache((BASE_OBJECT *)psFeature, NULL); objEcmCache((BASE_OBJECT *)psFeature, NULL); psFeature->bTargetted = false; psFeature->timeLastHit = 0; psFeature->lastHitWeapon = WSC_NUM_WEAPON_SUBCLASSES; // no such weapon // it has never been drawn psFeature->sDisplay.frameNumber = 0; if(getRevealStatus()) { vis = 0; } else { if(psStats->visibleAtStart) { vis = UBYTE_MAX; } else { vis = 0; } } // note that the advanced armour system current unused for features for (i = 0; i < NUM_HIT_SIDES; i++) { int j; for (j = 0; j < WC_NUM_WEAPON_CLASSES; j++) { psFeature->armour[i][j] = psFeature->psStats->armourValue; } } memset(psFeature->seenThisTick, 0, sizeof(psFeature->seenThisTick)); memset(psFeature->visible, 0, sizeof(psFeature->visible)); //load into the map data mapX = map_coord(x) - psStats->baseWidth/2; mapY = map_coord(y) - psStats->baseBreadth/2; // set up the imd for the feature if(psFeature->psStats->subType==FEAT_BUILD_WRECK) { psFeature->sDisplay.imd = getRandomWreckageImd(); } else { psFeature->sDisplay.imd = psStats->psImd; } ASSERT_OR_RETURN(NULL, psFeature->sDisplay.imd, "No IMD for feature"); // make sure we have an imd. for (width = 0; width < psStats->baseWidth; width++) { for (breadth = 0; breadth < psStats->baseBreadth; breadth++) { MAPTILE *psTile = mapTile(mapX + width, mapY + breadth); //check not outside of map - for load save game ASSERT_OR_RETURN(NULL, mapX + width < mapWidth, "x coord bigger than map width - %s, id = %d", getName(psFeature->psStats->pName), psFeature->id); ASSERT_OR_RETURN(NULL, mapY + breadth < mapHeight, "y coord bigger than map height - %s, id = %d", getName(psFeature->psStats->pName), psFeature->id); if (width != psStats->baseWidth && breadth != psStats->baseBreadth) { if (TileHasFeature(psTile)) { FEATURE *psBlock = (FEATURE *)psTile->psObject; debug(LOG_ERROR, "%s(%d) already placed at (%d+%d, %d+%d) when trying to place %s(%d) at (%d+%d, %d+%d) - removing it", getName(psBlock->psStats->pName), psBlock->id, map_coord(psBlock->pos.x), psBlock->psStats->baseWidth, map_coord(psBlock->pos.y), psBlock->psStats->baseBreadth, getName(psFeature->psStats->pName), psFeature->id, mapX, psStats->baseWidth, mapY, psStats->baseBreadth); removeFeature(psBlock); } psTile->psObject = (BASE_OBJECT*)psFeature; // if it's a tall feature then flag it in the map. if (psFeature->sDisplay.imd->max.y > TALLOBJECT_YMAX) { auxSetBlocking(mapX + width, mapY + breadth, AIR_BLOCKED); } if (psStats->subType != FEAT_GEN_ARTE && psStats->subType != FEAT_OIL_DRUM && psStats->subType != FEAT_BUILD_WRECK) { auxSetBlocking(mapX + width, mapY + breadth, FEATURE_BLOCKED); } } if( (!psStats->tileDraw) && (FromSave == false) ) { psTile->height = height; } } } psFeature->pos.z = map_TileHeight(mapX,mapY);//jps 18july97 // // set up the imd for the feature // if(psFeature->psStats->subType==FEAT_BUILD_WRECK) // { // psFeature->sDisplay.imd = wreckageImds[rand()%MAX_WRECKAGE]; // } // else // { // psFeature->sDisplay.imd = psStats->psImd; // } return psFeature; }
/* Create a feature on the map */ FEATURE * buildFeature(FEATURE_STATS *psStats, UDWORD x, UDWORD y,bool FromSave) { UDWORD mapX, mapY; UDWORD width,breadth, foundationMin,foundationMax, height; UDWORD startX,startY,max,min; //try and create the Feature FEATURE *psFeature = new FEATURE(generateSynchronisedObjectId(), psStats); if (psFeature == NULL) { debug(LOG_WARNING, "Feature couldn't be built."); return NULL; } // features are not in the cluster system // this will cause an assert when they still end up there psFeature->cluster = ~0; //add the feature to the list - this enables it to be drawn whilst being built addFeature(psFeature); // get the terrain average height startX = map_coord(x); startY = map_coord(y); foundationMin = TILE_MAX_HEIGHT; foundationMax = TILE_MIN_HEIGHT; for (breadth = 0; breadth < psStats->baseBreadth; breadth++) { for (width = 0; width < psStats->baseWidth; width++) { getTileMaxMin(startX + width, startY + breadth, &max, &min); if (foundationMin > min) { foundationMin = min; } if (foundationMax < max) { foundationMax = max; } } } //return the average of max/min height height = (foundationMin + foundationMax) / 2; // snap the coords to a tile if (!FromSave) { x = (x & ~TILE_MASK) + psStats->baseWidth %2 * TILE_UNITS/2; y = (y & ~TILE_MASK) + psStats->baseBreadth%2 * TILE_UNITS/2; } else { if ((x & TILE_MASK) != psStats->baseWidth %2 * TILE_UNITS/2 || (y & TILE_MASK) != psStats->baseBreadth%2 * TILE_UNITS/2) { debug(LOG_WARNING, "Feature not aligned. position (%d,%d), size (%d,%d)", x, y, psStats->baseWidth, psStats->baseBreadth); } } psFeature->pos.x = x; psFeature->pos.y = y; if (psStats->subType == FEAT_TREE) { psFeature->rot.direction = gameRand(DEG_360); } else { psFeature->rot.direction = 0; } psFeature->body = psStats->body; psFeature->inFire = false; objSensorCache((BASE_OBJECT *)psFeature, NULL); objEcmCache((BASE_OBJECT *)psFeature, NULL); // it has never been drawn psFeature->sDisplay.frameNumber = 0; for (int j = 0; j < WC_NUM_WEAPON_CLASSES; j++) { psFeature->armour[j] = psFeature->psStats->armourValue; } memset(psFeature->seenThisTick, 0, sizeof(psFeature->seenThisTick)); memset(psFeature->visible, 0, sizeof(psFeature->visible)); //load into the map data mapX = map_coord(x) - psStats->baseWidth/2; mapY = map_coord(y) - psStats->baseBreadth/2; // set up the imd for the feature psFeature->sDisplay.imd = psStats->psImd; ASSERT_OR_RETURN(NULL, psFeature->sDisplay.imd, "No IMD for feature"); // make sure we have an imd. for (width = 0; width < psStats->baseWidth; width++) { for (breadth = 0; breadth < psStats->baseBreadth; breadth++) { MAPTILE *psTile = mapTile(mapX + width, mapY + breadth); //check not outside of map - for load save game ASSERT_OR_RETURN(NULL, mapX + width < mapWidth, "x coord bigger than map width - %s, id = %d", getName(psFeature->psStats->pName), psFeature->id); ASSERT_OR_RETURN(NULL, mapY + breadth < mapHeight, "y coord bigger than map height - %s, id = %d", getName(psFeature->psStats->pName), psFeature->id); if (width != psStats->baseWidth && breadth != psStats->baseBreadth) { if (TileHasFeature(psTile)) { FEATURE *psBlock = (FEATURE *)psTile->psObject; debug(LOG_ERROR, "%s(%d) already placed at (%d+%d, %d+%d) when trying to place %s(%d) at (%d+%d, %d+%d) - removing it", getName(psBlock->psStats->pName), psBlock->id, map_coord(psBlock->pos.x), psBlock->psStats->baseWidth, map_coord(psBlock->pos.y), psBlock->psStats->baseBreadth, getName(psFeature->psStats->pName), psFeature->id, mapX, psStats->baseWidth, mapY, psStats->baseBreadth); removeFeature(psBlock); } psTile->psObject = (BASE_OBJECT*)psFeature; // if it's a tall feature then flag it in the map. if (psFeature->sDisplay.imd->max.y > TALLOBJECT_YMAX) { auxSetBlocking(mapX + width, mapY + breadth, AIR_BLOCKED); } if (psStats->subType != FEAT_GEN_ARTE && psStats->subType != FEAT_OIL_DRUM) { auxSetBlocking(mapX + width, mapY + breadth, FEATURE_BLOCKED); } } if( (!psStats->tileDraw) && (FromSave == false) ) { psTile->height = height; } } } psFeature->pos.z = map_TileHeight(mapX,mapY);//jps 18july97 return psFeature; }
/* Create a feature on the map */ FEATURE * buildFeature(FEATURE_STATS *psStats, UDWORD x, UDWORD y,bool FromSave) { //try and create the Feature FEATURE *psFeature = new FEATURE(generateSynchronisedObjectId(), psStats); if (psFeature == NULL) { debug(LOG_WARNING, "Feature couldn't be built."); return NULL; } // features are not in the cluster system // this will cause an assert when they still end up there psFeature->cluster = ~0; //add the feature to the list - this enables it to be drawn whilst being built addFeature(psFeature); // snap the coords to a tile if (!FromSave) { x = (x & ~TILE_MASK) + psStats->baseWidth %2 * TILE_UNITS/2; y = (y & ~TILE_MASK) + psStats->baseBreadth%2 * TILE_UNITS/2; } else { if ((x & TILE_MASK) != psStats->baseWidth %2 * TILE_UNITS/2 || (y & TILE_MASK) != psStats->baseBreadth%2 * TILE_UNITS/2) { debug(LOG_WARNING, "Feature not aligned. position (%d,%d), size (%d,%d)", x, y, psStats->baseWidth, psStats->baseBreadth); } } psFeature->pos.x = x; psFeature->pos.y = y; StructureBounds b = getStructureBounds(psFeature); // get the terrain average height int foundationMin = INT32_MAX; int foundationMax = INT32_MIN; for (int breadth = 0; breadth <= b.size.y; ++breadth) { for (int width = 0; width <= b.size.x; ++width) { int h = map_TileHeight(b.map.x + width, b.map.y + breadth); foundationMin = std::min(foundationMin, h); foundationMax = std::max(foundationMax, h); } } //return the average of max/min height int height = (foundationMin + foundationMax) / 2; if (psStats->subType == FEAT_TREE) { psFeature->rot.direction = gameRand(DEG_360); } else { psFeature->rot.direction = 0; } psFeature->body = psStats->body; psFeature->periodicalDamageStart = 0; psFeature->periodicalDamage = 0; // it has never been drawn psFeature->sDisplay.frameNumber = 0; memset(psFeature->seenThisTick, 0, sizeof(psFeature->seenThisTick)); memset(psFeature->visible, 0, sizeof(psFeature->visible)); // set up the imd for the feature psFeature->sDisplay.imd = psStats->psImd; ASSERT_OR_RETURN(NULL, psFeature->sDisplay.imd, "No IMD for feature"); // make sure we have an imd. for (int breadth = 0; breadth < b.size.y; ++breadth) { for (int width = 0; width < b.size.x; ++width) { MAPTILE *psTile = mapTile(b.map.x + width, b.map.y + breadth); //check not outside of map - for load save game ASSERT_OR_RETURN(NULL, b.map.x + width < mapWidth, "x coord bigger than map width - %s, id = %d", getName(psFeature->psStats), psFeature->id); ASSERT_OR_RETURN(NULL, b.map.y + breadth < mapHeight, "y coord bigger than map height - %s, id = %d", getName(psFeature->psStats), psFeature->id); if (width != psStats->baseWidth && breadth != psStats->baseBreadth) { if (TileHasFeature(psTile)) { FEATURE *psBlock = (FEATURE *)psTile->psObject; debug(LOG_ERROR, "%s(%d) already placed at (%d+%d, %d+%d) when trying to place %s(%d) at (%d+%d, %d+%d) - removing it", getName(psBlock->psStats), psBlock->id, map_coord(psBlock->pos.x), psBlock->psStats->baseWidth, map_coord(psBlock->pos.y), psBlock->psStats->baseBreadth, getName(psFeature->psStats), psFeature->id, b.map.x, b.size.x, b.map.y, b.size.y); removeFeature(psBlock); } psTile->psObject = (BASE_OBJECT*)psFeature; // if it's a tall feature then flag it in the map. if (psFeature->sDisplay.imd->max.y > TALLOBJECT_YMAX) { auxSetBlocking(b.map.x + width, b.map.y + breadth, AIR_BLOCKED); } if (psStats->subType != FEAT_GEN_ARTE && psStats->subType != FEAT_OIL_DRUM) { auxSetBlocking(b.map.x + width, b.map.y + breadth, FEATURE_BLOCKED); } } if( (!psStats->tileDraw) && (FromSave == false) ) { psTile->height = height; } } } psFeature->pos.z = map_TileHeight(b.map.x, b.map.y);//jps 18july97 return psFeature; }
void shMapLevel::moveWalls (int action) { shFeature *f; int north = (1 == action or -1 == action) ? 1 : 0; int squares[20]; int n = 0; int x, y; int i, j; int seen = 0; int interrupt = 0; int heard = 0; // move the wall y = -1; for (i = 0; i < mFeatures.count (); i++) { f = mFeatures.get (i); if (shFeature::kMovingHWall != f->mType) { continue; } if (action > 0) { /* close in */ if (north and f->mMovingHWall.mBeginY < f->mMovingHWall.mEndY and f->mY < f->mMovingHWall.mEndY) { //if (Hero.canSee (f->mX, f->mY)) // setMemory (f->mX, f->mY, ' '); mVisibility[f->mX][f->mY] = 0; y = f->mY + 1; squares[n++] = f->mX; f->mY++; addMachinery (f->mX, f->mY-1); } else if (!north and f->mMovingHWall.mBeginY > f->mMovingHWall.mEndY and f->mY > f->mMovingHWall.mEndY) { //if (Hero.canSee (f->mX, f->mY)) // setMemory (f->mX, f->mY, ' '); mVisibility[f->mX][f->mY] = 0; y = f->mY - 1; squares[n++] = f->mX; f->mY--; addMachinery (f->mX, f->mY+1); } else { continue; } if (Hero.canSee (f->mX, f->mY)) { interrupt++; seen++; } else if (distance (&Hero, f->mX, f->mY) < 100) { heard++; } } else if (action < 0) { /* reset */ int oldy = f->mY; if (north and f->mMovingHWall.mBeginY < f->mMovingHWall.mEndY and f->mY > f->mMovingHWall.mBeginY) { y = f->mY - 1; shFeature *machinery = getFeature (f->mX, y); if (machinery) removeFeature (machinery); f->mY--; } else if (!north and f->mMovingHWall.mBeginY > f->mMovingHWall.mEndY and f->mY < f->mMovingHWall.mBeginY) { y = f->mY + 1; shFeature *machinery = getFeature (f->mX, y); if (machinery) removeFeature (machinery); f->mY++; } else { continue; } if (Hero.canSee (f->mX, oldy)) interrupt++; } } if (!Hero.getStoryFlag ("walls moving")) { if (seen) { I->p ("The walls are moving!"); Hero.setStoryFlag ("walls moving", 1); } else if (heard and !Hero.getStoryFlag ("walls heard")) { I->p ("You hear a loud rumbling!"); Hero.setStoryFlag ("walls heard", 1); } } // displace objects and creatures if (n) { shuffle (squares, n, sizeof(int)); for (i = 0; i < n; i++) { x = squares[i]; shObjectVector *v = getObjects (x, y); if (v) { int y2 = north ? y + 1 : y - 1; int safe = !isObstacle (x, y2); for (j = 0; j < v->count (); j++) { shObject *obj = v->get (j); if (safe) { putObject (obj, x, y2); } else { delete obj; } } if (Hero.mX == x and Hero.mY == y2) { I->p ("%s pushed into your vicinity.", v->count () > 1 ? "Some objects are" : "An object is"); } delete v; setObjects (x, y, NULL); } shCreature *c = getCreature (x, y); if (c) { if (c->mZ < 0) { if (c->isHero ()) { I->p ("You are sealed below the moving wall!"); I->p ("That's not supposed to be possible!"); I->p ("Please send me a bug report! -cyrus"); } } else { pushCreature (c, north ? kSouth : kNorth); } } } } if (interrupt) Hero.interrupt (); }
/* Remove a Feature and free it's memory */ bool destroyFeature(FEATURE *psDel, unsigned impactTime) { UDWORD widthScatter, breadthScatter, heightScatter, i; EFFECT_TYPE explosionSize; Vector3i pos; ASSERT_OR_RETURN(false, psDel != NULL, "Invalid feature pointer"); ASSERT(gameTime - deltaGameTime < impactTime, "Expected %u < %u, gameTime = %u, bad impactTime", gameTime - deltaGameTime, impactTime, gameTime); /* Only add if visible and damageable*/ if (psDel->visible[selectedPlayer] && psDel->psStats->damageable) { /* Set off a destruction effect */ /* First Explosions */ widthScatter = TILE_UNITS / 2; breadthScatter = TILE_UNITS / 2; heightScatter = TILE_UNITS / 4; //set which explosion to use based on size of feature if (psDel->psStats->baseWidth < 2 && psDel->psStats->baseBreadth < 2) { explosionSize = EXPLOSION_TYPE_SMALL; } else if (psDel->psStats->baseWidth < 3 && psDel->psStats->baseBreadth < 3) { explosionSize = EXPLOSION_TYPE_MEDIUM; } else { explosionSize = EXPLOSION_TYPE_LARGE; } for (i = 0; i < 4; i++) { pos.x = psDel->pos.x + widthScatter - rand() % (2 * widthScatter); pos.z = psDel->pos.y + breadthScatter - rand() % (2 * breadthScatter); pos.y = psDel->pos.z + 32 + rand() % heightScatter; addEffect(&pos, EFFECT_EXPLOSION, explosionSize, false, NULL, 0, impactTime); } if (psDel->psStats->subType == FEAT_SKYSCRAPER) { pos.x = psDel->pos.x; pos.z = psDel->pos.y; pos.y = psDel->pos.z; addEffect(&pos, EFFECT_DESTRUCTION, DESTRUCTION_TYPE_SKYSCRAPER, true, psDel->sDisplay.imd, 0, impactTime); initPerimeterSmoke(psDel->sDisplay.imd, pos); shakeStart(250); // small shake } /* Then a sequence of effects */ pos.x = psDel->pos.x; pos.z = psDel->pos.y; pos.y = map_Height(pos.x, pos.z); addEffect(&pos, EFFECT_DESTRUCTION, DESTRUCTION_TYPE_FEATURE, false, NULL, 0, impactTime); //play sound // ffs gj if (psDel->psStats->subType == FEAT_SKYSCRAPER) { audio_PlayStaticTrack(psDel->pos.x, psDel->pos.y, ID_SOUND_BUILDING_FALL); } else { audio_PlayStaticTrack(psDel->pos.x, psDel->pos.y, ID_SOUND_EXPLOSION); } } if (psDel->psStats->subType == FEAT_SKYSCRAPER) { // ----- Flip all the tiles under the skyscraper to a rubble tile // smoke effect should disguise this happening StructureBounds b = getStructureBounds(psDel); for (int breadth = 0; breadth < b.size.y; ++breadth) { for (int width = 0; width < b.size.x; ++width) { MAPTILE *psTile = mapTile(b.map.x + width, b.map.y + breadth); // stops water texture changing for underwater features if (terrainType(psTile) != TER_WATER) { if (terrainType(psTile) != TER_CLIFFFACE) { /* Clear feature bits */ psTile->texture = TileNumber_texture(psTile->texture) | RUBBLE_TILE; auxClearBlocking(b.map.x + width, b.map.y + breadth, AUXBITS_ALL); } else { /* This remains a blocking tile */ psTile->psObject = NULL; auxClearBlocking(b.map.x + width, b.map.y + breadth, AIR_BLOCKED); // Shouldn't remain blocking for air units, however. psTile->texture = TileNumber_texture(psTile->texture) | BLOCKING_RUBBLE_TILE; } } } } } removeFeature(psDel); psDel->died = impactTime; return true; }