Add the ability of allied players to share each others' sensors. Since iterating over all structures

by all players to see if we could use each as a sensor would be rather time consuming, I created a 
new set of lists (currently with only one member) that sorts objects by function. This way we can 
very quickly iterate over all sensors, even when there are several hundred buildings on the map. 
Closes ticket:636.


git-svn-id: https://warzone2100.svn.sourceforge.net/svnroot/warzone2100/trunk@7765 4a71c877-e1ca-e34f-864e-861f7616d084
master
Per Inge Mathisen 2009-06-17 19:51:24 +00:00 committed by Git SVN Gateway
parent 53c81cfdc9
commit 6a683536d6
6 changed files with 210 additions and 120 deletions

153
src/ai.c
View File

@ -95,6 +95,19 @@ static BOOL aiDroidHasRange(DROID *psDroid, BASE_OBJECT *psTarget, int weapon_sl
return false; return false;
} }
static BOOL aiObjHasRange(BASE_OBJECT *psObj, BASE_OBJECT *psTarget, int weapon_slot)
{
if (psObj->type == OBJ_DROID)
{
return aiDroidHasRange((DROID *)psObj, psTarget, weapon_slot);
}
else if (psObj->type == OBJ_STRUCTURE)
{
return aiStructHasRange((STRUCTURE *)psObj, psTarget, weapon_slot);
}
return false;
}
/* alliance code for ai. return true if an alliance has formed. */ /* alliance code for ai. return true if an alliance has formed. */
BOOL aiCheckAlliances(UDWORD s1,UDWORD s2) BOOL aiCheckAlliances(UDWORD s1,UDWORD s2)
{ {
@ -133,13 +146,73 @@ BOOL aiShutdown(void)
return true; return true;
} }
/** Search the global list of sensors for a possible target for psObj. */
BASE_OBJECT *aiSearchSensorTargets(BASE_OBJECT *psObj, int weapon_slot, WEAPON_STATS *psWStats)
{
int longRange = proj_GetLongRange(psWStats);
int tarDist = longRange * longRange;
int minDist = psWStats->minRange * psWStats->minRange;
BASE_OBJECT *psSensor, *psTarget = NULL;
for (psSensor = apsSensorList[0]; psSensor; psSensor = psSensor->psNextFunc)
{
BASE_OBJECT *psTemp = NULL;
bool isCB = false;
if (!aiCheckAlliances(psSensor->player, psObj->player))
{
continue;
}
else if (psSensor->type == OBJ_DROID)
{
DROID *psDroid = (DROID *)psSensor;
ASSERT_OR_RETURN(false, psDroid->droidType == DROID_SENSOR, "A non-sensor droid in a sensor list is non-sense");
psTemp = psDroid->psTarget;
isCB = cbSensorDroid(psDroid);
}
else if (psSensor->type == OBJ_STRUCTURE)
{
STRUCTURE *psCStruct = (STRUCTURE *)psSensor;
// skip incomplete structures
if (psCStruct->status != SS_BUILT)
{
continue;
}
psTemp = psCStruct->psTarget[0];
isCB = structCBSensor(psCStruct);
}
if (!psTemp || psTemp->died || !validTarget(psObj, psTemp, 0) || aiCheckAlliances(psTemp->player, psObj->player))
{
continue;
}
if (aiObjHasRange(psObj, psTemp, weapon_slot))
{
int distSq = objPosDiffSq(psTemp->pos, psObj->pos);
// Need to be in range, prefer closer targets or CB targets
if ((isCB || distSq < tarDist) && distSq > minDist)
{
tarDist = distSq;
psTarget = psTemp;
if (isCB)
{
break; // got CB target, drop everything and shoot!
}
}
}
}
return psTarget;
}
// Find the best nearest target for a droid // Find the best nearest target for a droid
// Returns integer representing target priority, -1 if failed // Returns integer representing target priority, -1 if failed
SDWORD aiBestNearestTarget(DROID *psDroid, BASE_OBJECT **ppsObj, int weapon_slot) SDWORD aiBestNearestTarget(DROID *psDroid, BASE_OBJECT **ppsObj, int weapon_slot)
{ {
UDWORD i; UDWORD i;
SDWORD bestMod,newMod,failure=-1; SDWORD bestMod = 0,newMod, failure = -1;
BASE_OBJECT *psTarget,*friendlyObj,*bestTarget,*targetInQuestion,*tempTarget; BASE_OBJECT *psTarget = NULL, *friendlyObj, *bestTarget = NULL, *targetInQuestion, *tempTarget;
BOOL electronic = false; BOOL electronic = false;
STRUCTURE *targetStructure; STRUCTURE *targetStructure;
WEAPON_EFFECT weaponEffect; WEAPON_EFFECT weaponEffect;
@ -151,23 +224,24 @@ SDWORD aiBestNearestTarget(DROID *psDroid, BASE_OBJECT **ppsObj, int weapon_slot
} }
/* Return if have no weapons */ /* Return if have no weapons */
// Watermelon:added a protection against no weapon droid 'numWeaps'
// The ai orders a non-combat droid to patrol = crash without it... // The ai orders a non-combat droid to patrol = crash without it...
if(psDroid->asWeaps[0].nStat == 0 || psDroid->numWeaps == 0) if(psDroid->asWeaps[0].nStat == 0 || psDroid->numWeaps == 0)
{ {
return failure; return failure;
} }
// Check if we have a CB target to begin with
if (!proj_Direct(asWeaponStats + psDroid->asWeaps[weapon_slot].nStat))
{
WEAPON_STATS *psWStats = psWStats = psDroid->asWeaps[weapon_slot].nStat + asWeaponStats;
bestTarget = aiSearchSensorTargets((BASE_OBJECT *)psDroid, weapon_slot, psWStats);
bestMod = targetAttackWeight(bestTarget, (BASE_OBJECT *)psDroid, weapon_slot);
}
droidGetNaybors(psDroid); droidGetNaybors(psDroid);
//weaponMod = asWeaponModifier[weaponEffect][(asPropulsionStats + ((DROID*)psObj)->asBits[COMP_PROPULSION].nStat)->propulsionType];
weaponEffect = ((WEAPON_STATS *)(asWeaponStats + psDroid->asWeaps[weapon_slot].nStat))->weaponEffect; weaponEffect = ((WEAPON_STATS *)(asWeaponStats + psDroid->asWeaps[weapon_slot].nStat))->weaponEffect;
//electronic warfare can only be used against structures at present - not any more! AB 6/11/98
electronic = electronicDroid(psDroid); electronic = electronicDroid(psDroid);
psTarget = NULL;
bestTarget = NULL;
bestMod = 0;
for (i=0; i< numNaybors; i++) for (i=0; i< numNaybors; i++)
{ {
friendlyObj = NULL; friendlyObj = NULL;
@ -567,9 +641,6 @@ static BOOL aiObjIsWall(BASE_OBJECT *psObj)
BOOL aiChooseTarget(BASE_OBJECT *psObj, BASE_OBJECT **ppsTarget, int weapon_slot, BOOL bUpdateTarget) BOOL aiChooseTarget(BASE_OBJECT *psObj, BASE_OBJECT **ppsTarget, int weapon_slot, BOOL bUpdateTarget)
{ {
BASE_OBJECT *psTarget = NULL; BASE_OBJECT *psTarget = NULL;
SDWORD xdiff,ydiff, distSq, tarDist, minDist;
BOOL bCBTower;
STRUCTURE *psCStruct;
DROID *psCommander; DROID *psCommander;
SECONDARY_STATE state; SECONDARY_STATE state;
SDWORD curTargetWeight=-1; SDWORD curTargetWeight=-1;
@ -631,7 +702,7 @@ BOOL aiChooseTarget(BASE_OBJECT *psObj, BASE_OBJECT **ppsTarget, int weapon_slot
else if (psObj->type == OBJ_STRUCTURE) else if (psObj->type == OBJ_STRUCTURE)
{ {
WEAPON_STATS *psWStats = NULL; WEAPON_STATS *psWStats = NULL;
int longRange = 0; int tarDist, longRange = 0;
BOOL bCommanderBlock = false; BOOL bCommanderBlock = false;
ASSERT(((STRUCTURE *)psObj)->asWeaps[weapon_slot].nStat > 0, "no weapons on structure"); ASSERT(((STRUCTURE *)psObj)->asWeaps[weapon_slot].nStat > 0, "no weapons on structure");
@ -669,60 +740,9 @@ BOOL aiChooseTarget(BASE_OBJECT *psObj, BASE_OBJECT **ppsTarget, int weapon_slot
// indirect fire structures use sensor towers first // indirect fire structures use sensor towers first
tarDist = longRange * longRange; tarDist = longRange * longRange;
minDist = psWStats->minRange * psWStats->minRange;
bCBTower = false;
if (psTarget == NULL && !bCommanderBlock && !proj_Direct(psWStats)) if (psTarget == NULL && !bCommanderBlock && !proj_Direct(psWStats))
{ {
for(psCStruct=apsStructLists[psObj->player]; psCStruct; psCStruct=psCStruct->psNext) psTarget = aiSearchSensorTargets(psObj, weapon_slot, psWStats);
{
// skip incomplete structures
if (psCStruct->status != SS_BUILT)
{
continue;
}
if (!bCBTower
&& structStandardSensor(psCStruct)
&& psCStruct->psTarget[0] != NULL
&& !psCStruct->psTarget[0]->died)
{
/* Check it is a valid target */
//Watermelon:Greater than 1 for now
if ( validTarget(psObj, psCStruct->psTarget[0], 0) &&
aiStructHasRange((STRUCTURE *)psObj, psCStruct->psTarget[0], weapon_slot))
{
xdiff = (SDWORD)psCStruct->psTarget[0]->pos.x - (SDWORD)psObj->pos.x;
ydiff = (SDWORD)psCStruct->psTarget[0]->pos.y - (SDWORD)psObj->pos.y;
distSq = xdiff*xdiff + ydiff*ydiff;
if ((distSq < tarDist) &&
(distSq > minDist))
{
tarDist = distSq;
psTarget = psCStruct->psTarget[0];
}
}
}
else if ((structCBSensor(psCStruct) || objRadarDetector((BASE_OBJECT *)psCStruct))
&& psCStruct->psTarget[0] != NULL
&& !psCStruct->psTarget[0]->died)
{
/* Check it is a valid target */
if ( validTarget(psObj, psCStruct->psTarget[0], 0) &&
aiStructHasRange((STRUCTURE *)psObj, psCStruct->psTarget[0], weapon_slot))
{
xdiff = (SDWORD)psCStruct->psTarget[0]->pos.x - (SDWORD)psObj->pos.x;
ydiff = (SDWORD)psCStruct->psTarget[0]->pos.y - (SDWORD)psObj->pos.y;
distSq = xdiff*xdiff + ydiff*ydiff;
if ((!bCBTower || (distSq < tarDist)) &&
(distSq > minDist))
{
tarDist = distSq;
psTarget = psCStruct->psTarget[0];
bCBTower = true;
}
}
}
}
} }
if (psTarget == NULL && !bCommanderBlock) if (psTarget == NULL && !bCommanderBlock)
@ -739,9 +759,8 @@ BOOL aiChooseTarget(BASE_OBJECT *psObj, BASE_OBJECT **ppsTarget, int weapon_slot
&& validTarget(psObj, psCurr, weapon_slot) && psCurr->visible[psObj->player]) && validTarget(psObj, psCurr, weapon_slot) && psCurr->visible[psObj->player])
{ {
// See if in sensor range and visible // See if in sensor range and visible
xdiff = psCurr->pos.x - psObj->pos.x; int distSq = objPosDiffSq(psCurr->pos, psObj->pos);
ydiff = psCurr->pos.y - psObj->pos.y;
distSq = xdiff * xdiff + ydiff * ydiff;
if (distSq < tarDist if (distSq < tarDist
|| (psTarget && psTarget->type == OBJ_STRUCTURE && ((STRUCTURE *)psTarget)->status != SS_BUILT) || (psTarget && psTarget->type == OBJ_STRUCTURE && ((STRUCTURE *)psTarget)->status != SS_BUILT)
|| (psTarget && aiObjIsWall(psTarget) && !aiObjIsWall(psCurr))) || (psTarget && aiObjIsWall(psTarget) && !aiObjIsWall(psCurr)))

View File

@ -97,9 +97,12 @@ extern BOOL aiChooseTarget(BASE_OBJECT *psObj,
/*set the droid to attack if wihin range otherwise move to target*/ /*set the droid to attack if wihin range otherwise move to target*/
extern void attackTarget(DROID *psDroid, BASE_OBJECT *psTarget); extern void attackTarget(DROID *psDroid, BASE_OBJECT *psTarget);
/* See if there is a target in range for Sensor objects*/ /** See if there is a target in range for Sensor objects. */
extern BOOL aiChooseSensorTarget(BASE_OBJECT *psObj, BASE_OBJECT **ppsTarget); extern BOOL aiChooseSensorTarget(BASE_OBJECT *psObj, BASE_OBJECT **ppsTarget);
/** See if there is a friendly sensor anywhere holding a valid target for psObj. */
BASE_OBJECT *aiSearchSensorTargets(BASE_OBJECT *psObj, int weapon_slot, WEAPON_STATS *psWStats);
/*set of rules which determine whether the weapon associated with the object /*set of rules which determine whether the weapon associated with the object
can fire on the propulsion type of the target*/ can fire on the propulsion type of the target*/
extern BOOL validTarget(BASE_OBJECT *psObject, BASE_OBJECT *psTarget, int weapon_slot); extern BOOL validTarget(BASE_OBJECT *psObject, BASE_OBJECT *psTarget, int weapon_slot);

View File

@ -78,7 +78,8 @@ typedef enum _object_type
UDWORD armour[NUM_HIT_SIDES][WC_NUM_WEAPON_CLASSES] UDWORD armour[NUM_HIT_SIDES][WC_NUM_WEAPON_CLASSES]
#define NEXTOBJ(pointerType) \ #define NEXTOBJ(pointerType) \
pointerType *psNext /**< Pointer to the next object in the list */ pointerType *psNext; /**< Pointer to the next object in the object list */ \
pointerType *psNextFunc /**< Pointer to the next object in the function list */
#define SIMPLE_ELEMENTS(pointerType) \ #define SIMPLE_ELEMENTS(pointerType) \
BASE_ELEMENTS1(pointerType); \ BASE_ELEMENTS1(pointerType); \

View File

@ -2355,6 +2355,7 @@ BOOL loadGame(const char *pGameToLoad, BOOL keepObjects, BOOL freeMem, BOOL User
apsFlagPosLists[player] = NULL; apsFlagPosLists[player] = NULL;
//clear all the messages? //clear all the messages?
apsProxDisp[player] = NULL; apsProxDisp[player] = NULL;
apsSensorList[0] = NULL;
} }
initFactoryNumFlag(); initFactoryNumFlag();
} }

View File

@ -55,12 +55,12 @@ static SDWORD factoryDeliveryPointCheck[MAX_PLAYERS][NUM_FLAG_TYPES][MAX_FACTORY
*/ */
UDWORD objID; UDWORD objID;
/* The lists of objects allocated */ /* The lists of objects allocated */
DROID *apsDroidLists[MAX_PLAYERS]; DROID *apsDroidLists[MAX_PLAYERS];
STRUCTURE *apsStructLists[MAX_PLAYERS]; STRUCTURE *apsStructLists[MAX_PLAYERS];
FEATURE *apsFeatureLists[MAX_PLAYERS]; // Only player zero is valid for FEATURE *apsFeatureLists[MAX_PLAYERS]; ///< Only player zero is valid for features. TODO: Reduce to single list.
// features BASE_OBJECT *apsSensorList[1]; ///< List of sensors in the game.
/*The list of Flag Positions allocated */ /*The list of Flag Positions allocated */
FLAG_POSITION *apsFlagPosLists[MAX_PLAYERS]; FLAG_POSITION *apsFlagPosLists[MAX_PLAYERS];
@ -245,14 +245,25 @@ static inline BASE_OBJECT* createObject(UDWORD player, OBJECT_TYPE objType)
/* Add the object to its list /* Add the object to its list
* \param list is a pointer to the object list * \param list is a pointer to the object list
*/ */
static inline void addObjectToList(BASE_OBJECT *list[], BASE_OBJECT *object) static inline void addObjectToList(BASE_OBJECT *list[], BASE_OBJECT *object, int player)
{ {
ASSERT(object != NULL, ASSERT(object != NULL, "Invalid pointer");
"addObjectToList: Invalid pointer");
// Prepend the object to the top of the list // Prepend the object to the top of the list
object->psNext = list[object->player]; object->psNext = list[player];
list[object->player] = object; list[player] = object;
}
/* Add the object to its list
* \param list is a pointer to the object list
*/
static inline void addObjectToFuncList(BASE_OBJECT *list[], BASE_OBJECT *object, int player)
{
ASSERT(object != NULL, "Invalid pointer");
// Prepend the object to the top of the list
object->psNextFunc = list[player];
list[player] = object;
} }
/* Move an object from the active list to the destroyed list. /* Move an object from the active list to the destroyed list.
@ -305,36 +316,61 @@ static inline void destroyObject(BASE_OBJECT* list[], BASE_OBJECT* object)
* \param remove is a pointer to the object to remove * \param remove is a pointer to the object to remove
* \param type is the type of the object * \param type is the type of the object
*/ */
static inline void removeObjectFromList(BASE_OBJECT *list[], BASE_OBJECT *object) static inline void removeObjectFromList(BASE_OBJECT *list[], BASE_OBJECT *object, int player)
{ {
BASE_OBJECT *psPrev = NULL, *psCurr; BASE_OBJECT *psPrev = NULL, *psCurr;
ASSERT( object != NULL, ASSERT_OR_RETURN(, object != NULL, "Invalid pointer");
"removeObjectFromList: Invalid pointer" );
// If the message to remove is the first one in the list then mark the next one as the first // If the message to remove is the first one in the list then mark the next one as the first
if (list[object->player] == object) if (list[player] == object)
{ {
list[object->player] = list[object->player]->psNext; list[player] = list[player]->psNext;
return; return;
} }
// Iterate through the list and find the item before the object to delete // Iterate through the list and find the item before the object to delete
for(psCurr = list[object->player]; (psCurr != object) && (psCurr != NULL); psCurr = psCurr->psNext) for(psCurr = list[player]; (psCurr != object) && (psCurr != NULL); psCurr = psCurr->psNext)
{ {
psPrev = psCurr; psPrev = psCurr;
} }
ASSERT( psCurr != NULL, ASSERT_OR_RETURN(, psCurr != NULL, "Object %p not found in list", object);
"removeObjectFromList: object not found in list" );
if (psCurr != NULL)
{
// Modify the "next" pointer of the previous item to // Modify the "next" pointer of the previous item to
// point to the "next" item of the item to delete. // point to the "next" item of the item to delete.
psPrev->psNext = psCurr->psNext; psPrev->psNext = psCurr->psNext;
}
/* Remove an object from the relevant function list. An object can only be in one function list at a time!
* \param list is a pointer to the object list
* \param remove is a pointer to the object to remove
* \param type is the type of the object
*/
static inline void removeObjectFromFuncList(BASE_OBJECT *list[], BASE_OBJECT *object, int player)
{
BASE_OBJECT *psPrev = NULL, *psCurr;
ASSERT_OR_RETURN(, object != NULL, "Invalid pointer");
// If the message to remove is the first one in the list then mark the next one as the first
if (list[player] == object)
{
list[player] = list[player]->psNextFunc;
return;
} }
// Iterate through the list and find the item before the object to delete
for(psCurr = list[player]; psCurr != object && psCurr != NULL; psCurr = psCurr->psNextFunc)
{
psPrev = psCurr;
}
ASSERT_OR_RETURN(, psCurr != NULL, "Object %p not found in list", object);
// Modify the "next" pointer of the previous item to
// point to the "next" item of the item to delete.
psPrev->psNextFunc = psCurr->psNextFunc;
} }
static inline BASE_OBJECT* findObjectInList(BASE_OBJECT list[], UDWORD idNum) static inline BASE_OBJECT* findObjectInList(BASE_OBJECT list[], UDWORD idNum)
@ -392,17 +428,22 @@ DROID* createDroid(UDWORD player)
} }
/* add the droid to the Droid Lists */ /* add the droid to the Droid Lists */
void addDroid(DROID *psDroidToAdd, DROID *pList[MAX_PLAYERS]) void addDroid(DROID *psDroidToAdd, DROID *pList[MAX_PLAYERS])
{ {
DROID_GROUP *psGroup; DROID_GROUP *psGroup;
addObjectToList((BASE_OBJECT**)pList, (BASE_OBJECT*)psDroidToAdd); addObjectToList((BASE_OBJECT**)pList, (BASE_OBJECT*)psDroidToAdd, psDroidToAdd->player);
/*whenever a droid gets added to a list other than the current list
its died flag is set to NOT_CURRENT_LIST so that anything targetting /* Whenever a droid gets added to a list other than the current list
it will cancel itself - HACK?!*/ * its died flag is set to NOT_CURRENT_LIST so that anything targetting
* it will cancel itself - HACK?! */
if (pList[psDroidToAdd->player] == apsDroidLists[psDroidToAdd->player]) if (pList[psDroidToAdd->player] == apsDroidLists[psDroidToAdd->player])
{ {
psDroidToAdd->died = false; psDroidToAdd->died = false;
if (psDroidToAdd->droidType == DROID_SENSOR)
{
addObjectToFuncList(apsSensorList, (BASE_OBJECT*)psDroidToAdd, 0);
}
// commanders have to get their group back // commanders have to get their group back
if (psDroidToAdd->droidType == DROID_COMMAND) if (psDroidToAdd->droidType == DROID_COMMAND)
@ -414,9 +455,9 @@ DROID* createDroid(UDWORD player)
} }
} }
} }
} }
/*destroy a droid */ /* Destroy a droid */
void killDroid(DROID *psDel) void killDroid(DROID *psDel)
{ {
int i; int i;
@ -432,6 +473,10 @@ void killDroid(DROID *psDel)
setDroidActionTarget(psDel, NULL, i); setDroidActionTarget(psDel, NULL, i);
} }
setDroidBase(psDel, NULL); setDroidBase(psDel, NULL);
if (psDel->droidType == DROID_SENSOR)
{
removeObjectFromFuncList(apsSensorList, (BASE_OBJECT*)psDel, 0);
}
destroyObject((BASE_OBJECT**)apsDroidLists, (BASE_OBJECT*)psDel); destroyObject((BASE_OBJECT**)apsDroidLists, (BASE_OBJECT*)psDel);
} }
@ -449,13 +494,17 @@ void removeDroid(DROID *psDroidToRemove, DROID *pList[MAX_PLAYERS])
"removeUnit: pointer is not a unit" ); "removeUnit: pointer is not a unit" );
ASSERT( psDroidToRemove->player < MAX_PLAYERS, ASSERT( psDroidToRemove->player < MAX_PLAYERS,
"removeUnit: invalid player for unit" ); "removeUnit: invalid player for unit" );
removeObjectFromList((BASE_OBJECT**)pList, (BASE_OBJECT*)psDroidToRemove); removeObjectFromList((BASE_OBJECT**)pList, (BASE_OBJECT*)psDroidToRemove, psDroidToRemove->player);
/* Whenever a droid is removed from the current list its died /* Whenever a droid is removed from the current list its died
* flag is set to NOT_CURRENT_LIST so that anything targetting * flag is set to NOT_CURRENT_LIST so that anything targetting
* it will cancel itself, and we know it is not really on the map. */ * it will cancel itself, and we know it is not really on the map. */
if (pList[psDroidToRemove->player] == apsDroidLists[psDroidToRemove->player]) if (pList[psDroidToRemove->player] == apsDroidLists[psDroidToRemove->player])
{ {
if (psDroidToRemove->droidType == DROID_SENSOR)
{
removeObjectFromFuncList(apsSensorList, (BASE_OBJECT*)psDroidToRemove, 0);
}
psDroidToRemove->died = NOT_CURRENT_LIST; psDroidToRemove->died = NOT_CURRENT_LIST;
} }
} }
@ -483,7 +532,12 @@ STRUCTURE* createStruct(UDWORD player)
/* add the structure to the Structure Lists */ /* add the structure to the Structure Lists */
void addStructure(STRUCTURE *psStructToAdd) void addStructure(STRUCTURE *psStructToAdd)
{ {
addObjectToList((BASE_OBJECT**)apsStructLists, (BASE_OBJECT*)psStructToAdd); addObjectToList((BASE_OBJECT**)apsStructLists, (BASE_OBJECT*)psStructToAdd, psStructToAdd->player);
if (psStructToAdd->pStructureType->pSensor
&& psStructToAdd->pStructureType->pSensor->location == LOC_TURRET)
{
addObjectToFuncList(apsSensorList, (BASE_OBJECT*)psStructToAdd, 0);
}
} }
/* Destroy a structure */ /* Destroy a structure */
@ -496,6 +550,12 @@ void killStruct(STRUCTURE *psBuilding)
ASSERT( psBuilding->player < MAX_PLAYERS, ASSERT( psBuilding->player < MAX_PLAYERS,
"killStruct: invalid player for stucture" ); "killStruct: invalid player for stucture" );
if (psBuilding->pStructureType->pSensor
&& psBuilding->pStructureType->pSensor->location == LOC_TURRET)
{
removeObjectFromFuncList(apsSensorList, (BASE_OBJECT*)psBuilding, 0);
}
for (i = 0; i < STRUCT_MAXWEAPS; i++) for (i = 0; i < STRUCT_MAXWEAPS; i++)
{ {
setStructureTarget(psBuilding, NULL, i); setStructureTarget(psBuilding, NULL, i);
@ -552,7 +612,12 @@ void removeStructureFromList(STRUCTURE *psStructToRemove, STRUCTURE *pList[MAX_P
"removeStructureFromList: pointer is not a structure" ); "removeStructureFromList: pointer is not a structure" );
ASSERT( psStructToRemove->player < MAX_PLAYERS, ASSERT( psStructToRemove->player < MAX_PLAYERS,
"removeStructureFromList: invalid player for structure" ); "removeStructureFromList: invalid player for structure" );
removeObjectFromList((BASE_OBJECT**)pList, (BASE_OBJECT*)psStructToRemove); removeObjectFromList((BASE_OBJECT**)pList, (BASE_OBJECT*)psStructToRemove, psStructToRemove->player);
if (psStructToRemove->pStructureType->pSensor
&& psStructToRemove->pStructureType->pSensor->location == LOC_TURRET)
{
removeObjectFromFuncList(apsSensorList, (BASE_OBJECT*)psStructToRemove, 0);
}
} }
/************************** FEATURE *********************************/ /************************** FEATURE *********************************/
@ -566,7 +631,7 @@ FEATURE* createFeature()
/* add the feature to the Feature Lists */ /* add the feature to the Feature Lists */
void addFeature(FEATURE *psFeatureToAdd) void addFeature(FEATURE *psFeatureToAdd)
{ {
addObjectToList((BASE_OBJECT**)apsFeatureLists, (BASE_OBJECT*)psFeatureToAdd); addObjectToList((BASE_OBJECT**)apsFeatureLists, (BASE_OBJECT*)psFeatureToAdd, 0);
} }
/* Destroy a feature */ /* Destroy a feature */
@ -876,8 +941,8 @@ static void objListIntegCheck(void)
{ {
ASSERT( psCurr->type == OBJ_STRUCTURE && ASSERT( psCurr->type == OBJ_STRUCTURE &&
(SDWORD)psCurr->player == player, (SDWORD)psCurr->player == player,
"objListIntegCheck: misplaced object in the structure list for player %d", "objListIntegCheck: misplaced %s(%p) in the structure list for player %d, is owned by %d",
player ); objInfo(psCurr), psCurr, player, (int)psCurr->player);
} }
} }
for(psCurr = (BASE_OBJECT*)apsFeatureLists[0]; psCurr; psCurr=psCurr->psNext) for(psCurr = (BASE_OBJECT*)apsFeatureLists[0]; psCurr; psCurr=psCurr->psNext)

View File

@ -31,6 +31,7 @@ extern DROID *apsDroidLists[MAX_PLAYERS];
extern STRUCTURE *apsStructLists[MAX_PLAYERS]; extern STRUCTURE *apsStructLists[MAX_PLAYERS];
extern FEATURE *apsFeatureLists[MAX_PLAYERS]; extern FEATURE *apsFeatureLists[MAX_PLAYERS];
extern FLAG_POSITION *apsFlagPosLists[MAX_PLAYERS]; extern FLAG_POSITION *apsFlagPosLists[MAX_PLAYERS];
extern BASE_OBJECT *apsSensorList[1];
/* The list of destroyed objects */ /* The list of destroyed objects */
extern BASE_OBJECT *psDestroyedObj; extern BASE_OBJECT *psDestroyedObj;