Fix template loading for the 8 human player case by storing static AI templates in a special
linked list for that purpose alone. These templates are not saved to savegames, and the ID matching works only because load order is identical - the same way it is handled by campaign. This means that MP templates.txt, like the campaign one, must never be reordered. Patch reviewed by Zarel. Closes ticket:1486 git-svn-id: https://warzone2100.svn.sourceforge.net/svnroot/warzone2100/trunk@9606 4a71c877-e1ca-e34f-864e-861f7616d084master
parent
aa2e8fd0f5
commit
0cc7c315db
89
src/droid.c
89
src/droid.c
|
@ -94,6 +94,7 @@ extern DROID_TEMPLATE sDefaultDesignTemplate;
|
|||
|
||||
// Template storage
|
||||
DROID_TEMPLATE *apsDroidTemplates[MAX_PLAYERS];
|
||||
DROID_TEMPLATE *apsStaticTemplates; // for AIs and scripts
|
||||
|
||||
// store the experience of recently recycled droids
|
||||
UWORD aDroidExperience[MAX_PLAYERS][MAX_RECYCLED_DROIDS];
|
||||
|
@ -1834,15 +1835,18 @@ BOOL loadDroidTemplates(const char *pDroidData, UDWORD bufferSize)
|
|||
{
|
||||
int i;
|
||||
|
||||
// Give AI players all templates, and only those meant for humans (player 0)
|
||||
// to human players.
|
||||
// Give those meant for humans (player 0) to all human players.
|
||||
for (i = 0; i < MAX_PLAYERS; i++)
|
||||
{
|
||||
if (!NetPlay.players[i].allocated || player == 0)
|
||||
if (player == 0 && NetPlay.players[i].allocated) // human prototype template
|
||||
{
|
||||
addTemplate(i, pDroidDesign);
|
||||
pDroidDesign->prefab = false;
|
||||
addTemplateToList(pDroidDesign, &apsDroidTemplates[i]);
|
||||
}
|
||||
}
|
||||
// Add all templates to static template list
|
||||
pDroidDesign->prefab = true; // prefabricated templates referenced from VLOs
|
||||
addTemplateToList(pDroidDesign, &apsStaticTemplates);
|
||||
}
|
||||
|
||||
//increment the pointer to the start of the next record
|
||||
|
@ -1871,6 +1875,13 @@ void initTemplatePoints(void)
|
|||
pDroidDesign->powerPoints = calcTemplatePower(pDroidDesign);
|
||||
}
|
||||
}
|
||||
for (pDroidDesign = apsStaticTemplates; pDroidDesign != NULL; pDroidDesign = pDroidDesign->psNext)
|
||||
{
|
||||
//calculate the total build points
|
||||
pDroidDesign->buildPoints = calcTemplateBuild(pDroidDesign);
|
||||
//calc the total power points
|
||||
pDroidDesign->powerPoints = calcTemplatePower(pDroidDesign);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -2040,6 +2051,10 @@ BOOL loadDroidWeapons(const char *pWeaponData, UDWORD bufferSize)
|
|||
pTemplate->aName);
|
||||
pTemplate->storeCount++;
|
||||
}
|
||||
if (!isHumanPlayer(i))
|
||||
{
|
||||
break; // only one list to add to
|
||||
}
|
||||
}
|
||||
|
||||
//increment the pointer to the start of the next record
|
||||
|
@ -2055,24 +2070,33 @@ BOOL loadDroidWeapons(const char *pWeaponData, UDWORD bufferSize)
|
|||
BOOL droidTemplateShutDown(void)
|
||||
{
|
||||
unsigned int player;
|
||||
DROID_TEMPLATE *pTemplate, *pNext;
|
||||
|
||||
for (player = 0; player < MAX_PLAYERS; player++)
|
||||
{
|
||||
DROID_TEMPLATE *pTemplate, *pNext;
|
||||
|
||||
for (pTemplate = apsDroidTemplates[player]; pTemplate != NULL; pTemplate = pNext)
|
||||
{
|
||||
pNext = pTemplate->psNext;
|
||||
//FIX ME:
|
||||
ASSERT(sDefaultDesignTemplate.pName != pTemplate->pName, "We'll soon be getting a double free()!!!");
|
||||
if (pTemplate->pName != sDefaultDesignTemplate.pName)
|
||||
if (pTemplate->pName != sDefaultDesignTemplate.pName) // sanity check probably no longer necessary
|
||||
{
|
||||
free(pTemplate->pName);
|
||||
}
|
||||
ASSERT(!pTemplate->prefab, "Static template %s in player template list!", pTemplate->aName);
|
||||
free(pTemplate);
|
||||
}
|
||||
apsDroidTemplates[player] = NULL;
|
||||
}
|
||||
for (pTemplate = apsStaticTemplates; pTemplate != NULL; pTemplate = pNext)
|
||||
{
|
||||
pNext = pTemplate->psNext;
|
||||
if (pTemplate->pName != sDefaultDesignTemplate.pName) // sanity check probably no longer necessary
|
||||
{
|
||||
free(pTemplate->pName);
|
||||
}
|
||||
ASSERT(pTemplate->prefab, "Player template %s in static template list!", pTemplate->aName);
|
||||
free(pTemplate);
|
||||
}
|
||||
apsStaticTemplates = NULL;
|
||||
free(sDefaultDesignTemplate.pName);
|
||||
sDefaultDesignTemplate.pName = NULL;
|
||||
|
||||
|
@ -3056,8 +3080,14 @@ BOOL calcDroidMuzzleLocation(DROID *psDroid, Vector3f *muzzle, int weapon_slot)
|
|||
DROID_TEMPLATE * getTemplateFromUniqueName(const char *pName, unsigned int player)
|
||||
{
|
||||
DROID_TEMPLATE *psCurr;
|
||||
DROID_TEMPLATE *list = apsStaticTemplates; // assume AI
|
||||
|
||||
for (psCurr = apsDroidTemplates[player]; psCurr != NULL; psCurr = psCurr->psNext)
|
||||
if (isHumanPlayer(player))
|
||||
{
|
||||
list = apsDroidTemplates[player]; // was human
|
||||
}
|
||||
|
||||
for (psCurr = list; psCurr != NULL; psCurr = psCurr->psNext)
|
||||
{
|
||||
if (strcmp(psCurr->pName, pName) == 0)
|
||||
{
|
||||
|
@ -3069,65 +3099,44 @@ DROID_TEMPLATE * getTemplateFromUniqueName(const char *pName, unsigned int playe
|
|||
}
|
||||
|
||||
/*!
|
||||
* Gets a template from its name, irrespective of owner. This is really, really ugly, but
|
||||
* when reading from a VLO file we do not know its future owner. We must never read templates
|
||||
* from a human player, and we must never let AIs delete their templates, or this will break
|
||||
* horribly.
|
||||
* Get a static template from its name. This is used from scripts. These templates must
|
||||
* never be changed or deleted.
|
||||
* \param pName Template name
|
||||
* \pre pName has to be the unique, untranslated name!
|
||||
* \post pName will be translated via getDroidResourceName()!
|
||||
*/
|
||||
DROID_TEMPLATE *getTemplateFromTranslatedNameNoPlayer(char *pName)
|
||||
{
|
||||
int player;
|
||||
const char *rName;
|
||||
|
||||
for (player = 0; player < MAX_PLAYERS; player++)
|
||||
{
|
||||
DROID_TEMPLATE *psCurr;
|
||||
|
||||
for (psCurr = apsDroidTemplates[player]; psCurr != NULL; psCurr = psCurr->psNext)
|
||||
for (psCurr = apsStaticTemplates; psCurr != NULL; psCurr = psCurr->psNext)
|
||||
{
|
||||
rName = psCurr->pName ? psCurr->pName : psCurr->aName;
|
||||
if (!isHumanPlayer(player) && strcmp(rName, pName) == 0)
|
||||
if (strcmp(rName, pName) == 0)
|
||||
{
|
||||
return psCurr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*getTemplatefFromSinglePlayerID gets template for unique ID searching one players list */
|
||||
DROID_TEMPLATE* getTemplateFromSinglePlayerID(UDWORD multiPlayerID, UDWORD player)
|
||||
{
|
||||
DROID_TEMPLATE *pDroidDesign;
|
||||
|
||||
for(pDroidDesign = apsDroidTemplates[player]; pDroidDesign != NULL; pDroidDesign = pDroidDesign->psNext)
|
||||
{
|
||||
if (pDroidDesign->multiPlayerID == multiPlayerID)
|
||||
{
|
||||
return pDroidDesign;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*getTemplatefFromMultiPlayerID gets template for unique ID searching all lists */
|
||||
DROID_TEMPLATE* getTemplateFromMultiPlayerID(UDWORD multiPlayerID)
|
||||
{
|
||||
UDWORD player;
|
||||
DROID_TEMPLATE *pDroidDesign;
|
||||
|
||||
for (player=0; player < MAX_PLAYERS; player++)
|
||||
for (player = 0; player < MAX_PLAYERS; player++)
|
||||
{
|
||||
pDroidDesign = getTemplateFromSinglePlayerID(multiPlayerID, player);
|
||||
if (pDroidDesign != NULL)
|
||||
for(pDroidDesign = apsDroidTemplates[player]; pDroidDesign != NULL; pDroidDesign = pDroidDesign->psNext)
|
||||
{
|
||||
if (pDroidDesign->multiPlayerID == multiPlayerID)
|
||||
{
|
||||
return pDroidDesign;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -55,6 +55,8 @@ back when building is destroyed*/
|
|||
|
||||
//storage
|
||||
extern DROID_TEMPLATE *apsDroidTemplates[MAX_PLAYERS];
|
||||
extern DROID_TEMPLATE *apsStaticTemplates; // for AIs and scripts
|
||||
|
||||
extern bool runningMultiplayer(void);
|
||||
|
||||
//used to stop structures being built too near the edge and droids being placed down - pickATile
|
||||
|
@ -227,8 +229,6 @@ extern BOOL calcDroidMuzzleLocation(DROID *psDroid, Vector3f *muzzle, int weapon
|
|||
extern DROID_TEMPLATE * getTemplateFromUniqueName(const char *pName, unsigned int player);
|
||||
/* gets a template from its name - relies on the name being unique */
|
||||
extern DROID_TEMPLATE* getTemplateFromTranslatedNameNoPlayer(char *pName);
|
||||
/*getTemplateFromSinglePlayerID gets template for unique ID searching one players list */
|
||||
extern DROID_TEMPLATE* getTemplateFromSinglePlayerID(UDWORD multiPlayerID, UDWORD player);
|
||||
/*getTemplateFromMultiPlayerID gets template for unique ID searching all lists */
|
||||
extern DROID_TEMPLATE* getTemplateFromMultiPlayerID(UDWORD multiPlayerID);
|
||||
|
||||
|
|
|
@ -124,6 +124,7 @@ typedef struct _droid_template
|
|||
DROID_TYPE droidType; ///< The type of droid
|
||||
UDWORD multiPlayerID; ///< multiplayer unique descriptor(cant use id's for templates). Used for save games as well now - AB 29/10/98
|
||||
struct _droid_template* psNext; ///< Pointer to next template
|
||||
bool prefab; ///< Not player designed, not saved, never delete or change
|
||||
} WZ_DECL_MAY_ALIAS DROID_TEMPLATE;
|
||||
|
||||
typedef struct DROID
|
||||
|
|
11
src/game.c
11
src/game.c
|
@ -8928,7 +8928,7 @@ BOOL loadSaveTemplateV7(char *pFileData, UDWORD filesize, UDWORD numTemplates)
|
|||
|
||||
// ignore brains and programs for now
|
||||
psTemplate->asParts[COMP_BRAIN] = 0;
|
||||
|
||||
psTemplate->prefab = false; // not AI template
|
||||
|
||||
//calculate the total build points
|
||||
psTemplate->buildPoints = calcTemplateBuild(psTemplate);
|
||||
|
@ -8937,9 +8937,6 @@ BOOL loadSaveTemplateV7(char *pFileData, UDWORD filesize, UDWORD numTemplates)
|
|||
//store it in the apropriate player' list
|
||||
psTemplate->psNext = apsDroidTemplates[psSaveTemplate->player];
|
||||
apsDroidTemplates[psSaveTemplate->player] = psTemplate;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -9058,6 +9055,7 @@ BOOL loadSaveTemplateV14(char *pFileData, UDWORD filesize, UDWORD numTemplates)
|
|||
|
||||
// ignore brains and programs for now
|
||||
psTemplate->asParts[COMP_BRAIN] = 0;
|
||||
psTemplate->prefab = false; // not AI template
|
||||
|
||||
//calculate the total build points
|
||||
psTemplate->buildPoints = calcTemplateBuild(psTemplate);
|
||||
|
@ -9229,6 +9227,7 @@ BOOL loadSaveTemplateV(char *pFileData, UDWORD filesize, UDWORD numTemplates)
|
|||
|
||||
//no! put brains back in 10Feb //ignore brains and programs for now
|
||||
//psTemplate->asParts[COMP_BRAIN] = 0;
|
||||
psTemplate->prefab = false; // not AI template
|
||||
|
||||
//calculate the total build points
|
||||
psTemplate->buildPoints = calcTemplateBuild(psTemplate);
|
||||
|
@ -9259,10 +9258,6 @@ BOOL loadSaveTemplateV(char *pFileData, UDWORD filesize, UDWORD numTemplates)
|
|||
psTemplate->psNext = apsDroidTemplates[psSaveTemplate->player];
|
||||
apsDroidTemplates[psSaveTemplate->player] = psTemplate;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -345,8 +345,8 @@ BOOL multiShutdown(void)
|
|||
}
|
||||
|
||||
// ////////////////////////////////////////////////////////////////////////////
|
||||
// copy tempates from one player to another.
|
||||
BOOL addTemplate(UDWORD player, DROID_TEMPLATE *psNew)
|
||||
// copy templates from one player to another.
|
||||
BOOL addTemplateToList(DROID_TEMPLATE *psNew, DROID_TEMPLATE **ppList)
|
||||
{
|
||||
DROID_TEMPLATE *psTempl = malloc(sizeof(DROID_TEMPLATE));
|
||||
|
||||
|
@ -363,12 +363,19 @@ BOOL addTemplate(UDWORD player, DROID_TEMPLATE *psNew)
|
|||
psTempl->pName = strdup(psNew->pName);
|
||||
}
|
||||
|
||||
psTempl->psNext = apsDroidTemplates[player];
|
||||
apsDroidTemplates[player] = psTempl;
|
||||
psTempl->psNext = *ppList;
|
||||
*ppList = psTempl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ////////////////////////////////////////////////////////////////////////////
|
||||
// copy templates from one player to another.
|
||||
BOOL addTemplate(UDWORD player, DROID_TEMPLATE *psNew)
|
||||
{
|
||||
return addTemplateToList(psNew, &apsDroidTemplates[player]);
|
||||
}
|
||||
|
||||
// ////////////////////////////////////////////////////////////////////////////
|
||||
// setup templates
|
||||
BOOL multiTemplateSetup(void)
|
||||
|
|
|
@ -386,40 +386,29 @@ DROID_TEMPLATE *IdToTemplate(UDWORD tempId,UDWORD player)
|
|||
{
|
||||
DROID_TEMPLATE *psTempl = NULL;
|
||||
UDWORD i;
|
||||
if(player != ANYPLAYER)
|
||||
|
||||
// Check if we know which player this is from, in that case, assume it is a player template
|
||||
if (player != ANYPLAYER)
|
||||
{
|
||||
for (psTempl = apsDroidTemplates[player]; // follow templates
|
||||
(psTempl && (psTempl->multiPlayerID != tempId ));
|
||||
psTempl = psTempl->psNext);
|
||||
}
|
||||
else
|
||||
{
|
||||
// REALLY DANGEROUS!!! ID's are NOT assumed to be unique for TEMPLATES.
|
||||
debug( LOG_NEVER, "Really Dodgy Check performed for a template" );
|
||||
for(i=0;i<MAX_PLAYERS;i++)
|
||||
{
|
||||
for (psTempl = apsDroidTemplates[i]; // follow templates
|
||||
(psTempl && (psTempl->multiPlayerID != tempId ));
|
||||
psTempl = psTempl->psNext);
|
||||
if(psTempl)
|
||||
{
|
||||
return psTempl;
|
||||
}
|
||||
}
|
||||
}
|
||||
return psTempl;
|
||||
}
|
||||
|
||||
// the same as above, but only checks names in similarity.
|
||||
DROID_TEMPLATE *NameToTemplate(const char *sName,UDWORD player)
|
||||
{
|
||||
DROID_TEMPLATE *psTempl = NULL;
|
||||
|
||||
for (psTempl = apsDroidTemplates[player]; // follow templates
|
||||
(psTempl && (strcmp(psTempl->aName,sName) != 0) );
|
||||
psTempl = psTempl->psNext);
|
||||
|
||||
return psTempl;
|
||||
}
|
||||
|
||||
// If not, first try static templates from AI control (could potentially also happen for currently human controlled players)
|
||||
for (psTempl = apsStaticTemplates; psTempl && psTempl->multiPlayerID != tempId; psTempl = psTempl->psNext) ;
|
||||
if (psTempl) return psTempl;
|
||||
|
||||
// We really have no idea, but it is not a static template, so search through every player template
|
||||
for (i = 0; i < MAX_PLAYERS; i++)
|
||||
{
|
||||
for (psTempl = apsDroidTemplates[i]; psTempl && psTempl->multiPlayerID != tempId; psTempl = psTempl->psNext) ;
|
||||
if (psTempl) return psTempl;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -129,7 +129,6 @@ extern WZ_DECL_WARN_UNUSED_RESULT STRUCTURE *IdToStruct(UDWORD id,UDWORD player
|
|||
extern WZ_DECL_WARN_UNUSED_RESULT BOOL IdToDroid(UDWORD id, UDWORD player, DROID **psDroid);
|
||||
extern WZ_DECL_WARN_UNUSED_RESULT FEATURE *IdToFeature(UDWORD id,UDWORD player);
|
||||
extern WZ_DECL_WARN_UNUSED_RESULT DROID_TEMPLATE *IdToTemplate(UDWORD tempId,UDWORD player);
|
||||
extern WZ_DECL_WARN_UNUSED_RESULT DROID_TEMPLATE *NameToTemplate(const char *sName,UDWORD player);
|
||||
|
||||
extern const char* getPlayerName(unsigned int player);
|
||||
extern BOOL setPlayerName (UDWORD player, const char *sName);
|
||||
|
@ -195,6 +194,7 @@ extern void playerResponding (void);
|
|||
extern BOOL multiGameInit (void);
|
||||
extern BOOL multiGameShutdown (void);
|
||||
extern BOOL addTemplate (UDWORD player,DROID_TEMPLATE *psNew);
|
||||
extern BOOL addTemplateToList(DROID_TEMPLATE *psNew, DROID_TEMPLATE **ppList);
|
||||
|
||||
// syncing.
|
||||
extern BOOL sendCheck (void); //send/recv check info
|
||||
|
|
Loading…
Reference in New Issue