Logo Search packages:      
Sourcecode: warzone2100 version File versions

objmem.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
*/
/*
 * ObjMem.c
 *
 * Object memory management functions.
 *
 */
#include <string.h>

#include "lib/framework/frame.h"
#include "lib/sound/audio.h"
#include "objects.h"
#include "lib/gamelib/gtime.h"
#include "hci.h"
#include "map.h"
#include "power.h"
#include "lib/script/script.h"
#include "scriptvals.h"
#include "scripttabs.h"
#include "scriptcb.h"
#include "mission.h"
#include "structuredef.h"
#include "structure.h"
#include "droid.h"
#include "formation.h"
#include "mapgrid.h"

#ifdef DEBUG
static SDWORD factoryDeliveryPointCheck[MAX_PLAYERS][NUM_FLAG_TYPES][MAX_FACTORY];
#endif

// the initial value for the object ID
#define OBJ_ID_INIT           20000

/* The id number for the next object allocated
 * Each object will have a unique id number irrespective of type
 */
UDWORD      objID;


/* The lists of objects allocated */
DROID             *apsDroidLists[MAX_PLAYERS];
STRUCTURE         *apsStructLists[MAX_PLAYERS];
FEATURE                 *apsFeatureLists[MAX_PLAYERS];            // Only player zero is valid for
                                                                              // features
/*The list of Flag Positions allocated */
FLAG_POSITION     *apsFlagPosLists[MAX_PLAYERS];

/* The list of destroyed objects */
BASE_OBJECT       *psDestroyedObj=NULL;

/* Forward function declarations */
#ifdef DEBUG
static void objListIntegCheck(void);
#endif


/* Initialise the object heaps */
BOOL objmemInitialise(void)
{
      // reset the object ID number
      objID = OBJ_ID_INIT;

      return true;
}

/* Release the object heaps */
void objmemShutdown(void)
{
}

/* Remove an object from the destroyed list, finally freeing its memory
 * Hopefully by this time, no pointers still refer to it! */
static void objmemDestroy(BASE_OBJECT *psObj)
{
      switch (psObj->type)
      {
            case OBJ_DROID:
                  debug(LOG_MEMORY, "freeing droid at %p", psObj);
                  if (!droidCheckReferences((DROID *)psObj))
                  {
                        return;
                  }
                  droidRelease((DROID *)psObj);
                  break;

            case OBJ_STRUCTURE:
                  debug(LOG_MEMORY, "freeing structure at %p", psObj);
                  if (!structureCheckReferences((STRUCTURE *)psObj))
                  {
                        return;
                  }
                  structureRelease((STRUCTURE *)psObj);
                  break;

            case OBJ_FEATURE:
                  debug(LOG_MEMORY, "freeing feature at %p", psObj);
                  featureRelease((FEATURE *)psObj);
                  break;

            default:
                  ASSERT(!"unknown object type", "objmemDestroy: unknown object type in destroyed list at 0x%p", psObj);
      }
      // Make sure to get rid of some final references in the sound code to this object first
      audio_RemoveObj(psObj);

      free(psObj);
      debug(LOG_MEMORY, "BASE_OBJECT* 0x%p is freed.", psObj);
}

