747 lines
19 KiB
C
747 lines
19 KiB
C
/*
|
|
This file is part of Warzone 2100.
|
|
Copyright (C) 1999-2004 Eidos Interactive
|
|
Copyright (C) 2005-2007 Warzone Resurrection Project
|
|
|
|
Warzone 2100 is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Warzone 2100 is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Warzone 2100; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
/*
|
|
* Feature.c
|
|
*
|
|
* Load feature stats
|
|
*/
|
|
#include "lib/framework/frame.h"
|
|
#include "lib/framework/frameresource.h"
|
|
#include "lib/framework/strres.h"
|
|
|
|
#include "lib/gamelib/gtime.h"
|
|
#include "lib/sound/audio.h"
|
|
#include "lib/sound/audio_id.h"
|
|
|
|
#include "feature.h"
|
|
#include "map.h"
|
|
#include "hci.h"
|
|
#include "power.h"
|
|
#include "objects.h"
|
|
#include "display.h"
|
|
#include "console.h"
|
|
#include "order.h"
|
|
#include "structure.h"
|
|
#include "miscimd.h"
|
|
#include "anim_id.h"
|
|
#include "visibility.h"
|
|
#include "text.h"
|
|
#include "effects.h"
|
|
#include "geometry.h"
|
|
#include "scores.h"
|
|
#include "combat.h"
|
|
#include "multiplay.h"
|
|
#include "advvis.h"
|
|
|
|
#include "mapgrid.h"
|
|
#include "display3d.h"
|
|
|
|
|
|
/* The statistics for the features */
|
|
FEATURE_STATS *asFeatureStats;
|
|
UDWORD numFeatureStats;
|
|
|
|
//Value is stored for easy access to this feature in destroyDroid()/destroyStruct()
|
|
UDWORD oilResFeature;
|
|
|
|
/* other house droid to add */
|
|
#define DROID_TEMPLINDEX 0
|
|
#define DROID_X (TILE_UNITS * 37 + TILE_UNITS/2)
|
|
#define DROID_Y (TILE_UNITS + TILE_UNITS/2)
|
|
#define DROID_TARX 37
|
|
#define DROID_TARY 42
|
|
|
|
//specifies how far round (in tiles) a constructor droid sound look for more wreckage
|
|
#define WRECK_SEARCH 3
|
|
|
|
struct featureTypeMap
|
|
{
|
|
const char *typeStr;
|
|
FEATURE_TYPE type;
|
|
};
|
|
|
|
static const struct featureTypeMap map[] =
|
|
{
|
|
{ "PROPULSION_TYPE_HOVER WRECK", FEAT_HOVER },
|
|
{ "TANK WRECK", FEAT_TANK },
|
|
{ "GENERIC ARTEFACT", FEAT_GEN_ARTE },
|
|
{ "OIL RESOURCE", FEAT_OIL_RESOURCE },
|
|
{ "BOULDER", FEAT_BOULDER },
|
|
{ "VEHICLE", FEAT_VEHICLE },
|
|
{ "DROID WRECK", FEAT_DROID },
|
|
{ "BUILDING WRECK", FEAT_BUILD_WRECK },
|
|
{ "BUILDING", FEAT_BUILDING },
|
|
{ "OIL DRUM", FEAT_OIL_DRUM },
|
|
{ "TREE", FEAT_TREE },
|
|
{ "SKYSCRAPER", FEAT_SKYSCRAPER }
|
|
};
|
|
|
|
|
|
void featureInitVars(void)
|
|
{
|
|
asFeatureStats = NULL;
|
|
numFeatureStats = 0;
|
|
oilResFeature = 0;
|
|
}
|
|
|
|
static void featureType(FEATURE_STATS* psFeature, const char *pType)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < sizeof(map) / sizeof(map[0]); i++)
|
|
{
|
|
if (strcmp(pType, map[i].typeStr) == 0)
|
|
{
|
|
psFeature->subType = map[i].type;
|
|
return;
|
|
}
|
|
}
|
|
|
|
ASSERT(false, "featureType: Unknown feature type");
|
|
}
|
|
|
|
/* Load the feature stats */
|
|
BOOL loadFeatureStats(const char *pFeatureData, UDWORD bufferSize)
|
|
{
|
|
FEATURE_STATS *psFeature;
|
|
unsigned int i;
|
|
char featureName[MAX_STR_LENGTH], GfxFile[MAX_STR_LENGTH],
|
|
type[MAX_STR_LENGTH];
|
|
|
|
numFeatureStats = numCR(pFeatureData, bufferSize);
|
|
|
|
asFeatureStats = (FEATURE_STATS*)malloc(sizeof(FEATURE_STATS) * numFeatureStats);
|
|
|
|
if (asFeatureStats == NULL)
|
|
{
|
|
debug( LOG_ERROR, "Feature Stats - Out of memory" );
|
|
abort();
|
|
return false;
|
|
}
|
|
|
|
psFeature = asFeatureStats;
|
|
for (i = 0; i < numFeatureStats; i++)
|
|
{
|
|
UDWORD Width, Breadth;
|
|
|
|
memset(psFeature, 0, sizeof(FEATURE_STATS));
|
|
|
|
featureName[0] = '\0';
|
|
GfxFile[0] = '\0';
|
|
type[0] = '\0';
|
|
|
|
//read the data into the storage - the data is delimeted using comma's
|
|
sscanf(pFeatureData,"%[^','],%d,%d,%d,%d,%d,%[^','],%[^','],%d,%d,%d",
|
|
featureName, &Width, &Breadth,
|
|
&psFeature->damageable, &psFeature->armourValue, &psFeature->body,
|
|
GfxFile, type, &psFeature->tileDraw, &psFeature->allowLOS,
|
|
&psFeature->visibleAtStart);
|
|
|
|
// These are now only 16 bits wide - so we need to copy them
|
|
psFeature->baseWidth = (UWORD)Width;
|
|
psFeature->baseBreadth = (UWORD)Breadth;
|
|
|
|
psFeature->pName = allocateName(featureName);
|
|
if (!psFeature->pName)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//determine the feature type
|
|
featureType(psFeature, type);
|
|
|
|
//and the oil resource - assumes only one!
|
|
if (psFeature->subType == FEAT_OIL_RESOURCE)
|
|
{
|
|
oilResFeature = i;
|
|
}
|
|
|
|
//get the IMD for the feature
|
|
psFeature->psImd = (iIMDShape *) resGetData("IMD", GfxFile);
|
|
if (psFeature->psImd == NULL)
|
|
{
|
|
debug( LOG_ERROR, "Cannot find the feature PIE for record %s", getName( psFeature->pName ) );
|
|
abort();
|
|
return false;
|
|
}
|
|
|
|
psFeature->ref = REF_FEATURE_START + i;
|
|
|
|
//increment the pointer to the start of the next record
|
|
pFeatureData = strchr(pFeatureData,'\n') + 1;
|
|
//increment the list to the start of the next storage block
|
|
psFeature++;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/* Release the feature stats memory */
|
|
void featureStatsShutDown(void)
|
|
{
|
|
if(numFeatureStats)
|
|
{
|
|
free(asFeatureStats);
|
|
asFeatureStats = NULL;
|
|
}
|
|
}
|
|
|
|
/** Deals with damage to a feature
|
|
* \param psFeature feature to deal damage to
|
|
* \param damage amount of damage to deal
|
|
* \param weaponClass,weaponSubClass the class and subclass of the weapon that deals the damage
|
|
* \param impactSide the side/directon on which the feature is hit
|
|
* \return < 0 when the dealt damage destroys the feature, > 0 when the feature survives
|
|
*/
|
|
float featureDamage(FEATURE *psFeature, UDWORD damage, UDWORD weaponClass, UDWORD weaponSubClass, HIT_SIDE impactSide)
|
|
{
|
|
float relativeDamage;
|
|
|
|
ASSERT(psFeature != NULL, "featureDamage: Invalid feature pointer");
|
|
|
|
debug(LOG_ATTACK, "featureDamage(%d): body %d armour %d damage: %d",
|
|
psFeature->id, psFeature->body, psFeature->armour[impactSide][weaponClass], damage);
|
|
|
|
relativeDamage = objDamage((BASE_OBJECT *)psFeature, damage, psFeature->psStats->body, weaponClass, weaponSubClass, impactSide);
|
|
|
|
// If the shell did sufficient damage to destroy the feature
|
|
if (relativeDamage < 0.0f)
|
|
{
|
|
destroyFeature(psFeature);
|
|
return relativeDamage * -1.0f;
|
|
}
|
|
else
|
|
{
|
|
return relativeDamage;
|
|
}
|
|
}
|
|
|
|
|
|
/* 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)
|
|
{
|
|
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;
|
|
|
|
if(FromSave == true) {
|
|
psFeature->pos.x = (UWORD)x;
|
|
psFeature->pos.y = (UWORD)y;
|
|
} else {
|
|
psFeature->pos.x = (UWORD)((x & (~TILE_MASK)) + psStats->baseWidth * TILE_UNITS / 2);
|
|
psFeature->pos.y = (UWORD)((y & (~TILE_MASK)) + psStats->baseBreadth * TILE_UNITS / 2);
|
|
}
|
|
|
|
/* Dump down the building wrecks at random angles - still looks shit though */
|
|
if(psStats->subType == FEAT_BUILD_WRECK)
|
|
{
|
|
psFeature->direction = rand() % 360;
|
|
}
|
|
else if(psStats->subType == FEAT_TREE)
|
|
{
|
|
psFeature->direction = rand() % 360;
|
|
}
|
|
else
|
|
{
|
|
psFeature->direction = 0;
|
|
}
|
|
//psFeature->damage = featureDamage;
|
|
psFeature->selected = false;
|
|
psFeature->psStats = psStats;
|
|
//psFeature->subType = psStats->subType;
|
|
psFeature->body = psStats->body;
|
|
psFeature->player = MAX_PLAYERS+1; //set the player out of range to avoid targeting confusions
|
|
psFeature->sensorRange = 0;
|
|
psFeature->sensorPower = 0;
|
|
psFeature->ECMMod = 0;
|
|
psFeature->bTargetted = false;
|
|
psFeature->timeLastHit = 0;
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
for(i=0; i<MAX_PLAYERS; i++)
|
|
{
|
|
psFeature->visible[i] = 0;//vis;
|
|
}
|
|
//load into the map data
|
|
|
|
if(FromSave) {
|
|
mapX = map_coord(x) - psStats->baseWidth / 2;
|
|
mapY = map_coord(y) - psStats->baseBreadth / 2;
|
|
} else {
|
|
mapX = map_coord(x);
|
|
mapY = map_coord(y);
|
|
}
|
|
|
|
// 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(psFeature->sDisplay.imd); // 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( (mapX+width) < mapWidth,
|
|
"x coord bigger than map width - %s, id = %d",
|
|
getName(psFeature->psStats->pName), psFeature->id );
|
|
ASSERT( (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)
|
|
{
|
|
SET_TILE_TALLSTRUCTURE(psTile);
|
|
}
|
|
|
|
if (psStats->subType == FEAT_GEN_ARTE || psStats->subType == FEAT_OIL_DRUM || psStats->subType == FEAT_BUILD_WRECK)// they're there - just can see me
|
|
{
|
|
SET_TILE_NOTBLOCKING(psTile);
|
|
}
|
|
}
|
|
|
|
if( (!psStats->tileDraw) && (FromSave == false) )
|
|
{
|
|
psTile->height = (UBYTE)(height / ELEVATION_SCALE);
|
|
}
|
|
}
|
|
}
|
|
psFeature->pos.z = map_TileHeight(mapX,mapY);//jps 18july97
|
|
|
|
//store the time it was built for removing wrecked droids/structures
|
|
psFeature->startTime = gameTime;
|
|
|
|
// // 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;
|
|
// }
|
|
|
|
// add the feature to the grid
|
|
gridAddObject((BASE_OBJECT *)psFeature);
|
|
|
|
return psFeature;
|
|
}
|
|
|
|
|
|
/* Release the resources associated with a feature */
|
|
void featureRelease(FEATURE *psFeature)
|
|
{
|
|
gridRemoveObject((BASE_OBJECT *)psFeature);
|
|
}
|
|
|
|
|
|
/* Update routine for features */
|
|
void featureUpdate(FEATURE *psFeat)
|
|
{
|
|
// if(getRevealStatus())
|
|
// {
|
|
// update the visibility for the feature
|
|
processVisibility((BASE_OBJECT *)psFeat);
|
|
// }
|
|
|
|
switch (psFeat->psStats->subType)
|
|
{
|
|
case FEAT_DROID:
|
|
case FEAT_BUILD_WRECK:
|
|
// //kill off wrecked droids and structures after 'so' long
|
|
// if ((gameTime - psFeat->startTime) > WRECK_LIFETIME)
|
|
// {
|
|
destroyFeature(psFeat); // get rid of the now!!!
|
|
// }
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
// free up a feature with no visual effects
|
|
void removeFeature(FEATURE *psDel)
|
|
{
|
|
UDWORD mapX, mapY, width,breadth, player;
|
|
MESSAGE *psMessage;
|
|
Vector3i pos;
|
|
|
|
ASSERT( psDel != NULL,
|
|
"removeFeature: invalid feature pointer\n" );
|
|
|
|
if (psDel->died)
|
|
{
|
|
// feature has already been killed, quit
|
|
ASSERT( false,
|
|
"removeFeature: feature already dead" );
|
|
return;
|
|
}
|
|
|
|
|
|
if(bMultiPlayer && !ingame.localJoiningInProgress)
|
|
{
|
|
SendDestroyFeature(psDel); // inform other players of destruction
|
|
}
|
|
|
|
|
|
//remove from the map data
|
|
mapX = map_coord(psDel->pos.x - psDel->psStats->baseWidth * TILE_UNITS / 2);
|
|
mapY = map_coord(psDel->pos.y - psDel->psStats->baseBreadth * TILE_UNITS / 2);
|
|
for (width = 0; width < psDel->psStats->baseWidth; width++)
|
|
{
|
|
for (breadth = 0; breadth < psDel->psStats->baseBreadth; breadth++)
|
|
{
|
|
MAPTILE *psTile = mapTile(mapX + width, mapY + breadth);
|
|
|
|
psTile->psObject = NULL;
|
|
|
|
CLEAR_TILE_TALLSTRUCTURE(psTile);
|
|
CLEAR_TILE_NOTBLOCKING(psTile);
|
|
}
|
|
}
|
|
|
|
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))
|
|
{
|
|
// have to check all players cos if you cheat you'll get em.
|
|
for (player=0; player<MAX_PLAYERS; player ++)
|
|
{
|
|
//see if there is a proximity message FOR THE SELECTED PLAYER at this location
|
|
psMessage = findMessage((MSG_VIEWDATA *)psDel, MSG_PROXIMITY, selectedPlayer);
|
|
while (psMessage)
|
|
{
|
|
removeMessage(psMessage, selectedPlayer);
|
|
psMessage = findMessage((MSG_VIEWDATA *)psDel, MSG_PROXIMITY, player);
|
|
}
|
|
}
|
|
}
|
|
|
|
// remove the feature from the grid
|
|
gridRemoveObject((BASE_OBJECT *)psDel);
|
|
|
|
killFeature(psDel);
|
|
}
|
|
|
|
/* Remove a Feature and free it's memory */
|
|
void destroyFeature(FEATURE *psDel)
|
|
{
|
|
UDWORD widthScatter,breadthScatter,heightScatter, i;
|
|
EFFECT_TYPE explosionSize;
|
|
Vector3i pos;
|
|
UDWORD width,breadth;
|
|
UDWORD mapX,mapY;
|
|
UDWORD texture;
|
|
|
|
ASSERT( psDel != NULL,
|
|
"destroyFeature: invalid feature pointer\n" );
|
|
|
|
/* 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->sDisplay.imd->pos.ymax>300) // WARNING - STATS CHANGE NEEDED!!!!!!!!!!!
|
|
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.x,pos.y,pos.z);
|
|
|
|
// ----- 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 * TILE_UNITS / 2);
|
|
mapY = map_coord(psDel->pos.y - psDel->psStats->baseBreadth * TILE_UNITS / 2);
|
|
// if(psDel->sDisplay.imd->pos.ymax>300)
|
|
if (psDel->psStats->subType == FEAT_SKYSCRAPER)
|
|
{
|
|
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->psObject = NULL;
|
|
texture = TileNumber_texture(psTile->texture) | RUBBLE_TILE;
|
|
psTile->texture = (UWORD)texture;
|
|
}
|
|
else
|
|
{
|
|
/* This remains a blocking tile */
|
|
psTile->psObject = NULL;
|
|
texture = TileNumber_texture(psTile->texture) | BLOCKING_RUBBLE_TILE;
|
|
psTile->texture = (UWORD)texture;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// -------
|
|
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 );
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------------------
|
|
|
|
removeFeature(psDel);
|
|
}
|
|
|
|
|
|
SDWORD getFeatureStatFromName( const char *pName )
|
|
{
|
|
unsigned int inc;
|
|
FEATURE_STATS *psStat;
|
|
|
|
for (inc = 0; inc < numFeatureStats; inc++)
|
|
{
|
|
psStat = &asFeatureStats[inc];
|
|
if (!strcmp(psStat->pName, pName))
|
|
{
|
|
return inc;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
/*looks around the given droid to see if there is any building
|
|
wreckage to clear*/
|
|
FEATURE * checkForWreckage(DROID *psDroid)
|
|
{
|
|
FEATURE *psFeature;
|
|
UDWORD startX, startY, incX, incY;
|
|
SDWORD x=0, y=0;
|
|
|
|
startX = map_coord(psDroid->pos.x);
|
|
startY = map_coord(psDroid->pos.y);
|
|
|
|
//look around the droid - max 2 tiles distance
|
|
for (incX = 1, incY = 1; incX < WRECK_SEARCH; incX++, incY++)
|
|
{
|
|
/* across the top */
|
|
y = startY - incY;
|
|
for(x = startX - incX; x < (SDWORD)(startX + incX); x++)
|
|
{
|
|
if(TileHasFeature(mapTile(x,y)))
|
|
{
|
|
psFeature = getTileFeature(x, y);
|
|
if(psFeature && psFeature->psStats->subType == FEAT_BUILD_WRECK)
|
|
{
|
|
return psFeature;
|
|
}
|
|
}
|
|
}
|
|
/* the right */
|
|
x = startX + incX;
|
|
for(y = startY - incY; y < (SDWORD)(startY + incY); y++)
|
|
{
|
|
if(TileHasFeature(mapTile(x,y)))
|
|
{
|
|
psFeature = getTileFeature(x, y);
|
|
if(psFeature && psFeature->psStats->subType == FEAT_BUILD_WRECK)
|
|
{
|
|
return psFeature;
|
|
}
|
|
}
|
|
}
|
|
/* across the bottom*/
|
|
y = startY + incY;
|
|
for(x = startX + incX; x > (SDWORD)(startX - incX); x--)
|
|
{
|
|
if(TileHasFeature(mapTile(x,y)))
|
|
{
|
|
psFeature = getTileFeature(x, y);
|
|
if(psFeature && psFeature->psStats->subType == FEAT_BUILD_WRECK)
|
|
{
|
|
return psFeature;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* the left */
|
|
x = startX - incX;
|
|
for(y = startY + incY; y > (SDWORD)(startY - incY); y--)
|
|
{
|
|
if(TileHasFeature(mapTile(x,y)))
|
|
{
|
|
psFeature = getTileFeature(x, y);
|
|
if(psFeature && psFeature->psStats->subType == FEAT_BUILD_WRECK)
|
|
{
|
|
return psFeature;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|