/// Set up the texture coordinates for a tile static void getTileTexCoords(Vector2f *uv, unsigned int tileNumber) { /* unmask proper values from compressed data */ const unsigned short texture = TileNumber_texture(tileNumber); const unsigned short tile = TileNumber_tile(tileNumber); /* Used to calculate texture coordinates */ const float xMult = 1.0f / TILES_IN_PAGE_COLUMN; const float yMult = 1.0f / TILES_IN_PAGE_ROW; float texsize = (float)getTextureSize(); float centertile, shiftamount, one; Vector2f sP1, sP2, sP3, sP4, sPTemp; // the decals are 128x128 (at this time), we should not go above this value. See note above if (texsize > MAX_TILE_TEXTURE_SIZE) { texsize = MAX_TILE_TEXTURE_SIZE; } centertile = 0.5f / texsize; //compute center of tile shiftamount = (texsize -1.0) / texsize; // 1 pixel border one = 1.0f / (TILES_IN_PAGE_COLUMN * texsize); // bump the texture coords, for 1 pixel border, so our range is [.5,(texsize - .5)] one += centertile * shiftamount; /* * Points for flipping the texture around if the tile is flipped or rotated * Store the source rect as four points */ sP1.x = one; sP1.y = one; sP2.x = xMult - one; sP2.y = one; sP3.x = xMult - one; sP3.y = yMult - one; sP4.x = one; sP4.y = yMult - one; if (texture & TILE_XFLIP) { sPTemp = sP1; sP1 = sP2; sP2 = sPTemp; sPTemp = sP3; sP3 = sP4; sP4 = sPTemp; } if (texture & TILE_YFLIP) { sPTemp = sP1; sP1 = sP4; sP4 = sPTemp; sPTemp = sP2; sP2 = sP3; sP3 = sPTemp; } switch ((texture & TILE_ROTMASK) >> TILE_ROTSHIFT) { case 1: sPTemp = sP1; sP1 = sP4; sP4 = sP3; sP3 = sP2; sP2 = sPTemp; break; case 2: sPTemp = sP1; sP1 = sP3; sP3 = sPTemp; sPTemp = sP4; sP4 = sP2; sP2 = sPTemp; break; case 3: sPTemp = sP1; sP1 = sP2; sP2 = sP3; sP3 = sP4; sP4 = sPTemp; break; } uv[0 + 0].x = tileTexInfo[tile].uOffset + sP1.x; uv[0 + 0].y = tileTexInfo[tile].vOffset + sP1.y; uv[0 + 2].x = tileTexInfo[tile].uOffset + sP2.x; uv[0 + 2].y = tileTexInfo[tile].vOffset + sP2.y; uv[1 + 2].x = tileTexInfo[tile].uOffset + sP3.x; uv[1 + 2].y = tileTexInfo[tile].vOffset + sP3.y; uv[1 + 0].x = tileTexInfo[tile].uOffset + sP4.x; uv[1 + 0].y = tileTexInfo[tile].vOffset + sP4.y; }
/// Set up the texture coordinates for a tile static Vector2f getTileTexCoords(Vector2f *uv, unsigned int tileNumber) { /* unmask proper values from compressed data */ const unsigned short texture = TileNumber_texture(tileNumber); const unsigned short tile = TileNumber_tile(tileNumber); /* Used to calculate texture coordinates */ const float xMult = 1.0f / TILES_IN_PAGE_COLUMN; const float yMult = 1.0f / TILES_IN_PAGE_ROW; float texsize = (float)getTextureSize(); // the decals are 128x128 (at this time), we should not go above this value. See note above if (texsize > MAX_TILE_TEXTURE_SIZE) { texsize = MAX_TILE_TEXTURE_SIZE; } const float centertile = 0.5f / texsize; // compute center of tile const float shiftamount = (texsize - 1.0) / texsize; // 1 pixel border // bump the texture coords, for 1 pixel border, so our range is [.5,(texsize - .5)] const float one = 1.0f / (TILES_IN_PAGE_COLUMN * texsize) + centertile * shiftamount; /* * Points for flipping the texture around if the tile is flipped or rotated * Store the source rect as four points */ Vector2f sP1 { one, one }; Vector2f sP2 { xMult - one, one }; Vector2f sP3 { xMult - one, yMult - one }; Vector2f sP4 { one, yMult - one }; if (texture & TILE_XFLIP) { std::swap(sP1, sP2); std::swap(sP3, sP4); } if (texture & TILE_YFLIP) { std::swap(sP1, sP4); std::swap(sP2, sP3); } Vector2f sPTemp; switch ((texture & TILE_ROTMASK) >> TILE_ROTSHIFT) { case 1: sPTemp = sP1; sP1 = sP4; sP4 = sP3; sP3 = sP2; sP2 = sPTemp; break; case 2: sPTemp = sP1; sP1 = sP3; sP3 = sPTemp; sPTemp = sP4; sP4 = sP2; sP2 = sPTemp; break; case 3: sPTemp = sP1; sP1 = sP2; sP2 = sP3; sP3 = sP4; sP4 = sPTemp; break; } const Vector2f offset { tileTexInfo[tile].uOffset, tileTexInfo[tile].vOffset }; uv[0 + 0] = offset + sP1; uv[0 + 2] = offset + sP2; uv[1 + 2] = offset + sP3; uv[1 + 0] = offset + sP4; /// Calculate the average texture coordinates of 4 points return Vector2f { (uv[0].x + uv[1].x + uv[2].x + uv[3].x) / 4, (uv[0].y + uv[1].y + uv[2].y + uv[3].y) / 4 }; }
/* 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; }
/* 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; }