/* General housekeeping for the object system */
void objmemUpdate(void)
{
      BASE_OBJECT       *psCurr, *psNext, *psPrev;

#ifdef DEBUG
      // do a general validity check first
      objListIntegCheck();
#endif

      // tell the script system about any destroyed objects
      if (psDestroyedObj != NULL)
      {
            scrvUpdateBasePointers();
      }

      /* Go through the destroyed objects list looking for objects that
         were destroyed before this turn */

      /* First remove the objects from the start of the list */
      while (psDestroyedObj != NULL && psDestroyedObj->died != gameTime)
      {
            psNext = psDestroyedObj->psNext;
            objmemDestroy(psDestroyedObj);
            psDestroyedObj = psNext;
      }

      /* Now see if there are any further down the list
      Keep track of the previous object to set its Next pointer*/
      for(psCurr = psPrev = psDestroyedObj; psCurr != NULL; psCurr = psNext)
      {
            psNext = psCurr->psNext;
            if (psCurr->died != gameTime)
            {
                  objmemDestroy(psCurr);

                  /*set the linked list up - you will never be deleting the top
                  of the list, so don't have to check*/
                  psPrev->psNext = psNext;
            }
            else
            {
                  // do the object died callback
                  psCBObjDestroyed = psCurr;
                  eventFireCallbackTrigger((TRIGGER_TYPE)CALL_OBJ_DESTROYED);
                  switch (psCurr->type)
                  {
                  case OBJ_DROID:
                        eventFireCallbackTrigger((TRIGGER_TYPE)CALL_DROID_DESTROYED);
                        break;
                  case OBJ_STRUCTURE:
                        eventFireCallbackTrigger((TRIGGER_TYPE)CALL_STRUCT_DESTROYED);
                        break;
                  case OBJ_FEATURE:
                        eventFireCallbackTrigger((TRIGGER_TYPE)CALL_FEATURE_DESTROYED);
                        break;
                  default:
                        break;
                  }
                  psCBObjDestroyed = NULL;

                  psPrev = psCurr;
            }
      }
}

/**************************************************************************************
 *
 * Inlines for the object memory functions
 * The code is the same for the different object types only the pointer types
 * change.
 */

/* Creating a new object
 */
static inline BASE_OBJECT* createObject(UDWORD player, OBJECT_TYPE objType)
{
      BASE_OBJECT* newObject;

      ASSERT(player < MAX_PLAYERS,
             "createObject: invalid player number");

      switch (objType)
      {
            case OBJ_FEATURE:
                  newObject = malloc(sizeof(FEATURE));
                  break;

            case OBJ_STRUCTURE:
                  newObject = malloc(sizeof(STRUCTURE));
                  break;

            case OBJ_DROID:
                  newObject = malloc(sizeof(DROID));
                  break;

            default:
                  ASSERT(!"unknown object type", "createObject: unknown object type");
                  return NULL;
      }

      if (newObject == NULL)
      {
            debug(LOG_ERROR, "Out of memory");
            return NULL;
      }

      newObject->type = objType;
      newObject->id = (objID << 3) | player;
      objID++;
      newObject->player = (UBYTE)player;
      newObject->died = 0;

      return newObject;
}

/* Add the object to its list
 * \param list is a pointer to the object list
 */
static inline void addObjectToList(BASE_OBJECT *list[], BASE_OBJECT *object)
{
      ASSERT(object != NULL,
             "addObjectToList: Invalid pointer");

      // Prepend the object to the top of the list
      object->psNext = list[object->player];
      list[object->player] = object;
}

/* Move an object from the active list to the destroyed list.
 * \param list is a pointer to the object list
 * \param del is a pointer to the object to remove
 */
static inline void destroyObject(BASE_OBJECT* list[], BASE_OBJECT* object)
{
      BASE_OBJECT *psPrev = NULL, *psCurr;

      ASSERT(object != NULL,
             "destroyObject: Invalid pointer");

      // 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)
      {
            list[object->player] = list[object->player]->psNext;
            ((BASE_OBJECT *)object)->psNext = psDestroyedObj;
            psDestroyedObj = (BASE_OBJECT *)object;
            object->died = gameTime;
            return;
      }

      // 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)
      {
            psPrev = psCurr;
      }

      ASSERT(psCurr != NULL,
             "destroyObject: object not found in list");

      if (psCurr != NULL)
      {
            // Modify the "next" pointer of the previous item to
            // point to the "next" item of the item to delete.
            psPrev->psNext = psCurr->psNext;

            // Prepend the object to the destruction list
            ((BASE_OBJECT *)object)->psNext = psDestroyedObj;
            psDestroyedObj = (BASE_OBJECT *)object;

            // Set destruction time
            object->died = gameTime;
      }
}

