From 0cc7c315db4b1b80048e9a45839cdbde5900f698 Mon Sep 17 00:00:00 2001 From: Per Inge Mathisen Date: Mon, 1 Feb 2010 20:06:54 +0000 Subject: [PATCH] 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-861f7616d084 --- src/droid.c | 99 +++++++++++++++++++++++++++---------------------- src/droid.h | 4 +- src/droiddef.h | 1 + src/game.c | 11 ++---- src/multiopt.c | 15 ++++++-- src/multiplay.c | 41 ++++++++------------ src/multiplay.h | 2 +- 7 files changed, 87 insertions(+), 86 deletions(-) diff --git a/src/droid.c b/src/droid.c index ea7becfee..584548cb7 100644 --- a/src/droid.c +++ b/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,63 +3099,42 @@ 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; + DROID_TEMPLATE *psCurr; - for (player = 0; player < MAX_PLAYERS; player++) + for (psCurr = apsStaticTemplates; psCurr != NULL; psCurr = psCurr->psNext) { - DROID_TEMPLATE *psCurr; - - for (psCurr = apsDroidTemplates[player]; psCurr != NULL; psCurr = psCurr->psNext) + rName = psCurr->pName ? psCurr->pName : psCurr->aName; + if (strcmp(rName, pName) == 0) { - rName = psCurr->pName ? psCurr->pName : psCurr->aName; - if (!isHumanPlayer(player) && strcmp(rName, pName) == 0) - { - return psCurr; - } + 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; + 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) { - return pDroidDesign; + if (pDroidDesign->multiPlayerID == multiPlayerID) + { + return pDroidDesign; + } } } return NULL; diff --git a/src/droid.h b/src/droid.h index af2d64fc9..8f685720e 100644 --- a/src/droid.h +++ b/src/droid.h @@ -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); diff --git a/src/droiddef.h b/src/droiddef.h index 3533446a4..e2feba9f1 100644 --- a/src/droiddef.h +++ b/src/droiddef.h @@ -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 diff --git a/src/game.c b/src/game.c index e700cead1..d4db9d9f4 100644 --- a/src/game.c +++ b/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; diff --git a/src/multiopt.c b/src/multiopt.c index 53f294bd3..f8b680c83 100644 --- a/src/multiopt.c +++ b/src/multiopt.c @@ -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) diff --git a/src/multiplay.c b/src/multiplay.c index 2ffee1d48..a50796aaa 100644 --- a/src/multiplay.c +++ b/src/multiplay.c @@ -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); + + return psTempl; } - else + + // 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++) { - // 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;imultiPlayerID != tempId )); - psTempl = psTempl->psNext); - if(psTempl) - { - return psTempl; - } - } + for (psTempl = apsDroidTemplates[i]; 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; + return NULL; } ///////////////////////////////////////////////////////////////////////////////// diff --git a/src/multiplay.h b/src/multiplay.h index 3cffc78c9..0d1ff2158 100644 --- a/src/multiplay.h +++ b/src/multiplay.h @@ -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