// free up a feature with no visual effects bool removeFeature(FEATURE *psDel) { MESSAGE *psMessage; Vector3i pos; ASSERT_OR_RETURN(false, psDel != NULL, "Invalid feature pointer"); ASSERT_OR_RETURN(false, !psDel->died, "Feature already dead"); //remove from the map data StructureBounds b = getStructureBounds(psDel); for (int breadth = 0; breadth < b.size.y; ++breadth) { for (int width = 0; width < b.size.x; ++width) { if (tileOnMap(b.map.x + width, b.map.y + breadth)) { MAPTILE *psTile = mapTile(b.map.x + width, b.map.y + breadth); if (psTile->psObject == psDel) { psTile->psObject = NULL; auxClearBlocking(b.map.x + width, b.map.y + breadth, FEATURE_BLOCKED | AIR_BLOCKED); } } } } if (psDel->psStats->subType == FEAT_GEN_ARTE || psDel->psStats->subType == FEAT_OIL_DRUM) { pos.x = psDel->pos.x; pos.z = psDel->pos.y; pos.y = map_Height(pos.x, pos.z) + 30; addEffect(&pos, EFFECT_EXPLOSION, EXPLOSION_TYPE_DISCOVERY, false, NULL, 0, gameTime - deltaGameTime + 1); if (psDel->psStats->subType == FEAT_GEN_ARTE) { scoreUpdateVar(WD_ARTEFACTS_FOUND); intRefreshScreen(); } } if (psDel->psStats->subType == FEAT_GEN_ARTE || psDel->psStats->subType == FEAT_OIL_RESOURCE) { for (unsigned player = 0; player < MAX_PLAYERS; ++player) { psMessage = findMessage((MSG_VIEWDATA *)psDel, MSG_PROXIMITY, player); while (psMessage) { removeMessage(psMessage, player); psMessage = findMessage((MSG_VIEWDATA *)psDel, MSG_PROXIMITY, player); } } } debug(LOG_DEATH, "Killing off feature %s id %d (%p)", objInfo(psDel), psDel->id, psDel); killFeature(psDel); return true; }
// free up a feature with no visual effects bool removeFeature(FEATURE *psDel) { int mapX, mapY, width, breadth, player; MESSAGE *psMessage; Vector3i pos; ASSERT_OR_RETURN(false, psDel != NULL, "Invalid feature pointer"); ASSERT_OR_RETURN(false, !psDel->died, "Feature already dead"); if(bMultiMessages && !ingame.localJoiningInProgress) { SendDestroyFeature(psDel); // inform other players of destruction return true; // Wait for our message before really destroying the feature. } //remove from the map data 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++) { if (tileOnMap(mapX + width, mapY + breadth)) { MAPTILE *psTile = mapTile(mapX + width, mapY + breadth); if (psTile->psObject == (BASE_OBJECT *)psDel) { psTile->psObject = NULL; auxClearBlocking(mapX + width, mapY + breadth, FEATURE_BLOCKED | AIR_BLOCKED); } } } } if(psDel->psStats->subType == FEAT_GEN_ARTE) { pos.x = psDel->pos.x; pos.z = psDel->pos.y; pos.y = map_Height(pos.x,pos.z); addEffect(&pos,EFFECT_EXPLOSION,EXPLOSION_TYPE_DISCOVERY,false,NULL,0); scoreUpdateVar(WD_ARTEFACTS_FOUND); intRefreshScreen(); } if (psDel->psStats->subType == FEAT_GEN_ARTE || psDel->psStats->subType == FEAT_OIL_RESOURCE) { for (player = 0; player < MAX_PLAYERS; player++) { psMessage = findMessage((MSG_VIEWDATA *)psDel, MSG_PROXIMITY, player); while (psMessage) { removeMessage(psMessage, player); psMessage = findMessage((MSG_VIEWDATA *)psDel, MSG_PROXIMITY, player); } } } killFeature(psDel); return true; }
/* 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; auxClearBlocking(mapX + width, mapY + breadth, AIR_BLOCKED); // Shouldn't remain blocking for air units, however. psTile->texture = TileNumber_texture(psTile->texture) | BLOCKING_RUBBLE_TILE; } } } } } removeFeature(psDel); return true; }