/* Remove an object from the active list
 * \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 removeObjectFromList(BASE_OBJECT *list[], BASE_OBJECT *object)
{
      BASE_OBJECT *psPrev = NULL, *psCurr;

      ASSERT( object != NULL,
            "removeObjectFromList: Invalid pointer" );

      // 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)
      {
            list[object->player] = list[object->player]->psNext;
            
            return;
      }
      
      // 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)
      {
            psPrev = psCurr;
      }

      ASSERT( psCurr != NULL,
            "removeObjectFromList: object not found in list" );

      if (psCurr != NULL)
      {
            // Modify the "next" pointer of the previous item to
            // point to the "next" item of the item to delete.
            psPrev->psNext = psCurr->psNext;
      }
}

static inline BASE_OBJECT* findObjectInList(BASE_OBJECT list[], UDWORD idNum)
{
      BASE_OBJECT *psCurr;
      for(psCurr = list; psCurr != NULL; psCurr = psCurr->psNext)
      {
            if (psCurr->id == (idNum))
            {
                  return psCurr;
            }
      }

      return NULL;
}

// Necessary for a nice looking cast in calls to releaseAllObjectsInList
typedef void (*OBJECT_DESTRUCTOR)(BASE_OBJECT*);

static inline void releaseAllObjectsInList(BASE_OBJECT *list[], OBJECT_DESTRUCTOR objectDestructor)
{
      UDWORD i;
      BASE_OBJECT *psCurr, *psNext;

      // Iterate through all players' object lists
      for(i=0; i<MAX_PLAYERS; i++)
      {
            // Iterate through all objects in list
            for(psCurr = list[i]; psCurr != NULL; psCurr = psNext)
            {
                  psNext = psCurr->psNext;

                  // Call a specialized destruction function
                  // (will do all cleanup except for releasing memory of object)
                  objectDestructor(psCurr);

                  // Release object's memory
                  free(psCurr);
            }
            list[i] = NULL;
      }
}

/***************************************************************************************
 *
 * The actual object memory management functions for the different object types
 */

/***************************  DROID  *********************************/

/* Create a new droid */
DROID* createDroid(UDWORD player)
{
      return (DROID*)createObject(player, OBJ_DROID);
}

/* add the droid to the Droid Lists */
 void addDroid(DROID *psDroidToAdd, DROID *pList[MAX_PLAYERS])
 {
       DROID_GROUP      *psGroup;

       addObjectToList((BASE_OBJECT**)pList, (BASE_OBJECT*)psDroidToAdd);
     /*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
     it will cancel itself - HACK?!*/
     if (pList[psDroidToAdd->player] == apsDroidLists[psDroidToAdd->player])
     {
         psDroidToAdd->died = false;

             // commanders have to get their group back
             if (psDroidToAdd->droidType == DROID_COMMAND)
             {
                   grpCreate(&psGroup);
                   if (psGroup)
                   {
                         grpJoin(psGroup, psDroidToAdd);
                   }
             }
     }
 }

 /*destroy a droid */
void killDroid(DROID *psDel)
{
      int i;

      ASSERT( psDel->type == OBJ_DROID,
            "killUnit: pointer is not a unit" );
      ASSERT( psDel->player < MAX_PLAYERS,
            "killUnit: invalid player for unit" );

      setDroidTarget(psDel, NULL);
      for (i = 0; i < DROID_MAXWEAPS; i++)
      {
            setDroidActionTarget(psDel, NULL, i);
      }
      setDroidBase(psDel, NULL);

      destroyObject((BASE_OBJECT**)apsDroidLists, (BASE_OBJECT*)psDel);
}

/* Remove all droids */
void freeAllDroids(void)
{
      releaseAllObjectsInList((BASE_OBJECT**)apsDroidLists, (OBJECT_DESTRUCTOR)droidRelease);
}

/*Remove a single Droid from a list*/
void removeDroid(DROID *psDroidToRemove, DROID *pList[MAX_PLAYERS])
{
      ASSERT( psDroidToRemove->type == OBJ_DROID,
            "removeUnit: pointer is not a unit" );
      ASSERT( psDroidToRemove->player < MAX_PLAYERS,
            "removeUnit: invalid player for unit" );
      removeObjectFromList((BASE_OBJECT**)pList, (BASE_OBJECT*)psDroidToRemove);

      /* Whenever a droid is removed from the current list its died
       * 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. */
      if (pList[psDroidToRemove->player] == apsDroidLists[psDroidToRemove->player])
      {
            psDroidToRemove->died = NOT_CURRENT_LIST;
      }
}

/*Removes all droids that may be stored in the mission lists*/
void freeAllMissionDroids(void)
{
      releaseAllObjectsInList((BASE_OBJECT**)mission.apsDroidLists, (OBJECT_DESTRUCTOR)droidRelease);
}

/*Removes all droids that may be stored in the limbo lists*/
void freeAllLimboDroids(void)
{
      releaseAllObjectsInList((BASE_OBJECT**)apsLimboDroids, (OBJECT_DESTRUCTOR)droidRelease);
}

/**************************  STRUCTURE  *******************************/

/* Create a new structure */
STRUCTURE* createStruct(UDWORD player)
{
      return (STRUCTURE*)createObject(player, OBJ_STRUCTURE);
}

/* add the structure to the Structure Lists */
void addStructure(STRUCTURE *psStructToAdd)
{
    addObjectToList((BASE_OBJECT**)apsStructLists, (BASE_OBJECT*)psStructToAdd);
}

/* Destroy a structure */
void killStruct(STRUCTURE *psBuilding)
{
      int i;

      ASSERT( psBuilding->type == OBJ_STRUCTURE,
            "killStruct: pointer is not a droid" );
      ASSERT( psBuilding->player < MAX_PLAYERS,
            "killStruct: invalid player for stucture" );

      for (i = 0; i < STRUCT_MAXWEAPS; i++)
      {
            setStructureTarget(psBuilding, NULL, i);
      }

      if (psBuilding->pFunctionality != NULL)
      {
            if (StructIsFactory(psBuilding))
            {
                  FACTORY *psFactory = (FACTORY *)psBuilding->pFunctionality;

                  // remove any commander from the factory
                  if (psFactory->psCommander != NULL)
                  {
                        assignFactoryCommandDroid(psBuilding, NULL);
                  }

                  // remove any assembly points
                  if (psFactory->psAssemblyPoint != NULL)
                  {
                        removeFlagPosition(psFactory->psAssemblyPoint);
                        psFactory->psAssemblyPoint = NULL;
                  }
            }
            else if (psBuilding->pStructureType->type == REF_REPAIR_FACILITY)
            {
                  REPAIR_FACILITY *psRepair = (REPAIR_FACILITY *)psBuilding->pFunctionality;

                  if (psRepair->psDeliveryPoint)
                  {
                        // free up repair fac stuff
                        removeFlagPosition(psRepair->psDeliveryPoint);
                        psRepair->psDeliveryPoint = NULL;
                  }
            }
      }

      // remove the object from the grid
      gridRemoveObject((BASE_OBJECT *)psBuilding);

      destroyObject((BASE_OBJECT**)apsStructLists, (BASE_OBJECT*)psBuilding);
}

/* Remove heapall structures */
void freeAllStructs(void)
{
      releaseAllObjectsInList((BASE_OBJECT**)apsStructLists, (OBJECT_DESTRUCTOR)structureRelease);
}

/*Remove a single Structure from a list*/
void removeStructureFromList(STRUCTURE *psStructToRemove, STRUCTURE *pList[MAX_PLAYERS])
{
      ASSERT( psStructToRemove->type == OBJ_STRUCTURE,
            "removeStructureFromList: pointer is not a structure" );
      ASSERT( psStructToRemove->player < MAX_PLAYERS,
            "removeStructureFromList: invalid player for structure" );
      removeObjectFromList((BASE_OBJECT**)pList, (BASE_OBJECT*)psStructToRemove);
}

/**************************  FEATURE  *********************************/

/* Create a new Feature */
FEATURE* createFeature()
{
      return (FEATURE*)createObject(0, OBJ_FEATURE);
}

/* add the feature to the Feature Lists */
 void addFeature(FEATURE *psFeatureToAdd)
 {
      addObjectToList((BASE_OBJECT**)apsFeatureLists, (BASE_OBJECT*)psFeatureToAdd);
 }

/* Destroy a feature */
// set the player to 0 since features have player = maxplayers+1. This screws up destroyObject
// it's a bit of a hack, but hey, it works
void killFeature(FEATURE *psDel)
{
      ASSERT( psDel->type == OBJ_FEATURE,
            "killFeature: pointer is not a feature" );
      psDel->player = 0;
      destroyObject((BASE_OBJECT**)apsFeatureLists, (BASE_OBJECT*)psDel);
}

/* Remove all features */
void freeAllFeatures(void)
{
      releaseAllObjectsInList((BASE_OBJECT**)apsFeatureLists, (OBJECT_DESTRUCTOR)featureRelease);
}

/**************************  FLAG_POSITION ********************************/

/* Create a new Flag Position */
BOOL createFlagPosition(FLAG_POSITION **ppsNew, UDWORD player)
{
      ASSERT( player<MAX_PLAYERS, "createFlagPosition: invalid player number" );

      *ppsNew = malloc(sizeof(FLAG_POSITION));
      if (*ppsNew == NULL)
      {
            debug(LOG_ERROR, "Out of memory");
            return false;
      }
      (*ppsNew)->type = POS_DELIVERY;
      (*ppsNew)->player = player;
      (*ppsNew)->frameNumber = 0;
      (*ppsNew)->selected = false;
      (*ppsNew)->coords.x = ~0;
      (*ppsNew)->coords.y = ~0;
      (*ppsNew)->coords.z = ~0;
      return true;
}

/* add the Flag Position to the Flag Position Lists */
 void addFlagPosition(FLAG_POSITION *psFlagPosToAdd)
 {
      ASSERT( psFlagPosToAdd != NULL,
            "addFlagPosition: Invalid FlagPosition pointer" );
      ASSERT(psFlagPosToAdd->coords.x != ~0, "flag has invalid position");

      psFlagPosToAdd->psNext = apsFlagPosLists[psFlagPosToAdd->player];
      apsFlagPosLists[psFlagPosToAdd->player] = psFlagPosToAdd;
 }

/* Remove a Flag Position from the Lists */
void removeFlagPosition(FLAG_POSITION *psDel)
{
      FLAG_POSITION           *psPrev=NULL, *psCurr;

      ASSERT( psDel != NULL,
            "removeFlagPosition: Invalid Flag Positionpointer" );

      if (apsFlagPosLists[psDel->player] == psDel)
      {
            apsFlagPosLists[psDel->player] = apsFlagPosLists[psDel->player]->psNext;
            free(psDel);
      }
      else
      {
            for(psCurr = apsFlagPosLists[psDel->player]; (psCurr != psDel) &&
                  (psCurr != NULL); psCurr = psCurr->psNext)
            {
                  psPrev = psCurr;
            }
            if (psCurr != NULL)
            {
                  psPrev->psNext = psCurr->psNext;
                  free(psCurr);
            }
      }
}


// free all flag positions
void freeAllFlagPositions(void)
{
      FLAG_POSITION     *psNext;
      SDWORD                  player;

      for(player=0; player<MAX_PLAYERS; player++)
      {
            while (apsFlagPosLists[player])
            {
                  psNext = apsFlagPosLists[player]->psNext;
                  free(apsFlagPosLists[player]);
                  apsFlagPosLists[player] = psNext;
            }
      }
}


#ifdef DEBUG
// check all flag positions for duplicate delivery points
void checkFactoryFlags(void)
{
      FLAG_POSITION     *psFlag;
      SDWORD                  player, type, factory;

      //clear the check array
      for(player=0; player<MAX_PLAYERS; player++)
      {
            //for(type=0; type<NUM_FACTORY_TYPES; type++)
        for(type=0; type<NUM_FLAG_TYPES; type++)
            {
                  for(factory=0; factory<MAX_FACTORY; factory++)
                  {
                        factoryDeliveryPointCheck[player][type][factory] = 0;
                  }
            }
      }

      //check the flags
      for(player=0; player<MAX_PLAYERS; player++)
      {
            psFlag = apsFlagPosLists[player];
            while (psFlag)
            {
                  if ((psFlag->type == POS_DELIVERY) &&//check this is attached to a unique factory
                        (psFlag->factoryType != REPAIR_FLAG))
                  {
                        type = psFlag->factoryType;
                        factory = psFlag->factoryInc;
                        ASSERT( factoryDeliveryPointCheck[player][type][factory] == 0,"DUPLICATE FACTORY DELIVERY POINT FOUND" );
                        factoryDeliveryPointCheck[player][type][factory] = 1;
                  }
                  psFlag = psFlag->psNext;
            }
      }
}
#endif


/**************************  OBJECT ACCESS FUNCTIONALITY ********************************/

// Find a base object from it's id
BASE_OBJECT *getBaseObjFromId(UDWORD id)
{
      unsigned int i;
      UDWORD                  player;
      BASE_OBJECT       *psObj;
      DROID             *psTrans;

      for(i = 0; i < 7; ++i)
      {
            for(player = 0; player < MAX_PLAYERS; ++player)
            {
                  switch (i)
                  {
                        case 0:
                              psObj=(BASE_OBJECT *)apsDroidLists[player];
                              break;
                        case 1:
                              psObj=(BASE_OBJECT *)apsStructLists[player];
                              break;
                        case 2:
                              if (player == 0)
                              {
                                    psObj=(BASE_OBJECT *)apsFeatureLists[0];
                              }
                              else
                              {
                                    psObj = NULL;
                              }
                              break;
                        case 3:
                              psObj=(BASE_OBJECT *)mission.apsDroidLists[player];
                              break;
                        case 4:
                              psObj=(BASE_OBJECT *)mission.apsStructLists[player];
                              break;
                        case 5:
                              if (player == 0)
                              {
                                    psObj=(BASE_OBJECT *)mission.apsFeatureLists[0];
                              }
                              else
                              {
                                    psObj = NULL;
                              }
                              break;
                        case 6:
                              if (player == 0)
                              {
                                    psObj=(BASE_OBJECT *)apsLimboDroids[0];
                              }
                              else
                              {
                                    psObj = NULL;
                              }
                              break;
                        default:
                              psObj = NULL;
                              break;
                  }

                  while (psObj)
                  {
                        if (psObj->id == id)
                        {
                              return psObj;
                        }
                        // if transporter check any droids in the grp
                        if ((psObj->type == OBJ_DROID) && (((DROID*)psObj)->droidType == DROID_TRANSPORTER))
                        {
                              for(psTrans = ((DROID*)psObj)->psGroup->psList; psTrans != NULL; psTrans = psTrans->psGrpNext)
                              {
                                    if (psTrans->id == id)
                                    {
                                          return (BASE_OBJECT*)psTrans;
                                    }
                              }
                        }
                        psObj = psObj->psNext;
                  }
            }
      }
      ASSERT(!"couldn't find a BASE_OBJ with ID", "getBaseObjFromId() failed for id %d", id);

      return NULL;
}

UDWORD getRepairIdFromFlag(FLAG_POSITION *psFlag)
{
      unsigned int i;
      UDWORD                  player;
      STRUCTURE         *psObj;
      REPAIR_FACILITY   *psRepair;


      player = psFlag->player;

      //probably dont need to check mission list
      for(i = 0; i < 2; ++i)
      {
            switch (i)
            {
                  case 0:
                        psObj=(STRUCTURE *)apsStructLists[player];
                        break;
                  case 1:
                        psObj=(STRUCTURE *)mission.apsStructLists[player];
                        break;
                  default:
                        psObj = NULL;
                        break;
            }

            while (psObj)
            {
                  if (psObj->pFunctionality)
                  {
                        if    (psObj->pStructureType->type == REF_REPAIR_FACILITY)
                        {
                              //check for matching delivery point
                              psRepair = ((REPAIR_FACILITY *)psObj->pFunctionality);
                              if (psRepair->psDeliveryPoint == psFlag)
                              {
                                    return psObj->id;
                              }
                        }
                  }
                  psObj = psObj->psNext;
            }
      }
      ASSERT(!"unable to find repair id for FLAG_POSITION", "getRepairIdFromFlag() failed");

      return UDWORD_MAX;
}


// check a base object exists for an ID
BOOL checkValidId(UDWORD id)
{
      return getBaseObjFromId(id) != NULL;
}


// integrity check the lists
#ifdef DEBUG
static void objListIntegCheck(void)
{
      SDWORD                  player;
      BASE_OBJECT       *psCurr;

      for(player = 0; player <MAX_PLAYERS; player += 1)
      {
            for(psCurr = (BASE_OBJECT*)apsDroidLists[player]; psCurr; psCurr=psCurr->psNext)
            {
                  ASSERT( psCurr->type == OBJ_DROID &&
                              (SDWORD)psCurr->player == player,
                              "objListIntegCheck: misplaced object in the droid list for player %d",
                              player );
            }
      }
      for(player = 0; player <MAX_PLAYERS; player += 1)
      {
            for(psCurr = (BASE_OBJECT*)apsStructLists[player]; psCurr; psCurr=psCurr->psNext)
            {
                  ASSERT( psCurr->type == OBJ_STRUCTURE &&
                              (SDWORD)psCurr->player == player,
                              "objListIntegCheck: misplaced object in the structure list for player %d",
                              player );
            }
      }
      for(psCurr = (BASE_OBJECT*)apsFeatureLists[0]; psCurr; psCurr=psCurr->psNext)
      {
            ASSERT( psCurr->type == OBJ_FEATURE,
                        "objListIntegCheck: misplaced object in the feature list" );
      }
      for (psCurr = (BASE_OBJECT*)psDestroyedObj; psCurr; psCurr = psCurr->psNext)
      {
            ASSERT( psCurr->died > 0, "objListIntegCheck: Object in destroyed list but not dead!" );
      }
}
#endif

void objCount(int *droids, int *structures, int *features)
{
      int         i;
      DROID       *psDroid;
      STRUCTURE   *psStruct;
      FEATURE           *psFeat;

      *droids = 0;
      *structures = 0;
      *features = 0;

      for (i = 0; i < MAX_PLAYERS; i++)
      {
            for (psDroid = apsDroidLists[i]; psDroid; psDroid = psDroid->psNext)
            {
                  (*droids)++;
                  if (psDroid->droidType == DROID_TRANSPORTER)
                  {
                        DROID *psTrans = psDroid->psGroup->psList;

                        for(psTrans = psTrans->psGrpNext; psTrans != NULL; psTrans = psTrans->psGrpNext)
                        {
                              (*droids)++;
                        }
                  }
            }

            for (psStruct = apsStructLists[i]; psStruct; psStruct = psStruct->psNext)
            {
                  (*structures)++;
            }
      }

      for (psFeat = apsFeatureLists[0]; psFeat; psFeat = psFeat->psNext)
      {
            (*features)++;
      }
}

Generated by  Doxygen 1.6.0   Back to index